Ludovic 'Archivist' Lagouardette 3 роки тому
джерело
коміт
fd2863d63b
2 змінених файлів з 190 додано та 17 видалено
  1. +132
    -15
      include/gp/allocator/buddy.hpp
  2. +58
    -2
      include/gp/math/fp_math.hpp

+ 132
- 15
include/gp/allocator/buddy.hpp Переглянути файл

@ -24,29 +24,46 @@ namespace gp{
*/
template<size_t max_msb = 24, size_t align = 8>
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) k">noexcept {
used = 1 & src;
used_children = 2 & src;
}
operator uint8_t() {
operator uint8_t() k">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() k">noexcept {
a = 0; b = 0; c = 0; d = 0;
}
};
/**
* @brief a meta allocator to allocate the memory used and deallocate it later
*/
gp::optional<gp::reference_wrapper<allocator>> allocator_v;
/**
* @brief The actual buffer where data is stored
*
*/
gp::buffer<char> 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<bundle, span_size> 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<typename function>
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<typename function>
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<typename function>
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 k">noexcept {
k">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())

+ 58
- 2
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<typename T>
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<size_t steps, typename T, size_t accuracy = 1000000>
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<float>;
v = v - 2*pi<float>*floor(v/(2*pi<float>));
v -= pi<float>;
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<double>;
v = v - 2*pi<double>*floor(v/(2*pi<double>));
@ -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<size_t cycles = 5>
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<size_t cycles = 5>
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);}
}

Завантаження…
Відмінити
Зберегти