diff --git a/.gitignore b/.gitignore index efa382c..1e68462 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,7 @@ default.profraw bin/tests.profdata bin/tests.profraw bin/test_n +render.bmp +README.html +bin/tests.S +bin/tests.S.zip diff --git a/README.md b/README.md index dcf516f..d4f67b5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,69 @@ # gplib -General Purpose library for POSIX systems \ No newline at end of file +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 \ No newline at end of file diff --git a/include/gp/algorithm/rotate.hpp b/include/gp/algorithm/rotate.hpp new file mode 100644 index 0000000..3bc105d --- /dev/null +++ b/include/gp/algorithm/rotate.hpp @@ -0,0 +1,26 @@ +#pragma once +#include "gp/algorithm/move.hpp" + +namespace gp { + template + 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; + } + +} \ No newline at end of file diff --git a/include/gp/allocator/buddy.hpp b/include/gp/allocator/buddy.hpp index 05e9820..a9799c8 100644 --- a/include/gp/allocator/buddy.hpp +++ b/include/gp/allocator/buddy.hpp @@ -2,7 +2,7 @@ #include "gp_config.hpp" #include "gp/buffer.hpp" #include "gp/array.hpp" -#include "gp/integer_math.hpp" +#include "gp/math.hpp" #include #include #include diff --git a/include/gp/array.hpp b/include/gp/array.hpp index f0b1e19..ce09add 100644 --- a/include/gp/array.hpp +++ b/include/gp/array.hpp @@ -5,20 +5,74 @@ namespace gp{ template class array{ - T ary[sz]; public: - using associated_iterator = pointer_iterator; - using associated_const_iterator = pointer_iterator; + T ary[sz]; + using associated_iterator = pointer_iterator; + using associated_const_iterator = const_pointer_iterator; + using associated_riterator = pointer_iterator; + using associated_const_riterator = const_pointer_iterator; array() : ary() {} + array(const array& oth) + { + auto it_l = begin(); + auto it_o = oth.cbegin(); + for(size_t i = 0; i < sz; ++i) + { + new(&*(it_l++)) T(*(it_o++)); + } + } + template - array(U&& ...v) - : ary{gp::forward(v...)} + array(U&& ...values) + : ary{gp::move((T&&)values)...} {} + array(array&& values) + { + gp::move_uninitialized( + values, + *this + ); + } + + template<> + array(T (& oth)[sz]) { + gp::move_uninitialized( + gp::nameless_range(oth, oth+sz), + gp::nameless_range(begin(), end()) + ); + } + + template<> + array(T (&& oth)[sz]) { + gp::move_uninitialized( + gp::nameless_range(oth, oth+sz), + gp::nameless_range(begin(), end()) + ); + } + + array& operator=(array& oth) + { + for(size_t i = 0; i < sz; ++i) + { + ary[i]=oth[i]; + } + return *this; + } + + array& operator=(array&& oth) + { + for(size_t i = 0; i < sz; ++i) + { + ary[i]=gp::move(oth[i]); + } + return *this; + } + constexpr T& operator[] (size_t off) { if constexpr (gp_config::has_buffer_bounds) @@ -41,24 +95,44 @@ namespace gp{ return sz; } - constexpr associated_iterator begin() + constexpr pointer_iterator begin() { return associated_iterator(&ary[0]); } - constexpr associated_iterator end() + constexpr pointer_iterator end() { return associated_iterator(&ary[sz]); } - constexpr associated_const_iterator cbegin() const + constexpr const_pointer_iterator cbegin() const + { + return associated_const_iterator(&ary[0]); + } + + constexpr const_pointer_iterator cend() const + { + return associated_const_iterator(&ary[sz]); + } + + constexpr pointer_iterator rbegin() + { + return associated_riterator(&ary[sz-1]); + } + + constexpr pointer_iterator rend() + { + return associated_riterator(ary-1); + } + + constexpr const_pointer_iterator crbegin() const { - return ary; + return associated_const_riterator(&ary[sz-1]); } - constexpr associated_const_iterator cend() const + constexpr const_pointer_iterator crend() const { - return ary+sz; + return associated_const_riterator(ary-1); } constexpr bool operator==(const array& oth) const diff --git a/include/gp/buffer.hpp b/include/gp/buffer.hpp index f6a1577..3ea66f9 100644 --- a/include/gp/buffer.hpp +++ b/include/gp/buffer.hpp @@ -119,5 +119,29 @@ namespace gp{ return buffer{(T*)nullptr,(size_t)0}; } } + + buffer trim_start(size_t rm_sz) + { + if(rm_sz<=size()) + { + return buffer{begin().data + rm_sz, end().data}; + } + else + { + return buffer{(T*)nullptr,(size_t)0}; + } + } + + buffer trim_end(size_t rm_sz) + { + if(rm_sz<=size()) + { + return buffer{begin().data, end().data - rm_sz}; + } + else + { + return buffer{(T*)nullptr,(size_t)0}; + } + } }; } \ No newline at end of file diff --git a/include/gp/function.hpp b/include/gp/function.hpp index 059f068..ad52f32 100644 --- a/include/gp/function.hpp +++ b/include/gp/function.hpp @@ -1,5 +1,7 @@ #pragma once #include "gp/exception.hpp" +#include "gp/algorithm/tmp_manip.hpp" +#include "gp/algorithm/move.hpp" namespace gp{ @@ -10,26 +12,50 @@ namespace gp{ class function{ struct virtual_callable { + virtual void inplace_move(char*) = 0; + virtual virtual_callable* all_copy() = 0; + virtual void inplace_copy(char*) = 0; + virtual virtual_callable* all_move() = 0; virtual ~virtual_callable() = default; virtual ret operator() (args...) = 0; }; template - class callable : virtual_callable{ - fn internal_representation; + class callable final : public virtual_callable{ + typename gp::remove_reference::type internal_representation; public: - callable(const fn& func) - : internal_representation{func} + callable(const fn func) + : internal_representation{gp::move(func)} {} + callable(callable&) = default; + callable(callable&&) = default; + virtual ~callable() override = default; - ret operator() (args... arg_list) + virtual void inplace_copy(char* ptr) override { + new(ptr) callable(*this); + } + + virtual virtual_callable* all_copy() override { + return new callable(*this); + } + + virtual void inplace_move(char* ptr) override { + new(ptr) callable(gp::move(*this)); + } + + virtual virtual_callable* all_move() override { + return new callable(gp::move(*this)); + } + + ret operator() (args... arg_list) override { return internal_representation(arg_list...); } }; + // tweak a way to store a size in there for trivial copy enum state_t : uint8_t{ INACTIVE = 0, ACTIVE = 1, @@ -37,7 +63,7 @@ namespace gp{ SOO = 2 }; - state_t state = 0; + state_t state{}; union{ virtual_callable* functor = nullptr; char inplace[12]; @@ -51,52 +77,103 @@ namespace gp{ { if(state & SOO) { - ((virtual_callable*)&self)->~virtual_callable(); + ((virtual_callable*)self.inplace)->~virtual_callable(); } else { delete self.functor; } } - if constexpr (sizeof(callable) <= sizeof(self)) + if(!(t.state & ACTIVE)) { - new((void*)&self) callable(t); - state = ACTIVE | SOO; + state = INACTIVE; + return; } - else - { - self = new callable(t); - state = ACTIVE | NO_SOO; + if constexpr (!std::is_same_v>) { + if constexpr (sizeof(callable) <= sizeof(self)) + { + new((void*)self.inplace) callable(t); + state = (state_t)(ACTIVE | SOO); + } + else + { + self.functor = new callable(t); + state = (state_t)(ACTIVE | NO_SOO); + } + } else { + if(t.state & SOO) + { + auto& ref = t.self.functor; + ref->inplace_copy((char*)&self); + state = (state_t)(ACTIVE | SOO); + } + else + { + self.functor = t.self.functor->all_copy(); + state = (state_t)(ACTIVE | NO_SOO); + } } } - template - function(T t) + function() { - if constexpr (sizeof(callable) <= sizeof(self)) - { - new((void*)&self) callable(t); - state = ACTIVE | SOO; - } - else - { - self = new callable(t); - state = ACTIVE | NO_SOO; + state = INACTIVE; + } + + template + function<>(T& t) + { + if constexpr (!std::is_same_v>) { + if constexpr (sizeof(callable) <= sizeof(self)) + { + new((void*)self.inplace) callable(t); + state = (state_t)(ACTIVE | SOO); + } + else + { + self.functor = new callable(t); + state = (state_t)(ACTIVE | NO_SOO); + } + } else { + if(t.state & SOO) + { + t.self.functor->inplace_copy(self.inplace); + state = (state_t)(ACTIVE | SOO); + } + else + { + self.functor = t.self.functor->all_copy(); + state = (state_t)(ACTIVE | NO_SOO); + } } } template - function(T& t) + function(T&& t) { - if constexpr (sizeof(callable) <= sizeof(self)) - { - new((void*)&self) callable(t); - state = ACTIVE | SOO; - } - else - { - self = new callable(t); - state = ACTIVE | NO_SOO; + if constexpr (!std::is_same_v>) { + if constexpr (sizeof(callable) <= sizeof(self)) + { + new((void*)self.inplace) callable(gp::move(t)); + state = (state_t)(ACTIVE | SOO); + } + else + { + self.functor = new callable(gp::move(t)); + state = (state_t)(ACTIVE | NO_SOO); + } + } else { + if(t.state & SOO) + { + auto& ref = t.self.functor; + ref->inplace_move((char*)&self); + state = (state_t)(ACTIVE | SOO); + } + else + { + self.functor = t.self.functor->all_move(); + state = (state_t)(ACTIVE | NO_SOO); + } } } @@ -114,7 +191,7 @@ namespace gp{ } else { - return (*(self.functor))(arg_list...); + return (*self.functor)(arg_list...); } } diff --git a/include/gp/indexed_array.hpp b/include/gp/indexed_array.hpp new file mode 100644 index 0000000..8d8874a --- /dev/null +++ b/include/gp/indexed_array.hpp @@ -0,0 +1,130 @@ +#pragma once +#include +#include "gp_config.hpp" +#include "gp/algorithm/move.hpp" +#include "gp/iterator.hpp" +namespace gp{ + template + 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 begin() + { + return data_table; + } + + pointer_iterator end() + { + return data_table+data_top; + } + + const_pointer_iterator cbegin() + { + return data_table; + } + + const_pointer_iterator 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]]; + } + }; +} \ No newline at end of file diff --git a/include/gp/iterator.hpp b/include/gp/iterator.hpp index 9e2dc49..1f66b69 100644 --- a/include/gp/iterator.hpp +++ b/include/gp/iterator.hpp @@ -8,7 +8,7 @@ enum class iterator_type_t{ lazy_iterator }; -template +template struct pointer_iterator final { T* data; @@ -24,76 +24,171 @@ struct pointer_iterator final : data{ptr} {} - constexpr operator T&() + constexpr T& operator*() { return *data; } - constexpr T& operator*(){ - return *data; - } - - constexpr pointer_iterator operator++() + constexpr pointer_iterator& operator++() { - return pointer_iterator{++data}; + data += sign; + return *this; } constexpr pointer_iterator operator++(int) { - return pointer_iterator{data++}; + auto p = *this; + data += sign; + return p; } - constexpr pointer_iterator operator--() + constexpr pointer_iterator& operator--() { - return pointer_iterator{--data}; + data -= sign; + return *this; } constexpr pointer_iterator operator--(int) { - return pointer_iterator{data--}; + auto p = *this; + data -= sign; + return p; } constexpr pointer_iterator operator+(const std::size_t offset) { - return pointer_iterator{data+offset}; + return pointer_iterator{data+sign*offset}; } constexpr pointer_iterator operator+(const int offset) { - return pointer_iterator{data+offset}; + return pointer_iterator{data+sign*offset}; } constexpr pointer_iterator operator-(const std::size_t offset) { - return pointer_iterator{data-offset}; + return pointer_iterator{data-sign*offset}; } constexpr pointer_iterator operator-(const int offset) { - return pointer_iterator{data-offset}; + return pointer_iterator{data-sign*offset}; } constexpr difference_type operator-(const pointer_iterator& oth) const { - return (T*)data-(T*)oth.data; + return ((T*)data-(T*)oth.data)*sign; + } + + constexpr bool operator==(const pointer_iterator oth) + { + return data==oth.data; + } + + constexpr bool operator!=(pointer_iterator oth) + { + return data!=oth.data; + } + + constexpr bool before_or_equal(const pointer_iterator oth) + { + return reinterpret_cast(data) <= reinterpret_cast(oth.data); + } + + constexpr bool operator<=(const pointer_iterator oth) + { + return before_or_equal(oth); + } +}; + +template +struct const_pointer_iterator final +{ + const T* data; + typedef T value_type; + typedef std::size_t difference_type; + static constexpr iterator_type_t iterator_type = iterator_type_t::contiguous_iterator; + + constexpr const_pointer_iterator(const const_pointer_iterator& oth) + : data{oth.data} + {} + + constexpr const_pointer_iterator(const T* ptr) + : data{ptr} + {} + + constexpr const T& operator*() + { + return *data; + } + + constexpr const_pointer_iterator& operator++() + { + data += sign; + return *this; + } + + constexpr const_pointer_iterator operator++(int) + { + auto p = data; + data += sign; + return const_pointer_iterator{p}; + } + + constexpr const_pointer_iterator& operator--() + { + data -= sign; + return *this; + } + + constexpr const_pointer_iterator operator--(int) + { + auto p = data; + data -= sign; + return const_pointer_iterator{p}; + } + + constexpr const_pointer_iterator operator+(const std::size_t offset) + { + return const_pointer_iterator{data+sign*offset}; + } + + constexpr const_pointer_iterator operator+(const int offset) + { + return const_pointer_iterator{data+sign*offset}; + } + + constexpr const_pointer_iterator operator-(const std::size_t offset) + { + return const_pointer_iterator{data-sign*offset}; + } + + constexpr const_pointer_iterator operator-(const int offset) + { + return const_pointer_iterator{data-sign*offset}; + } + + constexpr difference_type operator-(const const_pointer_iterator& oth) const + { + return ((T*)data-(T*)oth.data)*sign; } - constexpr bool operator==(const pointer_iterator& oth) + constexpr bool operator==(const const_pointer_iterator oth) { return data==oth.data; } - constexpr bool operator!=(pointer_iterator& oth) + constexpr bool operator!=(const_pointer_iterator oth) { return data!=oth.data; } - constexpr bool before_or_equal(const pointer_iterator& oth) + constexpr bool before_or_equal(const const_pointer_iterator oth) { return reinterpret_cast(data) <= reinterpret_cast(oth.data); } - constexpr bool operator<=(const pointer_iterator& oth) + constexpr bool operator<=(const const_pointer_iterator oth) { return before_or_equal(oth); } diff --git a/include/gp/math.hpp b/include/gp/math.hpp new file mode 100644 index 0000000..9d5661e --- /dev/null +++ b/include/gp/math.hpp @@ -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 + T lerp(T input, T low, T high) { + return low + (high - low) * input; + } + template + T lextrap(T input, T low, T high) { + return (input - low) / (high - low); + } + + template + 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 + 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 + 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 + 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 + 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 left, T right) + : x{left.x} + , y{left.y} + , z{right} + {} + + vec3_g(T left, vec2_g 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 + 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 + auto sphere_sdf(vec3_g center, T radius) { + return [=](vec3_g position) -> T const { + auto p = position - center; + return p.length() - radius; + }; + } + + template + auto union_sdf(lhs _l, rhs _r) { + return [=](vec3_g position) -> T const { + return gp::min(_l(position), _r(position)); + }; + } + + template + auto intersect_sdf(lhs _l, rhs _r) { + return [=](vec3_g position) -> T const { + return gp::max(_l(position), _r(position)); + }; + } + + template + auto difference_sdf(lhs _l, rhs _r) { + return [=](vec3_g position) -> T const { + return gp::max(_l(position), -_r(position)); + }; + } + + template + vec2_g operator*(vec2_g p, T v) { + return {p.x*v, p.y*v}; + } + + template + vec3_g operator*(vec3_g p, T v) { + return {p.x*v, p.y*v, p.z*v}; + } + + template + vec4_g operator*(vec4_g p, T v) { + return {p.x*v, p.y*v, p.z*v, p.w*v}; + } + + template + vec2_g operator*(T v, vec2_g p) { + return p*v; + } + + template + vec3_g operator*(T v, vec3_g p) { + return p*v; + } + + template + vec4_g operator*(T v, vec4_g p) { + return p*v; + } +} + +static_assert(sizeof(gp::vec3_g) == sizeof(int)*3, "vec3_g has strange alignment"); +static_assert(sizeof(gp::vec4_g) == sizeof(int)*4, "vec4_g has strange alignment"); \ No newline at end of file diff --git a/include/gp/math/fp_math.hpp b/include/gp/math/fp_math.hpp new file mode 100644 index 0000000..a021b93 --- /dev/null +++ b/include/gp/math/fp_math.hpp @@ -0,0 +1,196 @@ +#pragma once +#include +#include +#include +#include "gp/algorithm/repeat.hpp" + +namespace gp{ + + template + constexpr T pi; + + template<> + constexpr float pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062; + + template<> + constexpr double pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062; + + template + T abs(T); + + template<> + float abs(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 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 + T floor(T); + + template<> + float floor(float value) { + static_assert(sizeof(float) == 4, "bad float size"); + if( + value >= std::numeric_limits::max() + || value <= std::numeric_limits::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 value) { + static_assert(sizeof(double) == 8, "bad double size"); + if( + value >= std::numeric_limits::max() + || value <= std::numeric_limits::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 + T sign(T); + + template<> + float sign(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 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 + 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; + v = v - 2*pi*floor(v/(2*pi)); + v -= pi; + float s = sign(v); + v *= s; + return sin_taylor<10>(v)*s; + } + + double sin(double v) { + v += pi; + v = v - 2*pi*floor(v/(2*pi)); + v -= pi; + 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/2); + } + + // TODO: replace with an actual implementation + double cos(double v) { + return sin(v+pi/2); + } + + template + 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 + 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);} +} diff --git a/include/gp/math/integer_math.hpp b/include/gp/math/integer_math.hpp new file mode 100644 index 0000000..6691f46 --- /dev/null +++ b/include/gp/math/integer_math.hpp @@ -0,0 +1,76 @@ +#pragma once +#include +#include + +namespace gp { + namespace math { + + template + size_t log2(word_t v); + + /** + Sean Eron Anderson + seander@cs.stanford.edu + **/ + template<> + constexpr size_t log2(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 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(7) == 2, "bad log2"); + static_assert(log2(8) == 3, "bad log2"); + + template + constexpr size_t msb(word_t v); + + template<> + constexpr size_t msb(uint32_t v) + { + auto l = log2(v); + return l + (((1 << l) ^ v) != 0); + } + template<> + constexpr size_t msb(uint64_t v) + { + auto l = log2(v); + return l + (((1 << l) ^ v) != 0); + } + + static_assert(msb(7) == 3, "bad log2"); + static_assert(msb(8) == 3, "bad log2"); + } +} diff --git a/include/gp/math/q_math.hpp b/include/gp/math/q_math.hpp new file mode 100644 index 0000000..e69de29 diff --git a/include/gp_config.hpp b/include/gp_config.hpp index f5b7c0b..54cb9fb 100644 --- a/include/gp_config.hpp +++ b/include/gp_config.hpp @@ -4,46 +4,33 @@ #include #include -namespace gp_config{ - namespace memory_module{ - enum class memory_mode_t{ - other, - clib, - buffer, - arena_buffer - }; - - constexpr memory_mode_t memory_mode = memory_mode_t::clib; - - - template - constexpr void*(*memory_allocator)(std::size_t)=nullptr; - template - constexpr void(*memory_deallocator)(void*)=nullptr; - - // C Standard library memory usage - template<> - constexpr void*(*memory_allocator)(std::size_t) = malloc; - template<> - constexpr void(*memory_deallocator)(void*) = free; +#ifdef GP_TESTS + class static_mapper; +#else +namespace gp { + class c_allocator; +} +#endif - // Buffer memory usage only - template<> - constexpr void*(*memory_allocator)(std::size_t) = nullptr; - template<> - constexpr void(*memory_deallocator)(void*) = nullptr; +namespace gp_config{ + namespace rendering { + using default_type = float; + constexpr default_type epsilon = 0.001; +#define GP_CONFIG__RENDERING__COLOR_T vec4 + } - // Buffer of arena memory usage - template<> - constexpr void*(*memory_allocator)(std::size_t) = nullptr; - template<> - constexpr void(*memory_deallocator)(void*) = nullptr; + namespace memory_module{ + #ifdef GP_TESTS + using default_allocator = static_mapper; + #else + using default_allocator = gp::c_allocator; + #endif - constexpr bool is_ok = - ( memory_allocator != nullptr ) - && ( memory_deallocator != nullptr ); + constexpr bool is_ok = true; } + typedef uint32_t file_descriptor_t; + constexpr bool has_exceptions = true; constexpr bool has_buffer_bounds = true; diff --git a/tests.cpp b/tests.cpp index 4930d58..70d7c82 100644 --- a/tests.cpp +++ b/tests.cpp @@ -6,6 +6,9 @@ #include "quotient_filter.cpp" #include +alignas(2048) gp::array static_mapper::store; +gp::buddy<> static_mapper::impl = gp::buddy<>{store.begin().data, store.size()}; + int main() { uint failed = 0; @@ -14,13 +17,13 @@ int main() { ++runned; int value; - //try{ + try{ value = test->run(); if(value) { std::cout << std::dec << test->name << " failed with "<< value << std::endl; } - /*} catch (gp::runtime_error err) { + } catch (gp::runtime_error err) { std::cout << test->name << " failed with an exception: " << err.what() << std::endl; value = -1; } catch (gp_config::assert_failure err) { @@ -29,7 +32,7 @@ int main() } catch (...) { std::cout << test->name << " failed with an exception" << std::endl; value = -1; - }*/ + } failed += (value != 0); } std::cout << std::dec << "Runned "< store; + static gp::buddy<> impl; + + void* allocate(size_t sz) { + return impl.allocate(sz); + } + + bool deallocate(void* ptr) { + return impl.deallocate(ptr); + } +}; \ No newline at end of file diff --git a/tests/gp_test.cpp b/tests/gp_test.cpp index 12ea7f4..8b15735 100644 --- a/tests/gp_test.cpp +++ b/tests/gp_test.cpp @@ -1,9 +1,12 @@ #include "test_scaffold.h" +#include "allocator.hpp" #include "gp/array.hpp" +#include "gp/indexed_array.hpp" #include "gp/allocator/aggregator.hpp" #include "gp/allocator/buddy.hpp" #include "gp/allocator/dummy.hpp" #include "gp/algorithm/repeat.hpp" +#include "gp/algorithm/rotate.hpp" #include "gp/ring_list.hpp" #include #include @@ -28,20 +31,6 @@ constexpr bool time_fuzzes = true; -struct static_mapper { - static gp::array store; - static gp::buddy<> impl; - - void* allocate(size_t sz) { - return impl.allocate(sz); - } - - bool deallocate(void* ptr) { - return impl.deallocate(ptr); - } -}; -alignas(2048) gp::array static_mapper::store; -gp::buddy<> static_mapper::impl = gp::buddy<>{store.begin().data, store.size()}; struct arraysum_test : public test_scaffold { arraysum_test() { @@ -239,7 +228,7 @@ append_test dummy_654sisd3(new buddy_test{}); - +// TODO: should implement a test that tries to wrongly remove pointers as well as to allocate them correctly struct buddy_fuzz_test : public test_scaffold { buddy_fuzz_test() { name = std::string(__FILE__ "seed_") + std::to_string(seed) + ":4"; @@ -430,3 +419,115 @@ struct aggregator_test : public test_scaffold { }; append_test dummy_8ijfsd658(new aggregator_test{}); + + +struct array_test : public test_scaffold { + array_test() { + name = __FILE__ ":7"; + } + + virtual int run() { + int res = 0; + gp::array store; + { + int i = 0; + for(auto& p : store) + { + p = i++; + } + for(auto it = store.rbegin(); it != store.rend(); ++it) + { + gp_config::assertion(*it == --i, "array error"); + } + for(const auto& p : store) + { + gp_config::assertion(p == i++, "array error"); + } + for(auto it = store.crbegin(); it != store.crend(); ++it) + { + gp_config::assertion(*it == --i, "array error"); + } + size_t cnt = 0; + for(const auto& p : store) + { + cnt++; + } + gp_config::assertion(cnt == store.size(), "array error"); + cnt = 0; + for(auto& p : store) + { + cnt++; + } + gp_config::assertion(cnt == store.size(), "array error"); + cnt = 0; + for(auto it = store.crbegin(); it != store.crend(); ++it) + { + cnt++; + } + gp_config::assertion(cnt == store.size(), "array error"); + cnt = 0; + for(auto it = store.rbegin(); it != store.rend(); ++it) + { + cnt++; + } + gp_config::assertion(cnt == store.size(), "array error"); + gp::rotate(store.begin(), store.begin()+1, store.end()); + gp::array rotated({1,2,3,4,5,6,7,0}); + gp_config::assertion(store == rotated, "rotate error"); + gp::rotate(store.begin(), store.end()-1, store.end()); + gp_config::assertion(store[0] == 0, "rotate error"); + + } + return res; + } +}; + +append_test dummy_ajcurgsd3(new array_test{}); + +struct indexed_array_test : public test_scaffold { + indexed_array_test() { + name = __FILE__ ":7"; + } + + virtual int run() { + int res = 0; + { + gp::indexed_array store; + size_t idx = store.push (112); + store.push (113); + store.push (114); + gp_config::assertion(store[idx] == 112, "Bad value in indexed array"); + + store.mark_for_removal(idx); + store.sweep_removed(); + for(auto& p : store) { + if(p == 112) res++; + } + + gp_config::assertion(store.size() == 2, "Bad size of indexed array"); + } + { + gp::indexed_array store; + size_t idx = store.push ("112"); + store.push ("113"); + store.push ("114"); + gp_config::assertion(store[idx] == "112", "Bad value in indexed array"); + + store.mark_for_removal(idx); + store.sweep_removed(); + for(auto& p : store) { + if(p == "112") res++; + } + + gp_config::assertion(store.size() == 2, "Bad size of indexed array"); + + { + // TODO: write a concrete implementation and test it + // gp::vfs fs; + } + } + return res; + } +}; + +append_test dummy_khxurgsd3(new indexed_array_test{}); \ No newline at end of file