@ -1,3 +1,69 @@ | |||||
# gplib | # 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); | |||||
} | |||||
}; |