diff --git a/include/gp/allocator/buddy.hpp b/include/gp/allocator/buddy.hpp index 8718a35..f6f3a9f 100644 --- a/include/gp/allocator/buddy.hpp +++ b/include/gp/allocator/buddy.hpp @@ -24,29 +24,46 @@ namespace gp{ */ template class buddy : public allocator { + + /** + * @brief an allocation tree node, made into an easily packable struct + */ struct twig { bool used : 1; bool used_children : 1; - twig(uint8_t src) { + twig(uint8_t src) noexcept { used = 1 & src; used_children = 2 & src; } - operator uint8_t() { + operator uint8_t() noexcept { return 1 * used + 2 * used_children; } }; + + /** + * @brief a structure to pack 4 twig within + */ struct bundle { uint8_t a : 2; uint8_t b : 2; uint8_t c : 2; uint8_t d : 2; - bundle() { + bundle() noexcept { a = 0; b = 0; c = 0; d = 0; } }; + + /** + * @brief a meta allocator to allocate the memory used and deallocate it later + */ gp::optional> allocator_v; + + /** + * @brief The actual buffer where data is stored + * + */ gp::buffer data; const size_t max_depth; const size_t twig_explore_length; @@ -67,7 +84,7 @@ namespace gp{ static constexpr size_t span_size = required_twigs / 4 + (required_twigs % 4 != 0); /** - * @brief The array of twigs (in bundles) + * @brief The array of twigs (in bundles) aka the metadata */ gp::array stack; @@ -79,7 +96,13 @@ namespace gp{ #pragma clang diagnostic ignored "-Wreturn-type" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wreturn-type" - twig get_twig(size_t idx) const { + /** + * @brief Get the value of the twig at the specified index + * + * @param idx + * @return twig A copy of the specified twig + */ + twig get_twig(size_t idx) const noexcept { auto far = idx / 4; auto local = idx % 4; switch(local) { @@ -96,7 +119,13 @@ namespace gp{ #pragma GCC diagnostic pop #pragma clang diagnostic pop - void set_twig(size_t idx, twig v) { + /** + * @brief Set the twig at the specified index to the value of the heredescribed twig + * + * @param idx + * @param v + */ + void set_twig(size_t idx, twig v) noexcept { auto far = idx / 4; auto local = idx % 4; auto& group = stack[far]; @@ -117,7 +146,13 @@ namespace gp{ } } - constexpr size_t size_to_depth(size_t sz) { + /** + * @brief Deduces the depth to explore to allocate the specified size + * + * @param sz + * @return size_t + */ + constexpr size_t size_to_depth(size_t sz) noexcept { size_t pow2 = gp::math::msb(sz) - gp::math::msb(align); return gp::clamp( (size_t)0 , @@ -126,18 +161,42 @@ namespace gp{ ); } - constexpr size_t depth_to_size(size_t depth) { + /** + * @brief Deduces the size from the specified depth + * + * @param depth + * @return size_t + */ + constexpr size_t depth_to_size(size_t depth) noexcept { return 1 << (max_depth - depth + gp::math::msb(align)); } - constexpr size_t get_left(size_t index) const { + /** + * @brief Get the left child index from the specified index + * + * @param index + * @return size_t + */ + constexpr size_t get_left(size_t index) const noexcept { return ((index + 1) << 1) - 1; } - constexpr size_t get_right(size_t index) const { + /** + * @brief Get the right child index from the specified index + * + * @param index + * @return size_t + */ + constexpr size_t get_right(size_t index) const noexcept{ return ((index + 1) << 1); } + /** + * @brief Recursively applies a function to the children of a given node + * + * @param index the starting node + * @param func the function to apply downwards + */ template void all_under(size_t index, function func) { size_t left = get_left(index); @@ -148,6 +207,13 @@ namespace gp{ func(right); } + + /** + * @brief Recursively applies a function to the chain of parents of the given node + * + * @param index the starting node + * @param func the function to apply upwards + */ template void all_over(size_t index, function func) { if(index != 0) { @@ -158,6 +224,14 @@ namespace gp{ } } + /** + * @brief Recursively checks if any child matches a given predicate + * + * @param index The parent + * @param func The predicate + * @return true if the predicate matched once + * @return false if the predicate never matched + */ template bool is_any_child(size_t index, function func) const { size_t left = get_left(index); @@ -171,8 +245,21 @@ namespace gp{ return false; } + /** + * @brief a constant used to specify that no twig has been found + */ static constexpr size_t no_twig = -1; + /** + * @brief Finds a twig that represent free memory + * + * It's free real estate! + * + * @param depth the depth to allocate + * @param root the root to look from + * @param explored the current depth we sit at + * @return size_t + */ size_t find_free_twig(size_t depth, size_t root = 0, size_t explored = 0) const { auto v = get_twig(root); if(depth == explored) { @@ -202,6 +289,14 @@ namespace gp{ return no_twig; } + /** + * @brief Recursively looks for the highest filled nodewith the given offset + * + * @param offset The offset to look for + * @param root the root to look from + * @param explored the explored depth + * @return size_t + */ size_t find_used_twig(size_t offset, size_t root = 0, size_t explored = 0) { auto v = get_twig(root); if(v.used && offset == 0) @@ -279,6 +374,12 @@ namespace gp{ { } + /** + * @brief Allocates memory + * + * @param sz The size of memory to allocate + * @return void* the allocated memory OR nullptr + */ virtual void* allocate(size_t sz) { auto depth = size_to_depth(sz); @@ -309,10 +410,22 @@ namespace gp{ return pot; } + /** + * @brief Tries to reallocate (UNIMPLEMENTED) + * + * @return false + */ virtual bool try_reallocate(void*, size_t) { return false; } + /** + * @brief Tries to deallocate the given memory + * + * @param ptr the pointer to the memory to deallocate + * @return true if everything went fine + * @return false if deallocation failed + */ virtual bool deallocate(void* ptr) { if(data.contains((char*)ptr)) @@ -330,7 +443,8 @@ namespace gp{ all_over(index, [&](size_t idx){ auto l = get_twig(get_left(idx)); auto r = get_twig(get_right(idx)); - + // And now for the tricky bit: + // Sets the "used_children" bit if any of the collected twigs has a bit set set_twig(idx, 2*(l.used | l.used_children | r.used | r.used_children)); }); @@ -345,13 +459,16 @@ namespace gp{ * @return true if the allocator is completely empty * @return false if anything is still allocated in there */ - bool empty() const { - buddy* addr = (buddy*)this; - auto prepred = not_fn(&buddy::empty_node); - auto pred = bind_front(prepred, addr); + bool empty() const noexcept { + const buddy* addr = (buddy*)this; + const auto prepred = not_fn(&buddy::empty_node); + const auto pred = bind_front(prepred, addr); return empty_node(addr, 0) && !is_any_child(0, pred); } + /** + * @brief Destroy the buddy object, will wrink out the space if it was created with an allocator + */ virtual ~buddy() { if(allocator_v.has_value()) diff --git a/include/gp/math/fp_math.hpp b/include/gp/math/fp_math.hpp index e7116b1..caa40a8 100644 --- a/include/gp/math/fp_math.hpp +++ b/include/gp/math/fp_math.hpp @@ -86,6 +86,14 @@ namespace gp{ } } + /** + * @brief Reads the sign of a value + * + * @tparam T + * @return -1 if the value is negative + * @return 0 if the value is 0 or not a number + * @return 1 if the value is positive + */ template T sign(T); @@ -116,7 +124,15 @@ namespace gp{ } - + /** + * @brief Calculate the sin of a value using Taylor's method + * + * @tparam steps The number of steps to do at the maximum + * @tparam T the type of value and the return type expected + * @tparam accuracy the maximum accuracy to shoot for (early stopping) + * @param value The value to calculate the sin of. Works better for values close to 0. + * @return T the sin of the value (the sign may be off idk I don't remember) + */ template T sin_taylor(T value) { const T acc = T{1}/T{accuracy}; @@ -131,15 +147,30 @@ namespace gp{ return ret; } + /** + * @brief General purpose sin function + * + * @param v + * @return float + */ float sin(float v) { + // limit the range between -pi and +pi v += pi; v = v - 2*pi*floor(v/(2*pi)); v -= pi; float s = sign(v); v *= s; + + // use taylor's method on the value return sin_taylor<10>(v)*s; } + /** + * @brief General purpose sin function + * + * @param v + * @return double + */ double sin(double v) { v += pi; v = v - 2*pi*floor(v/(2*pi)); @@ -171,7 +202,13 @@ namespace gp{ } - + /** + * @brief Quake isqrt (x) -> 1/sqrt(x) + * + * @tparam cycles the number of newton method cycles to apply + * @param v the value to apply the function on + * @return float \f$\frac{1}{\sqrt{v}}\f$ + */ template float isqrt(float v) { int32_t i; @@ -189,6 +226,13 @@ namespace gp{ return y; } + /** + * @brief Quake isqrt (x) -> 1/sqrt(x) but for doubles + * + * @tparam cycles the number of newton method cycles to apply + * @param v the value to apply the function on + * @return double \f$\frac{1}{\sqrt{v}}\f$ + */ template double isqrt(double v) { int64_t i; @@ -206,6 +250,18 @@ namespace gp{ return y; } + /** + * @brief A faster version of the Quake isqrt (actually the same but with defined cycles) + * + * @param v + * @return float + */ float fast_isqrt(float v) {return isqrt<1>(v);} + /** + * @brief A faster version of the Quake isqrt (actually the same but with defined cycles) + * + * @param v + * @return double + */ double fast_isqrt(double v) {return isqrt<1>(v);} }