Compare commits
6 Commits
a35ca0b367
...
b8ae61b7c7
Author | SHA1 | Date | |
---|---|---|---|
b8ae61b7c7 | |||
1449e966ab | |||
24f9dd22ec | |||
b8e70996c3 | |||
6058a69182 | |||
e247310ded |
@ -1,37 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* @file Alignment.h
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief Functions to align addresses and sizes to specified boundaries.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022-2023, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <luna/TypeTraits.h>
|
|
||||||
#include <luna/Types.h>
|
#include <luna/Types.h>
|
||||||
|
|
||||||
template <usize alignment, typename T> constexpr inline T is_aligned(T value)
|
/**
|
||||||
|
* @brief Check whether a value is aligned to a specific alignment.
|
||||||
|
*
|
||||||
|
* @tparam alignment The alignment to use. It must be provided as a template parameter to help the compiler with
|
||||||
|
* optimizations. For best results, use a power of two.
|
||||||
|
* @tparam T The type of the value.
|
||||||
|
* @param value The value to check.
|
||||||
|
* @return constexpr bool Whether the value is aligned.
|
||||||
|
*/
|
||||||
|
template <usize alignment, typename T> constexpr inline bool is_aligned(T value)
|
||||||
{
|
{
|
||||||
return (value % alignment == 0);
|
return (value % alignment == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(is_aligned<512>(1024u));
|
/**
|
||||||
static_assert(!is_aligned<32>(235u));
|
* @brief Find the closest aligned value that is smaller than the value provided.
|
||||||
static_assert(is_aligned<4096>(40960u));
|
*
|
||||||
|
* @tparam alignment The alignment to use. It must be provided as a template parameter to help the compiler with
|
||||||
|
* optimizations. For best results, use a power of two.
|
||||||
|
* @tparam T The type of the value.
|
||||||
|
* @param value The value to use.
|
||||||
|
* @return constexpr T The aligned value.
|
||||||
|
*/
|
||||||
template <usize alignment, typename T> constexpr inline T align_down(T value)
|
template <usize alignment, typename T> constexpr inline T align_down(T value)
|
||||||
{
|
{
|
||||||
return value - value % alignment;
|
return value - value % alignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(align_down<512>(598ul) == 512ul);
|
/**
|
||||||
static_assert(align_down<64>(194ul) == 192ul);
|
* @brief Find the closest aligned value that is bigger than the value provided.
|
||||||
static_assert(align_down<32>(64ul) == 64ul);
|
*
|
||||||
|
* @tparam alignment The alignment to use. It must be provided as a template parameter to help the compiler with
|
||||||
|
* optimizations. For best results, use a power of two.
|
||||||
|
* @tparam T The type of the value.
|
||||||
|
* @param value The value to use.
|
||||||
|
* @return constexpr T The aligned value.
|
||||||
|
*/
|
||||||
template <usize alignment, typename T> constexpr inline T align_up(T value)
|
template <usize alignment, typename T> constexpr inline T align_up(T value)
|
||||||
{
|
{
|
||||||
if (is_aligned<alignment>(value)) return value;
|
if (is_aligned<alignment>(value)) return value;
|
||||||
return align_down<alignment>(value) + alignment;
|
return align_down<alignment>(value) + alignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(align_up<512>(598ul) == 1024ul);
|
/**
|
||||||
static_assert(align_up<64>(194ul) == 256ul);
|
* @brief Offset a pointer by exactly <offset> bytes, no matter the type.
|
||||||
static_assert(align_up<32>(64ul) == 64ul);
|
*
|
||||||
|
* Generally only useful for pointers to void (or char), because breaking other pointers' alignments is not a good
|
||||||
// Offset a pointer by exactly <offset> bytes, no matter the type. Useful to avoid the quirks that come from C pointer
|
* idea...
|
||||||
// arithmetic.
|
*
|
||||||
|
* @tparam T The underlying type of the pointer.
|
||||||
|
* @tparam Offset The type of the offset.
|
||||||
|
* @param ptr The pointer to offset.
|
||||||
|
* @param offset The offset to use (depending on the type, this could be negative).
|
||||||
|
* @return constexpr T* The new pointer.
|
||||||
|
*/
|
||||||
template <typename T, typename Offset> constexpr inline T* offset_ptr(T* ptr, Offset offset)
|
template <typename T, typename Offset> constexpr inline T* offset_ptr(T* ptr, Offset offset)
|
||||||
{
|
{
|
||||||
return (T*)((u8*)ptr + offset);
|
return (T*)((u8*)ptr + offset);
|
||||||
|
@ -1,16 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* @file Alloc.h
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief Fallible version of new.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022-2023, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <luna/Heap.h>
|
#include <luna/Heap.h>
|
||||||
#include <luna/PlacementNew.h>
|
#include <luna/PlacementNew.h>
|
||||||
#include <luna/Result.h>
|
#include <luna/Result.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocate a value on the heap and initialize it.
|
||||||
|
*
|
||||||
|
* When this value is no longer used, you must call delete to destroy it.
|
||||||
|
*
|
||||||
|
* @tparam T The type of the value.
|
||||||
|
* @tparam Args The types of arguments to pass to the value's constructor.
|
||||||
|
* @param args The arguments to pass to the value's constructor.
|
||||||
|
* @return Result<T*> An error, or a pointer to the new value.
|
||||||
|
*/
|
||||||
template <typename T, class... Args> [[nodiscard]] Result<T*> make(Args... args)
|
template <typename T, class... Args> [[nodiscard]] Result<T*> make(Args... args)
|
||||||
{
|
{
|
||||||
T* const result = (T*)TRY(malloc_impl(sizeof(T)));
|
T* const result = (T*)TRY(malloc_impl(sizeof(T)));
|
||||||
new (result) T(args...);
|
new (result) T(args...);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> void destroy(T* item)
|
|
||||||
{
|
|
||||||
delete item;
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* @file Atomic.h
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief Atomic value operations.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022-2023, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief An enum representing the different C++11 memory orders.
|
||||||
|
*/
|
||||||
enum class MemoryOrder
|
enum class MemoryOrder
|
||||||
{
|
{
|
||||||
Relaxed = __ATOMIC_RELAXED,
|
Relaxed = __ATOMIC_RELAXED,
|
||||||
@ -10,48 +22,114 @@ enum class MemoryOrder
|
|||||||
SeqCst = __ATOMIC_SEQ_CST,
|
SeqCst = __ATOMIC_SEQ_CST,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief An atomic wrapper around a simple integer value.
|
||||||
|
*
|
||||||
|
* @tparam T The type of the value.
|
||||||
|
*/
|
||||||
template <typename T> class Atomic
|
template <typename T> class Atomic
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Atomic object.
|
||||||
|
*/
|
||||||
Atomic() : m_value()
|
Atomic() : m_value()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Atomic object.
|
||||||
|
*
|
||||||
|
* @param value The value to use.
|
||||||
|
*/
|
||||||
Atomic(T value) : m_value(value)
|
Atomic(T value) : m_value(value)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Store a new value inside this object.
|
||||||
|
*
|
||||||
|
* @param other The value to store.
|
||||||
|
* @return T The updated value.
|
||||||
|
*/
|
||||||
T operator=(T other)
|
T operator=(T other)
|
||||||
{
|
{
|
||||||
store(other);
|
store(other);
|
||||||
return other;
|
return other;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Perform an atomic load of the stored value.
|
||||||
|
*
|
||||||
|
* @param order The memory order to use (keep it to the default if you don't know what you're doing).
|
||||||
|
* @return T The loaded value.
|
||||||
|
*/
|
||||||
T load(MemoryOrder order = MemoryOrder::SeqCst) const
|
T load(MemoryOrder order = MemoryOrder::SeqCst) const
|
||||||
{
|
{
|
||||||
return __atomic_load_n(&m_value, (int)order);
|
return __atomic_load_n(&m_value, (int)order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the stored value atomically.
|
||||||
|
*
|
||||||
|
* @return T The stored value.
|
||||||
|
*/
|
||||||
operator T() const
|
operator T() const
|
||||||
{
|
{
|
||||||
return load();
|
return load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Store a new value atomically.
|
||||||
|
*
|
||||||
|
* @param value The value to store.
|
||||||
|
* @param order The memory order to use (keep it to the default if you don't know what you're doing).
|
||||||
|
*/
|
||||||
void store(T value, MemoryOrder order = MemoryOrder::SeqCst)
|
void store(T value, MemoryOrder order = MemoryOrder::SeqCst)
|
||||||
{
|
{
|
||||||
return __atomic_store_n(&m_value, value, (int)order);
|
return __atomic_store_n(&m_value, value, (int)order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Store a new value atomically, and return the old value.
|
||||||
|
*
|
||||||
|
* @param value The value to store.
|
||||||
|
* @param order The memory order to use (keep it to the default if you don't know what you're doing).
|
||||||
|
* @return T The old value.
|
||||||
|
*/
|
||||||
T exchange(T value, MemoryOrder order = MemoryOrder::SeqCst)
|
T exchange(T value, MemoryOrder order = MemoryOrder::SeqCst)
|
||||||
{
|
{
|
||||||
return __atomic_exchange_n(&m_value, value, (int)order);
|
return __atomic_exchange_n(&m_value, value, (int)order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compare the current value against an expected value and exchange it with a desired value only if they
|
||||||
|
* match, all in a single atomic step.
|
||||||
|
*
|
||||||
|
* @param expected The expected value. After compare_exchange_strong returns, it will be set to the value that used
|
||||||
|
* to be held.
|
||||||
|
* @param desired The value to store if the two values match.
|
||||||
|
* @param success The memory order to use in case of success.
|
||||||
|
* @param failure The memory order to use in case of failure.
|
||||||
|
* @return true The values match and the current value was updated to match desired.
|
||||||
|
* @return false The values did not match and the current value stays the same.
|
||||||
|
*/
|
||||||
bool compare_exchange_strong(T& expected, T desired, MemoryOrder success, MemoryOrder failure)
|
bool compare_exchange_strong(T& expected, T desired, MemoryOrder success, MemoryOrder failure)
|
||||||
{
|
{
|
||||||
return __atomic_compare_exchange_n(&m_value, &expected, desired, false, (int)success, (int)failure);
|
return __atomic_compare_exchange_n(&m_value, &expected, desired, false, (int)success, (int)failure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compare the current value against an expected value and exchange it with a desired value only if they
|
||||||
|
* match, all in a single atomic step.
|
||||||
|
*
|
||||||
|
* @param expected The expected value. After compare_exchange_strong returns, it will be set to the value that used
|
||||||
|
* to be held.
|
||||||
|
* @param desired The value to store if the two values match.
|
||||||
|
* @param order The memory order to use (keep it to the default if you don't know what you're doing).
|
||||||
|
* @return true The values match and the current value was updated to match desired.
|
||||||
|
* @return false The values did not match and the current value stays the same.
|
||||||
|
*/
|
||||||
bool compare_exchange_strong(T& expected, T desired, MemoryOrder order = MemoryOrder::SeqCst)
|
bool compare_exchange_strong(T& expected, T desired, MemoryOrder order = MemoryOrder::SeqCst)
|
||||||
{
|
{
|
||||||
MemoryOrder failure = (order == MemoryOrder::AcqRel) ? MemoryOrder::Acquire
|
MemoryOrder failure = (order == MemoryOrder::AcqRel) ? MemoryOrder::Acquire
|
||||||
@ -60,11 +138,40 @@ template <typename T> class Atomic
|
|||||||
return __atomic_compare_exchange_n(&m_value, &expected, desired, false, (int)order, (int)failure);
|
return __atomic_compare_exchange_n(&m_value, &expected, desired, false, (int)order, (int)failure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compare the current value against an expected value and exchange it with a desired value only if they
|
||||||
|
* match, all in a single atomic step.
|
||||||
|
*
|
||||||
|
* This variant may be more performant than compare_exchange_strong, but is allowed to sometimes spuriously fail
|
||||||
|
* (fail even if the two values did match).
|
||||||
|
*
|
||||||
|
* @param expected The expected value. After compare_exchange_weak returns, it will be set to the value that used
|
||||||
|
* to be held.
|
||||||
|
* @param desired The value to store if the two values match.
|
||||||
|
* @param success The memory order to use in case of success.
|
||||||
|
* @param failure The memory order to use in case of failure.
|
||||||
|
* @return true The values match and the current value was updated to match desired.
|
||||||
|
* @return false The values did not match (or there was a spurious failure) and the current value stays the same.
|
||||||
|
*/
|
||||||
bool compare_exchange_weak(T& expected, T desired, MemoryOrder success, MemoryOrder failure)
|
bool compare_exchange_weak(T& expected, T desired, MemoryOrder success, MemoryOrder failure)
|
||||||
{
|
{
|
||||||
return __atomic_compare_exchange_n(&m_value, &expected, desired, true, (int)success, (int)failure);
|
return __atomic_compare_exchange_n(&m_value, &expected, desired, true, (int)success, (int)failure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compare the current value against an expected value and exchange it with a desired value only if they
|
||||||
|
* match, all in a single atomic step.
|
||||||
|
*
|
||||||
|
* This variant may be more performant than compare_exchange_strong, but is allowed to sometimes spuriously fail
|
||||||
|
* (fail even if the two values did match).
|
||||||
|
*
|
||||||
|
* @param expected The expected value. After compare_exchange_weak returns, it will be set to the value that used
|
||||||
|
* to be held.
|
||||||
|
* @param desired The value to store if the two values match.
|
||||||
|
* @param order The memory order to use (keep it to the default if you don't know what you're doing).
|
||||||
|
* @return true The values match and the current value was updated to match desired.
|
||||||
|
* @return false The values did not match (or there was a spurious failure) and the current value stays the same.
|
||||||
|
*/
|
||||||
bool compare_exchange_weak(T& expected, T desired, MemoryOrder order = MemoryOrder::SeqCst)
|
bool compare_exchange_weak(T& expected, T desired, MemoryOrder order = MemoryOrder::SeqCst)
|
||||||
{
|
{
|
||||||
MemoryOrder failure = (order == MemoryOrder::AcqRel) ? MemoryOrder::Acquire
|
MemoryOrder failure = (order == MemoryOrder::AcqRel) ? MemoryOrder::Acquire
|
||||||
@ -73,41 +180,87 @@ template <typename T> class Atomic
|
|||||||
return __atomic_compare_exchange_n(&m_value, &expected, desired, true, (int)order, (int)failure);
|
return __atomic_compare_exchange_n(&m_value, &expected, desired, true, (int)order, (int)failure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Atomically add a value to the stored value and return the previous value.
|
||||||
|
*
|
||||||
|
* @param other The value to add.
|
||||||
|
* @param order The memory order to use (keep it to the default if you don't know what you're doing).
|
||||||
|
* @return T The original stored value.
|
||||||
|
*/
|
||||||
T fetch_add(T other, MemoryOrder order = MemoryOrder::SeqCst)
|
T fetch_add(T other, MemoryOrder order = MemoryOrder::SeqCst)
|
||||||
{
|
{
|
||||||
return __atomic_fetch_add(&m_value, other, (int)order);
|
return __atomic_fetch_add(&m_value, other, (int)order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Atomically subtract a value from the stored value and return the previous value.
|
||||||
|
*
|
||||||
|
* @param other The value to add.
|
||||||
|
* @param order The memory order to use (keep it to the default if you don't know what you're doing).
|
||||||
|
* @return T The original stored value.
|
||||||
|
*/
|
||||||
T fetch_sub(T other, MemoryOrder order = MemoryOrder::SeqCst)
|
T fetch_sub(T other, MemoryOrder order = MemoryOrder::SeqCst)
|
||||||
{
|
{
|
||||||
return __atomic_fetch_sub(&m_value, other, (int)order);
|
return __atomic_fetch_sub(&m_value, other, (int)order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Increment the stored value and return it.
|
||||||
|
*
|
||||||
|
* @return T The new value.
|
||||||
|
*/
|
||||||
T operator++()
|
T operator++()
|
||||||
{
|
{
|
||||||
return fetch_add(1) + 1;
|
return fetch_add(1) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fetch the stored value, increment it and return the original value.
|
||||||
|
*
|
||||||
|
* @return T The original value.
|
||||||
|
*/
|
||||||
T operator++(int)
|
T operator++(int)
|
||||||
{
|
{
|
||||||
return fetch_add(1);
|
return fetch_add(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decrement the stored value and return it.
|
||||||
|
*
|
||||||
|
* @return T The new value.
|
||||||
|
*/
|
||||||
T operator--()
|
T operator--()
|
||||||
{
|
{
|
||||||
return fetch_sub(1) - 1;
|
return fetch_sub(1) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fetch the stored value, decrement it and return the original value.
|
||||||
|
*
|
||||||
|
* @return T The original value.
|
||||||
|
*/
|
||||||
T operator--(int)
|
T operator--(int)
|
||||||
{
|
{
|
||||||
return fetch_sub(1);
|
return fetch_sub(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add a value to the stored value and return the result.
|
||||||
|
*
|
||||||
|
* @param other The value to add.
|
||||||
|
* @return T The resulting value.
|
||||||
|
*/
|
||||||
T operator+=(const T& other)
|
T operator+=(const T& other)
|
||||||
{
|
{
|
||||||
return fetch_add(other) + other;
|
return fetch_add(other) + other;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Subtract a value from the stored value and return the result.
|
||||||
|
*
|
||||||
|
* @param other The value to subtract.
|
||||||
|
* @return T The resulting value.
|
||||||
|
*/
|
||||||
T operator-=(const T& other)
|
T operator-=(const T& other)
|
||||||
{
|
{
|
||||||
return fetch_sub(other) - other;
|
return fetch_sub(other) - other;
|
||||||
|
@ -1,3 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* @file Attributes.h
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief Macro wrappers around GCC attributes.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022-2023, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define _weak __attribute__((weak))
|
#define _weak __attribute__((weak))
|
||||||
|
@ -1,8 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* @file Badge.h
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief A simple way to control who can call functions.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022-2023, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A struct that can only be constructed by one type, used to control access to functions/methods.
|
||||||
|
*
|
||||||
|
* Example: There is a private method FooClass::foo() that you want to be callable by BarClass without making it a
|
||||||
|
* friend.
|
||||||
|
*
|
||||||
|
* So, make FooClass::foo() public and make it take a Badge<BarClass> which will only be constructible by BarClass, thus
|
||||||
|
* limiting the method even though it is public.
|
||||||
|
*
|
||||||
|
* @tparam T The type that can construct this badge.
|
||||||
|
*/
|
||||||
template <class T> struct Badge
|
template <class T> struct Badge
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Badge.
|
||||||
|
*
|
||||||
|
* This can only be done by the type T.
|
||||||
|
*/
|
||||||
constexpr Badge() = default;
|
constexpr Badge() = default;
|
||||||
|
|
||||||
Badge(const Badge<T>&) = delete;
|
Badge(const Badge<T>&) = delete;
|
||||||
|
@ -1,13 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* @file Base64.h
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief Base64 encoding and decoding.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <luna/Buffer.h>
|
#include <luna/Buffer.h>
|
||||||
#include <luna/String.h>
|
#include <luna/String.h>
|
||||||
|
|
||||||
namespace Base64
|
namespace Base64
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @brief Encode a string into Base64.
|
||||||
|
*
|
||||||
|
* @param data The string to encode.
|
||||||
|
* @return Result<String> An error, or the resulting Base64 string.
|
||||||
|
*/
|
||||||
Result<String> encode(StringView data);
|
Result<String> encode(StringView data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Encode a slice of data into Base64.
|
||||||
|
*
|
||||||
|
* @param data The data to encode.
|
||||||
|
* @return Result<String> An error, or the resulting Base64 string.
|
||||||
|
*/
|
||||||
Result<String> encode(Slice<const u8> data);
|
Result<String> encode(Slice<const u8> data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Encode a buffer into Base64.
|
||||||
|
*
|
||||||
|
* @param data The buffer to encode.
|
||||||
|
* @return Result<String> An error, or the resulting Base64 string.
|
||||||
|
*/
|
||||||
Result<String> encode(const Buffer& data);
|
Result<String> encode(const Buffer& data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decode a Base64 string.
|
||||||
|
*
|
||||||
|
* @param data The string to decode.
|
||||||
|
* @param allow_garbage_chars Whether to skip non-Base64 characters instead of returning an error.
|
||||||
|
* @return Result<Buffer> An error, or the raw decoded data.
|
||||||
|
*/
|
||||||
Result<Buffer> decode(StringView data, bool allow_garbage_chars = false);
|
Result<Buffer> decode(StringView data, bool allow_garbage_chars = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decode a Base64 string, returning a string instead of raw data.
|
||||||
|
*
|
||||||
|
* Note that decoded Base64 may be anything; invalid UTF-8, null characters in the middle of data, etc...
|
||||||
|
* For this reason it is not recommended to use this function unless you're sure that what is decoded will be a
|
||||||
|
* valid string (so, don't use this with untrusted user input).
|
||||||
|
*
|
||||||
|
* @param data The string to decode.
|
||||||
|
* @param allow_garbage_chars Whether to skip non-Base64 characters instead of returning an error.
|
||||||
|
* @return Result<String> An error, or the decoded string.
|
||||||
|
*/
|
||||||
Result<String> decode_string(StringView data, bool allow_garbage_chars = false);
|
Result<String> decode_string(StringView data, bool allow_garbage_chars = false);
|
||||||
}
|
}
|
||||||
|
@ -1,58 +1,195 @@
|
|||||||
|
/**
|
||||||
|
* @file Bitmap.h
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief An interface to an array of bits.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022-2023, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <luna/Result.h>
|
#include <luna/Result.h>
|
||||||
#include <luna/Types.h>
|
#include <luna/Types.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A class providing an interface to an array of bits.
|
||||||
|
*/
|
||||||
class Bitmap
|
class Bitmap
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new empty Bitmap object.
|
||||||
|
*
|
||||||
|
* This object is invalid until initialize() is called on it.
|
||||||
|
*/
|
||||||
Bitmap();
|
Bitmap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Bitmap object.
|
||||||
|
*
|
||||||
|
* @param location The memory to use. This memory is not managed by Bitmap; if it is dynamically allocated, you must
|
||||||
|
* free it after it is no longer used by the bitmap.
|
||||||
|
* @param size_in_bytes The size (in bytes, the number of bits available will be 8 times more) of the memory used.
|
||||||
|
*/
|
||||||
Bitmap(void* location, usize size_in_bytes);
|
Bitmap(void* location, usize size_in_bytes);
|
||||||
|
|
||||||
// Naive initialization functions.
|
/**
|
||||||
|
* @brief Initialize a Bitmap object.
|
||||||
|
*
|
||||||
|
* If the object was previously initialized, you should call move() instead.
|
||||||
|
*
|
||||||
|
* @param location The memory to use. This memory is not managed by Bitmap; if it is dynamically allocated, you must
|
||||||
|
* free it after it is no longer used by the bitmap.
|
||||||
|
* @param size_in_bytes The size (in bytes, the number of bits available will be 8 times more) of the memory used.
|
||||||
|
*/
|
||||||
void initialize(void* location, usize size_in_bytes);
|
void initialize(void* location, usize size_in_bytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize a previously initialized Bitmap object and return the memory location it was previously using.
|
||||||
|
*
|
||||||
|
* If the object was not previously initialized, you should call initialize() instead.
|
||||||
|
*
|
||||||
|
* @param new_location The memory to use. This memory is not managed by Bitmap; if it is dynamically allocated, you
|
||||||
|
* must free it after it is no longer used by the bitmap.
|
||||||
|
* @param new_location_size_in_bytes The size (in bytes, the number of bits available will be 8 times more) of the
|
||||||
|
* memory used.
|
||||||
|
* @return void* The old memory location previously used by the bitmap.
|
||||||
|
*/
|
||||||
void* move(void* new_location, usize new_location_size_in_bytes);
|
void* move(void* new_location, usize new_location_size_in_bytes);
|
||||||
|
|
||||||
// Dynamic memory initialization functions.
|
/**
|
||||||
Result<void> allocate(usize size_in_bytes);
|
* @brief Change the value of the bit at a specific index.
|
||||||
Result<void*> resize(usize new_size_in_bytes);
|
*
|
||||||
Result<void> deallocate();
|
* @param index The index of the bit to change.
|
||||||
|
* @param value The value to set.
|
||||||
|
*/
|
||||||
void set(usize index, bool value);
|
void set(usize index, bool value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read the value of the bit at a specific index.
|
||||||
|
*
|
||||||
|
* @param index The index of the bit to read.
|
||||||
|
* @return bool The value of the specified bit.
|
||||||
|
*/
|
||||||
bool get(usize index) const;
|
bool get(usize index) const;
|
||||||
|
|
||||||
// size() returns size in bits! If you want the size in bytes, call size_in_bytes().
|
/**
|
||||||
|
* @brief Return the size in bits of the bitmap.
|
||||||
|
*
|
||||||
|
* @return usize The size in bits.
|
||||||
|
*/
|
||||||
usize size() const
|
usize size() const
|
||||||
{
|
{
|
||||||
return m_size_in_bytes * 8;
|
return m_size_in_bytes * 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the size in bytes of the bitmap.
|
||||||
|
*
|
||||||
|
* @return usize The size in bytes.
|
||||||
|
*/
|
||||||
usize size_in_bytes() const
|
usize size_in_bytes() const
|
||||||
{
|
{
|
||||||
return m_size_in_bytes;
|
return m_size_in_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the memory location used by the bitmap.
|
||||||
|
*
|
||||||
|
* @return void* The memory location used. If it is NULL, the bitmap was not initialized.
|
||||||
|
*/
|
||||||
void* location() const
|
void* location() const
|
||||||
{
|
{
|
||||||
return (void*)m_location;
|
return (void*)m_location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check whether the bitmap has been initialized.
|
||||||
|
*
|
||||||
|
* @return true The bitmap was initialized by a constructor or initialize().
|
||||||
|
* @return false The bitmap was not initialized and you should not call other methods on it until initialize() is
|
||||||
|
* called.
|
||||||
|
*/
|
||||||
bool initialized() const
|
bool initialized() const
|
||||||
{
|
{
|
||||||
return m_location;
|
return m_location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Find the first bit with a specific value.
|
||||||
|
*
|
||||||
|
* @param value The value to look for.
|
||||||
|
* @param begin If different from 0, the bit index to start looking at.
|
||||||
|
* @return Option<usize> If a matching bit was found, the index of said bit, otherwise an empty Option.
|
||||||
|
*/
|
||||||
Option<usize> find(bool value, usize begin = 0) const;
|
Option<usize> find(bool value, usize begin = 0) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Find the first bit with a specific value and toggle it.
|
||||||
|
*
|
||||||
|
* @param value The value to look for.
|
||||||
|
* @param begin If different from 0, the bit index to start looking at.
|
||||||
|
* @return Option<usize> If a matching bit was found, the index of said bit, otherwise an empty Option.
|
||||||
|
*/
|
||||||
Option<usize> find_and_toggle(bool value, usize begin = 0);
|
Option<usize> find_and_toggle(bool value, usize begin = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Find the first region of bits all with a specific value.
|
||||||
|
*
|
||||||
|
* @param value The value to look for.
|
||||||
|
* @param count The number of consecutive bits that should all match the value.
|
||||||
|
* @param begin If different from 0, the bit index to start looking at.
|
||||||
|
* @return Option<usize> If a matching region was found, the index of the first bit in said region, otherwise an
|
||||||
|
* empty Option.
|
||||||
|
*/
|
||||||
Option<usize> find_region(bool value, usize count, usize begin = 0) const;
|
Option<usize> find_region(bool value, usize count, usize begin = 0) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Find the first region of bits all with a specific value, and toggle them all.
|
||||||
|
*
|
||||||
|
* @param value The value to look for.
|
||||||
|
* @param count The number of consecutive bits that should all match the value.
|
||||||
|
* @param begin If different from 0, the bit index to start looking at.
|
||||||
|
* @return Option<usize> If a matching region was found, the index of the first bit in said region, otherwise an
|
||||||
|
* empty Option.
|
||||||
|
*/
|
||||||
Option<usize> find_and_toggle_region(bool value, usize count, usize begin = 0);
|
Option<usize> find_and_toggle_region(bool value, usize count, usize begin = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check whether a region of bits all match a value.
|
||||||
|
*
|
||||||
|
* @param start The bit index of the first bit in the region.
|
||||||
|
* @param bits The number of bits in the region.
|
||||||
|
* @param value The value to check against.
|
||||||
|
* @return bool Whether the region matches.
|
||||||
|
*/
|
||||||
bool match_region(usize start, usize bits, bool value);
|
bool match_region(usize start, usize bits, bool value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check whether a region of bits all match a value, returning an error if the region is outside of the
|
||||||
|
* Bitmap's bounds (instead of crashing).
|
||||||
|
*
|
||||||
|
* @param start The bit index of the first bit in the region.
|
||||||
|
* @param bits The number of bits in the region.
|
||||||
|
* @param value The value to check against.
|
||||||
|
* @return Result<bool> An error if the region is out of bounds, or whether the region matches.
|
||||||
|
*/
|
||||||
Result<bool> try_match_region(usize start, usize bits, bool value);
|
Result<bool> try_match_region(usize start, usize bits, bool value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the entire bitmap to a value.
|
||||||
|
*
|
||||||
|
* @param value The value to use.
|
||||||
|
*/
|
||||||
void clear(bool value);
|
void clear(bool value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set a region of bits to a value.
|
||||||
|
*
|
||||||
|
* @param start The bit index of the first bit in the region.
|
||||||
|
* @param bits The number of bits in the region.
|
||||||
|
* @param value The value to set.
|
||||||
|
*/
|
||||||
void clear_region(usize start, usize bits, bool value);
|
void clear_region(usize start, usize bits, bool value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1,3 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* @file Base64.cpp
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief Base64 encoding and decoding.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#include <luna/Base64.h>
|
#include <luna/Base64.h>
|
||||||
#include <luna/CType.h>
|
#include <luna/CType.h>
|
||||||
#include <luna/DebugLog.h>
|
#include <luna/DebugLog.h>
|
||||||
@ -152,6 +161,6 @@ namespace Base64
|
|||||||
u8 nul_byte = '\0';
|
u8 nul_byte = '\0';
|
||||||
TRY(buf.append_data(&nul_byte, 1));
|
TRY(buf.append_data(&nul_byte, 1));
|
||||||
|
|
||||||
return String { (char*)buf.release_data() };
|
return String { (char*)buf.release_data(), buf.size() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* @file Bitmap.cpp
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief An interface to an array of bits.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022-2023, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#include <luna/Bitmap.h>
|
#include <luna/Bitmap.h>
|
||||||
#include <luna/CString.h>
|
#include <luna/CString.h>
|
||||||
#include <luna/Check.h>
|
#include <luna/Check.h>
|
||||||
@ -17,24 +26,6 @@ void Bitmap::initialize(void* location, usize size_in_bytes)
|
|||||||
m_size_in_bytes = size_in_bytes;
|
m_size_in_bytes = size_in_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> Bitmap::allocate(usize size_in_bytes)
|
|
||||||
{
|
|
||||||
initialize(TRY(malloc_impl(size_in_bytes)), size_in_bytes);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void*> Bitmap::resize(usize new_size_in_bytes)
|
|
||||||
{
|
|
||||||
m_location = (u8*)TRY(realloc_impl(m_location, new_size_in_bytes));
|
|
||||||
m_size_in_bytes = new_size_in_bytes;
|
|
||||||
return (void*)m_location;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> Bitmap::deallocate()
|
|
||||||
{
|
|
||||||
return free_impl(m_location);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* Bitmap::move(void* new_location, usize new_location_size_in_bytes)
|
void* Bitmap::move(void* new_location, usize new_location_size_in_bytes)
|
||||||
{
|
{
|
||||||
if (new_location_size_in_bytes > m_size_in_bytes) memcpy(new_location, m_location, m_size_in_bytes);
|
if (new_location_size_in_bytes > m_size_in_bytes) memcpy(new_location, m_location, m_size_in_bytes);
|
||||||
|
Loading…
Reference in New Issue
Block a user