| @ -1,3 +1,69 @@ | |||
| # gplib | |||
| General Purpose library for POSIX systems | |||
| General Purpose library for Freestanding C++ environment and POSIX systems. | |||
| > Expects C++17 | |||
| ## Datastructures | |||
| ### `buffer` | |||
| Also named "slices" in other languages, they are a combination of a pointer and a size. | |||
| ### `array` | |||
| A fixed size, inplace array. | |||
| ### `indexed_array` | |||
| A resizable, fragmentation resistant array, it associates elements with fixed indices. It will reuse deleted indices. | |||
| ### `optional` | |||
| A Maybe monad, will not allocate for final classes or primitives. | |||
| ### `variant` and `fixed_variant` | |||
| ### `ring_list` | |||
| ### `bloomfilter` | |||
| ### `quotient_filter` | |||
| ## Algorithms | |||
| ## Tools | |||
| ### Allocators | |||
| ### Renderer | |||
| ### Internal file-system | |||
| ## GP Configuration | |||
| ### `enum class gp_errorcodes` | |||
| This `enum` should not contain any non-zero value. | |||
| - `infinite_skipstone`: used when a linear probing reaches infinity lookup | |||
| ### Generic elements | |||
| - `constexpr bool gp_config::has_exceptions`: enables or disables exceptions throwing | |||
| - `constexpr bool gp_config::has_buffer_bounds`: enables or disables bound checking | |||
| - `constexpr size_t gp_config::arc4random_strength`: determines the amount of shuffling of the arc4random PRNG | |||
| - `constexpr /* T */ gp_config::assertion`: `T` is a callable type taking a boolean predicate and a `const char*` | |||
| - `typedef /* T */ file_descriptor_t`: `T` is an integer type. No negative value should be expected | |||
| ### Rendering and mathematics | |||
| - `using gp_config::rendering::default_type`: provide a numeric type for rendering and for the mathematical framework | |||
| - `constexpr default_type gp_config::rendering::epsilon`: a small value of the default type (example for float: `0.001f`) | |||
| - `#define GP_CONFIG__RENDERING__COLOR_T`: a configuration define for storing a color for rendering purposes | |||
| ### Memory | |||
| - `using gp_config::memory_module::default_allocator`: a default constructible allocator type | |||
| - `constexpr bool gp_config::memory_module::is_ok`: true if the default allocator is able to allocate, false if not | |||
| @ -0,0 +1,26 @@ | |||
| #pragma once | |||
| #include "gp/algorithm/move.hpp" | |||
| namespace gp { | |||
| template<typename iterator> | |||
| iterator rotate(iterator first, iterator new_first, iterator last) | |||
| { | |||
| if(first == new_first) return last; | |||
| if(new_first == last) return first; | |||
| iterator in = new_first; | |||
| iterator out = first; | |||
| iterator mv = first; | |||
| while(in != last) { | |||
| if(out == mv) mv = in; | |||
| gp::swap((*out++), (*in++)); | |||
| } | |||
| // rotate the remaining sequence into place | |||
| (rotate)(out, mv, last); | |||
| return out; | |||
| } | |||
| } | |||
| @ -0,0 +1,130 @@ | |||
| #pragma once | |||
| #include <stddef.h> | |||
| #include "gp_config.hpp" | |||
| #include "gp/algorithm/move.hpp" | |||
| #include "gp/iterator.hpp" | |||
| namespace gp{ | |||
| template<typename T, size_t _capacity> | |||
| class indexed_array{ | |||
| size_t data_top = 0; | |||
| size_t available_indexes_top = 0; | |||
| size_t remove_top = 0; | |||
| T data_table[_capacity]; | |||
| size_t available_indexes[_capacity]; | |||
| size_t translation_table[_capacity]; | |||
| size_t reverse_translation_table[_capacity]; | |||
| size_t remove_table[_capacity]; | |||
| public: | |||
| indexed_array() {} | |||
| size_t push(T&& value) { | |||
| size_t index; | |||
| gp_config::assertion(data_top+1 != _capacity, "Indexed array capacity exceeded"); | |||
| if(available_indexes_top) { | |||
| available_indexes_top--; | |||
| index = available_indexes[available_indexes_top]; | |||
| } else { | |||
| index = data_top; | |||
| } | |||
| new(&data_table[data_top]) T(gp::move(value)); | |||
| translation_table[index] = data_top; | |||
| reverse_translation_table[data_top] = index; | |||
| ++data_top; | |||
| return index; | |||
| } | |||
| void pop(size_t idx) { | |||
| size_t v_idx = translation_table[idx]; | |||
| available_indexes[available_indexes_top] = idx; | |||
| ++available_indexes_top; | |||
| translation_table[idx] = -1; | |||
| --data_top; | |||
| if(v_idx < data_top) { | |||
| size_t u_idx = reverse_translation_table[data_top]; | |||
| data_table[v_idx] = gp::move(data_table[data_top]); | |||
| ::operator delete(&data_table[data_top], &data_table[data_top]); | |||
| data_table[data_top].~T(); | |||
| translation_table[u_idx] = v_idx; | |||
| reverse_translation_table[v_idx] = u_idx; | |||
| } | |||
| } | |||
| void reset() { | |||
| auto it = data_table; | |||
| auto end = data_table+data_top; | |||
| while(it != end) { | |||
| ::operator delete(it, it); | |||
| ++it; | |||
| } | |||
| data_top = 0; | |||
| available_indexes_top = 0; | |||
| remove_top = 0; | |||
| } | |||
| void mark_internal_for_removal(size_t i_idx) { | |||
| remove_table[remove_top] = reverse_translation_table[i_idx]; | |||
| ++remove_top; | |||
| } | |||
| void mark_for_removal(size_t idx) { | |||
| remove_table[remove_top] = idx; | |||
| ++remove_top; | |||
| } | |||
| void sweep_removed() { | |||
| auto it = remove_table; | |||
| auto end = remove_table+remove_top; | |||
| while(it != end) { | |||
| pop(*it); | |||
| ++it; | |||
| } | |||
| } | |||
| bool has(size_t idx) { | |||
| if(idx > data_top) return false; | |||
| if(translation_table[idx] == -1) return false; | |||
| return true; | |||
| } | |||
| pointer_iterator<T> begin() | |||
| { | |||
| return data_table; | |||
| } | |||
| pointer_iterator<T> end() | |||
| { | |||
| return data_table+data_top; | |||
| } | |||
| const_pointer_iterator<T> cbegin() | |||
| { | |||
| return data_table; | |||
| } | |||
| const_pointer_iterator<T> cend() | |||
| { | |||
| return data_table+data_top; | |||
| } | |||
| size_t size() { | |||
| return data_top; | |||
| } | |||
| size_t capacity() { | |||
| return _capacity; | |||
| } | |||
| T& operator[](size_t idx) { | |||
| gp_config::assertion(idx < data_top, "Bad indexed array access"); | |||
| return data_table[translation_table[idx]]; | |||
| } | |||
| }; | |||
| } | |||
| @ -0,0 +1,351 @@ | |||
| #pragma once | |||
| #include "gp_config.hpp" | |||
| #include "gp/math/integer_math.hpp" | |||
| #include "gp/math/q_math.hpp" | |||
| #if !defined(NO_FP_MATH) | |||
| # include "gp/math/fp_math.hpp" | |||
| #endif | |||
| #include "gp/algorithm/repeat.hpp" | |||
| #include "gp/algorithm/min_max.hpp" | |||
| namespace gp { | |||
| template<typename T> | |||
| T lerp(T input, T low, T high) { | |||
| return low + (high - low) * input; | |||
| } | |||
| template<typename T> | |||
| T lextrap(T input, T low, T high) { | |||
| return (input - low) / (high - low); | |||
| } | |||
| template<typename T, size_t fixed_passes = 16> | |||
| T fixed_sqrt(T value) { | |||
| gp_config::assertion(value >= 0, "trying to compute square root of negative number"); | |||
| if(value == 0) return 0; | |||
| T ret = value / 2; | |||
| T tmp; | |||
| gp::repeat(fixed_passes, [&](){ | |||
| tmp = ret; | |||
| ret = (value / tmp + tmp) / 2; | |||
| }); | |||
| return ret; | |||
| } | |||
| template<typename T, size_t cap_passes = 16> | |||
| T epsilon_sqrt(T value) { | |||
| gp_config::assertion(value >= 0, "trying to compute square root of negative number"); | |||
| if(value == 0) return 0; | |||
| T ret = value / 2; | |||
| T tmp; | |||
| constexpr T epsilon = gp_config::rendering::epsilon; | |||
| size_t cnt = 0; | |||
| while( | |||
| !( | |||
| (ret+epsilon)*ret > value | |||
| && (ret-epsilon)*ret < value | |||
| ) | |||
| && cnt < cap_passes | |||
| ){ | |||
| tmp = ret; | |||
| ret = (value / tmp + tmp) / 2; | |||
| ++cnt; | |||
| }; | |||
| return ret; | |||
| } | |||
| template<typename T, size_t cap_passes = 16> | |||
| T stable_sqrt(T value) { | |||
| gp_config::assertion(value >= 0, "trying to compute square root of negative number"); | |||
| if(value == 0) return 0; | |||
| T ret = value / 2; | |||
| T tmp; | |||
| while(ret != tmp){ | |||
| tmp = ret; | |||
| ret = (value / tmp + tmp) / 2; | |||
| }; | |||
| return ret; | |||
| } | |||
| template<typename T = gp_config::rendering::default_type> | |||
| struct vec2_g { | |||
| T x; | |||
| T y; | |||
| vec2_g() | |||
| : x{} | |||
| , y{} | |||
| {} | |||
| vec2_g( | |||
| T _x, | |||
| T _y | |||
| ) | |||
| : x{_x} | |||
| , y{_y} | |||
| {} | |||
| vec2_g operator/(vec2_g rhs) { | |||
| return { | |||
| x / rhs.x, | |||
| y / rhs.y | |||
| }; | |||
| } | |||
| vec2_g operator*(vec2_g rhs) { | |||
| return { | |||
| x * rhs.x, | |||
| y * rhs.y | |||
| }; | |||
| } | |||
| vec2_g operator+(vec2_g oth) { | |||
| return {x+oth.x, y+oth.y}; | |||
| } | |||
| vec2_g operator-(vec2_g oth) { | |||
| return {x-oth.x, y-oth.y}; | |||
| } | |||
| vec2_g normalize() { | |||
| T ilen = fast_isqrt(x*x+y*y); | |||
| return {x*ilen, y*ilen}; | |||
| } | |||
| T length() { | |||
| return fixed_sqrt(x*x+y*y); | |||
| } | |||
| }; | |||
| template<typename T = gp_config::rendering::default_type> | |||
| struct vec3_g { | |||
| T x; | |||
| T y; | |||
| T z; | |||
| T& r(){ | |||
| return x; | |||
| } | |||
| T& g(){ | |||
| return y; | |||
| } | |||
| T& b(){ | |||
| return z; | |||
| } | |||
| vec3_g() | |||
| : x{} | |||
| , y{} | |||
| , z{} | |||
| {} | |||
| vec3_g( | |||
| T _x, | |||
| T _y, | |||
| T _z | |||
| ) | |||
| : x{_x} | |||
| , y{_y} | |||
| , z{_z} | |||
| {} | |||
| vec3_g(vec2_g<T> left, T right) | |||
| : x{left.x} | |||
| , y{left.y} | |||
| , z{right} | |||
| {} | |||
| vec3_g(T left, vec2_g<T> right) | |||
| : x{left} | |||
| , y{right.x} | |||
| , z{right.y} | |||
| {} | |||
| vec3_g operator/(vec3_g rhs) { | |||
| return { | |||
| x / rhs.x, | |||
| y / rhs.y, | |||
| z / rhs.z | |||
| }; | |||
| } | |||
| vec3_g operator*(vec3_g rhs) { | |||
| return { | |||
| x * rhs.x, | |||
| y * rhs.y, | |||
| z * rhs.z | |||
| }; | |||
| } | |||
| vec3_g operator+(vec3_g oth) { | |||
| return {x+oth.x, y+oth.y, z+oth.z}; | |||
| } | |||
| vec3_g operator-(vec3_g oth) { | |||
| return {x-oth.x, y-oth.y, z-oth.z}; | |||
| } | |||
| vec3_g normalize() { | |||
| T ilen = fast_isqrt(x*x+y*y+z*z); | |||
| return {x*ilen, y*ilen, z*ilen}; | |||
| } | |||
| T length() { | |||
| return fixed_sqrt(x*x+y*y+z*z); | |||
| } | |||
| }; | |||
| template<typename T = gp_config::rendering::default_type> | |||
| struct vec4_g { | |||
| T x; | |||
| T y; | |||
| T z; | |||
| T w; | |||
| T& r(){ | |||
| return x; | |||
| } | |||
| T& g(){ | |||
| return y; | |||
| } | |||
| T& b(){ | |||
| return z; | |||
| } | |||
| T& a(){ | |||
| return w; | |||
| } | |||
| vec4_g() | |||
| : x{} | |||
| , y{} | |||
| , z{} | |||
| , w{} | |||
| {} | |||
| vec4_g( | |||
| T _x, | |||
| T _y, | |||
| T _z, | |||
| T _w | |||
| ) | |||
| : x{_x} | |||
| , y{_y} | |||
| , z{_z} | |||
| , w{_w} | |||
| {} | |||
| vec4_g(T left, vec3_g<> right) | |||
| : x{left} | |||
| , y{right.x} | |||
| , z{right.y} | |||
| , w{right.z} | |||
| {} | |||
| vec4_g(vec3_g<> left, T right) | |||
| : x{left.x} | |||
| , y{left.y} | |||
| , z{left.z} | |||
| , w{right} | |||
| {} | |||
| vec4_g operator/(vec4_g rhs) { | |||
| return { | |||
| x / rhs.x, | |||
| y / rhs.y, | |||
| z / rhs.z, | |||
| w / rhs.w | |||
| }; | |||
| } | |||
| vec4_g operator*(vec4_g rhs) { | |||
| return { | |||
| x * rhs.x, | |||
| y * rhs.y, | |||
| z * rhs.z, | |||
| w * rhs.w | |||
| }; | |||
| } | |||
| vec4_g operator+(vec4_g oth) { | |||
| return {x+oth.x, y+oth.y, z+oth.z, w+oth.w}; | |||
| } | |||
| vec4_g operator-(vec4_g oth) { | |||
| return {x-oth.x, y-oth.y, z-oth.w, z-oth.w}; | |||
| } | |||
| vec4_g normalize() { | |||
| T ilen = fast_isqrt(x*x+y*y+z*z+w*w); | |||
| return {x*ilen, y*ilen, z*ilen, w*ilen}; | |||
| } | |||
| T length() { | |||
| return fixed_sqrt(x*x+y*y+z*z+w*w); | |||
| } | |||
| }; | |||
| template<typename T> | |||
| auto sphere_sdf(vec3_g<T> center, T radius) { | |||
| return [=](vec3_g<T> position) -> T const { | |||
| auto p = position - center; | |||
| return p.length() - radius; | |||
| }; | |||
| } | |||
| template<typename T, typename lhs, typename rhs> | |||
| auto union_sdf(lhs _l, rhs _r) { | |||
| return [=](vec3_g<T> position) -> T const { | |||
| return gp::min(_l(position), _r(position)); | |||
| }; | |||
| } | |||
| template<typename T, typename lhs, typename rhs> | |||
| auto intersect_sdf(lhs _l, rhs _r) { | |||
| return [=](vec3_g<T> position) -> T const { | |||
| return gp::max(_l(position), _r(position)); | |||
| }; | |||
| } | |||
| template<typename T, typename lhs, typename rhs> | |||
| auto difference_sdf(lhs _l, rhs _r) { | |||
| return [=](vec3_g<T> position) -> T const { | |||
| return gp::max(_l(position), -_r(position)); | |||
| }; | |||
| } | |||
| template<typename T> | |||
| vec2_g<T> operator*(vec2_g<T> p, T v) { | |||
| return {p.x*v, p.y*v}; | |||
| } | |||
| template<typename T> | |||
| vec3_g<T> operator*(vec3_g<T> p, T v) { | |||
| return {p.x*v, p.y*v, p.z*v}; | |||
| } | |||
| template<typename T> | |||
| vec4_g<T> operator*(vec4_g<T> p, T v) { | |||
| return {p.x*v, p.y*v, p.z*v, p.w*v}; | |||
| } | |||
| template<typename T> | |||
| vec2_g<T> operator*(T v, vec2_g<T> p) { | |||
| return p*v; | |||
| } | |||
| template<typename T> | |||
| vec3_g<T> operator*(T v, vec3_g<T> p) { | |||
| return p*v; | |||
| } | |||
| template<typename T> | |||
| vec4_g<T> operator*(T v, vec4_g<T> p) { | |||
| return p*v; | |||
| } | |||
| } | |||
| static_assert(sizeof(gp::vec3_g<int>) == sizeof(int)*3, "vec3_g has strange alignment"); | |||
| static_assert(sizeof(gp::vec4_g<int>) == sizeof(int)*4, "vec4_g has strange alignment"); | |||
| @ -0,0 +1,196 @@ | |||
| #pragma once | |||
| #include <stddef.h> | |||
| #include <stdint.h> | |||
| #include <limits> | |||
| #include "gp/algorithm/repeat.hpp" | |||
| namespace gp{ | |||
| template<typename T> | |||
| constexpr T pi; | |||
| template<> | |||
| constexpr float pi<float> = 3.1415926535897932384626433832795028841971693993751058209749445923078164062; | |||
| template<> | |||
| constexpr double pi<double> = 3.1415926535897932384626433832795028841971693993751058209749445923078164062; | |||
| template<typename T> | |||
| T abs(T); | |||
| template<> | |||
| float abs<float>(float value) { | |||
| static_assert(sizeof(float) == 4, "bad float size"); | |||
| union { | |||
| float fp; | |||
| uint32_t ab; | |||
| } p; | |||
| p.fp = value; | |||
| p.ab &= 0x7fFFffFF; | |||
| return p.fp; | |||
| } | |||
| template<> | |||
| double abs<double>(double value) { | |||
| static_assert(sizeof(double) == 8, "bad double size"); | |||
| union { | |||
| double fp; | |||
| uint64_t ab; | |||
| } p; | |||
| p.fp = value; | |||
| p.ab &= 0x7fFFffFFffFFffFF; | |||
| return p.fp; | |||
| } | |||
| template<typename T> | |||
| T floor(T); | |||
| template<> | |||
| float floor<float>(float value) { | |||
| static_assert(sizeof(float) == 4, "bad float size"); | |||
| if( | |||
| value >= std::numeric_limits<int32_t>::max() | |||
| || value <= std::numeric_limits<int32_t>::min() | |||
| || value != value | |||
| ) { | |||
| return value; | |||
| } | |||
| int32_t ret = value; | |||
| float ret_d = ret; | |||
| if(value == ret_d || value >= 0) { | |||
| return ret; | |||
| } else { | |||
| return ret-1; | |||
| } | |||
| } | |||
| template<> | |||
| double floor<double>(double value) { | |||
| static_assert(sizeof(double) == 8, "bad double size"); | |||
| if( | |||
| value >= std::numeric_limits<int64_t>::max() | |||
| || value <= std::numeric_limits<int64_t>::min() | |||
| || value != value | |||
| ) { | |||
| return value; | |||
| } | |||
| int64_t ret = value; | |||
| double ret_d = ret; | |||
| if(value == ret_d || value >= 0) { | |||
| return ret; | |||
| } else { | |||
| return ret-1; | |||
| } | |||
| } | |||
| template<typename T> | |||
| T sign(T); | |||
| template<> | |||
| float sign<float>(float value) { | |||
| static_assert(sizeof(float) == 4, "bad float size"); | |||
| if(!value) return 0; | |||
| union { | |||
| float fp; | |||
| uint32_t ab; | |||
| } p; | |||
| p.fp = value; | |||
| p.ab &= 0x7fFFffFF; | |||
| return value/p.fp; | |||
| } | |||
| template<> | |||
| double sign<double>(double value) { | |||
| static_assert(sizeof(double) == 8, "bad double size"); | |||
| if(!value) return 0; | |||
| union { | |||
| double fp; | |||
| uint64_t ab; | |||
| } p; | |||
| p.fp = value; | |||
| p.ab &= 0x7fFFffFFffFFffFF; | |||
| return value/p.fp; | |||
| } | |||
| template<size_t steps, typename T, size_t accuracy = 1000000> | |||
| T sin_taylor(T value) { | |||
| const T acc = T{1}/T{accuracy}; | |||
| T B = value; | |||
| T C = 1; | |||
| T ret = B/C; | |||
| for(size_t i = 1; (i < steps) && (abs<>(B/C) > acc); ++i) { | |||
| B *= -1*value*value; | |||
| C *= 2*i*(2*i+1); | |||
| ret += B/C; | |||
| } | |||
| return ret; | |||
| } | |||
| float sin(float v) { | |||
| v += pi<float>; | |||
| v = v - 2*pi<float>*floor(v/(2*pi<float>)); | |||
| v -= pi<float>; | |||
| float s = sign(v); | |||
| v *= s; | |||
| return sin_taylor<10>(v)*s; | |||
| } | |||
| double sin(double v) { | |||
| v += pi<double>; | |||
| v = v - 2*pi<double>*floor(v/(2*pi<double>)); | |||
| v -= pi<double>; | |||
| float s = sign(v); | |||
| v *= s; | |||
| return sin_taylor<10>(v)*s; | |||
| } | |||
| // TODO: replace with an actual implementation | |||
| float cos(float v) { | |||
| return sin(v+pi<float>/2); | |||
| } | |||
| // TODO: replace with an actual implementation | |||
| double cos(double v) { | |||
| return sin(v+pi<float>/2); | |||
| } | |||
| template<size_t cycles = 5> | |||
| float isqrt(float v) { | |||
| int32_t i; | |||
| float x2, y; | |||
| constexpr float threehalfs = 1.5F; | |||
| x2 = v * 0.5F; | |||
| y = v; | |||
| i = * ( int32_t * ) &y; | |||
| i = 0x5F375A86 - ( i >> 1 ); | |||
| y = * ( float * ) &i; | |||
| gp::repeat(cycles, [&](){ | |||
| y = y * ( threehalfs - ( x2 * y * y ) ); | |||
| }); | |||
| return y; | |||
| } | |||
| template<size_t cycles = 5> | |||
| double isqrt(double v) { | |||
| int64_t i; | |||
| double x2, y; | |||
| constexpr double threehalfs = 1.5F; | |||
| x2 = v * 0.5F; | |||
| y = v; | |||
| i = * ( int64_t * ) &y; | |||
| i = 0x5FE6EB50C7B537A9 - ( i >> 1 ); | |||
| y = * ( double * ) &i; | |||
| gp::repeat(cycles, [&](){ | |||
| y = y * ( threehalfs - ( x2 * y * y ) ); | |||
| }); | |||
| return y; | |||
| } | |||
| float fast_isqrt(float v) {return isqrt<1>(v);} | |||
| double fast_isqrt(double v) {return isqrt<1>(v);} | |||
| } | |||
| @ -0,0 +1,76 @@ | |||
| #pragma once | |||
| #include <stdint.h> | |||
| #include <stddef.h> | |||
| namespace gp { | |||
| namespace math { | |||
| template<typename word_t> | |||
| size_t log2(word_t v); | |||
| /** | |||
| Sean Eron Anderson | |||
| seander@cs.stanford.edu | |||
| **/ | |||
| template<> | |||
| constexpr size_t log2<uint32_t>(uint32_t v) | |||
| { | |||
| constexpr int MultiplyDeBruijnBitPosition[32] = | |||
| { | |||
| 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, | |||
| 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 | |||
| }; | |||
| v |= v >> 1; | |||
| v |= v >> 2; | |||
| v |= v >> 4; | |||
| v |= v >> 8; | |||
| v |= v >> 16; | |||
| return MultiplyDeBruijnBitPosition[(uint32_t)(v * 0x07C4ACDDU) >> 27]; | |||
| } | |||
| template<> | |||
| constexpr size_t log2<uint64_t>(uint64_t v) | |||
| { | |||
| constexpr int MultiplyDeBruijnBitPosition[64] = | |||
| { | |||
| 0, 58, 1, 59, 47, 53, 2, 60, 39, 48, 27, 54, 33, 42, 3, 61, | |||
| 51, 37, 40, 49, 18, 28, 20, 55, 30, 34, 11, 43, 14, 22, 4, 62, | |||
| 57, 46, 52, 38, 26, 32, 41, 50, 36, 17, 19, 29, 10, 13, 21, 56, | |||
| 45, 25, 31, 35, 16, 9, 12, 44, 24, 15, 8, 23, 7, 6, 5, 63 | |||
| }; | |||
| v |= v >> 1; | |||
| v |= v >> 2; | |||
| v |= v >> 4; | |||
| v |= v >> 8; | |||
| v |= v >> 16; | |||
| v |= v >> 32; | |||
| return MultiplyDeBruijnBitPosition[(uint64_t)(v * 0x03f6eaf2cd271461) >> 58]; | |||
| } | |||
| static_assert(log2<uint32_t>(7) == 2, "bad log2"); | |||
| static_assert(log2<uint32_t>(8) == 3, "bad log2"); | |||
| template<typename word_t> | |||
| constexpr size_t msb(word_t v); | |||
| template<> | |||
| constexpr size_t msb<uint32_t>(uint32_t v) | |||
| { | |||
| auto l = log2(v); | |||
| return l + (((1 << l) ^ v) != 0); | |||
| } | |||
| template<> | |||
| constexpr size_t msb<uint64_t>(uint64_t v) | |||
| { | |||
| auto l = log2(v); | |||
| return l + (((1 << l) ^ v) != 0); | |||
| } | |||
| static_assert(msb<uint32_t>(7) == 3, "bad log2"); | |||
| static_assert(msb<uint32_t>(8) == 3, "bad log2"); | |||
| } | |||
| } | |||
| @ -0,0 +1,16 @@ | |||
| #pragma once | |||
| #include "gp/allocator/buddy.hpp" | |||
| #include "gp/allocator/dummy.hpp" | |||
| struct static_mapper { | |||
| static gp::array<char, 4096> store; | |||
| static gp::buddy<> impl; | |||
| void* allocate(size_t sz) { | |||
| return impl.allocate(sz); | |||
| } | |||
| bool deallocate(void* ptr) { | |||
| return impl.deallocate(ptr); | |||
| } | |||
| }; | |||