From bf90e8544b2aeb09bd3b33e5df9ad10a3466f274 Mon Sep 17 00:00:00 2001 From: Ludovic 'Archivist' Lagouardette Date: Fri, 5 Jun 2020 06:38:22 +0200 Subject: [PATCH 1/5] Update of the stable version --- .gitignore | 4 + README.md | 68 +++++- include/gp/algorithm/rotate.hpp | 26 +++ include/gp/allocator/buddy.hpp | 2 +- include/gp/array.hpp | 96 ++++++++- include/gp/buffer.hpp | 24 +++ include/gp/function.hpp | 149 +++++++++---- include/gp/indexed_array.hpp | 130 ++++++++++++ include/gp/iterator.hpp | 137 ++++++++++-- include/gp/math.hpp | 351 +++++++++++++++++++++++++++++++ include/gp/math/fp_math.hpp | 196 +++++++++++++++++ include/gp/math/integer_math.hpp | 76 +++++++ include/gp/math/q_math.hpp | 0 include/gp_config.hpp | 57 ++--- tests.cpp | 9 +- tests/allocator.hpp | 16 ++ tests/gp_test.cpp | 131 ++++++++++-- 17 files changed, 1349 insertions(+), 123 deletions(-) create mode 100644 include/gp/algorithm/rotate.hpp create mode 100644 include/gp/indexed_array.hpp create mode 100644 include/gp/math.hpp create mode 100644 include/gp/math/fp_math.hpp create mode 100644 include/gp/math/integer_math.hpp create mode 100644 include/gp/math/q_math.hpp create mode 100644 tests/allocator.hpp 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 From 25f2f4769beefd4e7a5fa20a7e575eb0ca6d8abb Mon Sep 17 00:00:00 2001 From: Ludovic 'Archivist' Lagouardette Date: Wed, 9 Sep 2020 00:07:55 +0200 Subject: [PATCH 2/5] added the pair type (mostly std conformant) --- .vscode/settings.json | 6 ++++ Makefile | 2 +- include/gp/pair.hpp | 72 +++++++++++++++++++++++++++++++++++++++++++ tests.cpp | 1 + tests/pair_test.cpp | 37 ++++++++++++++++++++++ 5 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json create mode 100644 include/gp/pair.hpp create mode 100644 tests/pair_test.cpp diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6bc7f76 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "clang.cflags": [ + "-std=c++17", + "-I${workspaceRoot}/include" + ] +} \ No newline at end of file diff --git a/Makefile b/Makefile index c112d61..55a6ddb 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CXX= clang++-8 +CXX= clang++-10 CXXFLAGS= --std=c++17 -O0 -pthread -DFUZZ_STRENGTH=500000 \ -Wno-unknown-attributes \ -g -fprofile-instr-generate -fcoverage-mapping diff --git a/include/gp/pair.hpp b/include/gp/pair.hpp new file mode 100644 index 0000000..397cabb --- /dev/null +++ b/include/gp/pair.hpp @@ -0,0 +1,72 @@ +#pragma once +#include "gp/algorithm/move.hpp" + +namespace gp{ + template + struct pair{ + T1 first; + T2 second; + + pair() : first(), second() {} + + pair(const T1& a, const T2& b) : first(a), second(b) {} + + pair(pair&& v) + : first(gp::move(v.first)) + , second(gp::move(v.second)) + {} + + template + pair(U1&& a, U2&& b) + : first(gp::forward(a)) + , second(gp::forward(b)) + {} + + template + pair(pair&& v) + : first(gp::move(v.first)) + , second(gp::move(v.second)) + {} + + pair& operator=(pair&& v) + { + first = gp::move(v.first); + second = gp::move(v.second); + return *this; + } + + bool operator==(const pair& rhs) { + return first == rhs.first and second == rhs.second; + } + + bool operator!=(const pair& rhs) { + return first != rhs.first or second != rhs.second; + } + + bool operator<=(const pair& rhs) { + if(first > rhs.first) { + return false; + } else if(first == rhs.first) { + return second <= rhs.second; + } + return true; + } + + bool operator>=(const pair& rhs) { + if(first < rhs.first) { + return false; + } else if(first == rhs.first) { + return second >= rhs.second; + } + return true; + } + + bool operator<(const pair& rhs) { + return !(*this >= rhs); + } + + bool operator>(const pair& rhs) { + return !(*this <= rhs); + } + }; +} \ No newline at end of file diff --git a/tests.cpp b/tests.cpp index 70d7c82..5d167d9 100644 --- a/tests.cpp +++ b/tests.cpp @@ -4,6 +4,7 @@ #include "gp_test.cpp" #include "bloomfilter.cpp" #include "quotient_filter.cpp" +#include "pair_test.cpp" #include alignas(2048) gp::array static_mapper::store; diff --git a/tests/pair_test.cpp b/tests/pair_test.cpp new file mode 100644 index 0000000..ac3b139 --- /dev/null +++ b/tests/pair_test.cpp @@ -0,0 +1,37 @@ +#include "test_scaffold.h" +#include +#include +#include "gp/pair.hpp" + +typedef std::mt19937_64 cheap_rand; + +struct pair_test : public test_scaffold { + uint32_t seed; + + pair_test() { + seed = std::random_device{}(); + name = __FILE__ ":1_seed"; + name += std::to_string(seed); + } + + virtual int run() { + + cheap_rand setter(seed); + cheap_rand getter(seed); + + gp::pair v{0, "zero"}; + bool result = true; + + for(int i = 0 ; i < 100; i++) + { + auto a = setter(); + auto b = setter(); + v = gp::pair(a, std::to_string(a)); + result = gp::pair(b, std::to_string(b)) == v ? result : false; + } + + return !result; + } +}; + +append_test dummy_rsly21r43(new pair_test{}); \ No newline at end of file From 7bbdf7b2fc5dafe19b6c30ac70289cd203cff6cd Mon Sep 17 00:00:00 2001 From: Ludovic 'Archivist' Lagouardette Date: Wed, 9 Sep 2020 00:21:57 +0200 Subject: [PATCH 3/5] poorly written test fixed --- tests/pair_test.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/pair_test.cpp b/tests/pair_test.cpp index ac3b139..5548488 100644 --- a/tests/pair_test.cpp +++ b/tests/pair_test.cpp @@ -17,7 +17,6 @@ struct pair_test : public test_scaffold { virtual int run() { cheap_rand setter(seed); - cheap_rand getter(seed); gp::pair v{0, "zero"}; bool result = true; @@ -25,9 +24,8 @@ struct pair_test : public test_scaffold { for(int i = 0 ; i < 100; i++) { auto a = setter(); - auto b = setter(); v = gp::pair(a, std::to_string(a)); - result = gp::pair(b, std::to_string(b)) == v ? result : false; + result = gp::pair(a, std::to_string(a)) == v ? result : false; } return !result; From 4b1aa7da73779487009d4a1cc94323e38078cd33 Mon Sep 17 00:00:00 2001 From: Ludovic 'Archivist' Lagouardette Date: Wed, 9 Sep 2020 01:15:55 +0200 Subject: [PATCH 4/5] Fixed some interface problems as well as some bugs --- include/gp/algorithm/tmp_manip.hpp | 4 ++-- include/gp/allocator/arena.hpp | 14 ++++++++------ include/gp/ring_list.hpp | 13 +++++++++++-- tests/gp_test.cpp | 30 ++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/include/gp/algorithm/tmp_manip.hpp b/include/gp/algorithm/tmp_manip.hpp index 80af38f..058c8e8 100644 --- a/include/gp/algorithm/tmp_manip.hpp +++ b/include/gp/algorithm/tmp_manip.hpp @@ -202,7 +202,7 @@ namespace gp{ typedef std::true_type yes; typedef std::false_type no; - template struct SFINAE{}; + template struct SFINAE{}; template static yes test(SFINAE*); @@ -219,7 +219,7 @@ namespace gp{ typedef std::true_type yes; typedef std::false_type no; - template struct SFINAE{}; + template struct SFINAE{}; template static yes test(SFINAE*); diff --git a/include/gp/allocator/arena.hpp b/include/gp/allocator/arena.hpp index 6fd38cf..118a2bd 100644 --- a/include/gp/allocator/arena.hpp +++ b/include/gp/allocator/arena.hpp @@ -7,7 +7,7 @@ namespace gp{ - template + template class arena{ page_allocator allocator; gp::buffer data; @@ -20,18 +20,20 @@ namespace gp{ ,data(gp::buffer(nullptr,nullptr)) {} - template::value,int>::type> arena(size_t sz) :last(0) ,count(0) ,data(nullptr,nullptr) { - if(sz!=0) + if constexpr (gp::has_allocator_interface::value) { - auto v=allocator.allocate(sz); - if(v!=nullptr) + if(sz!=0) { - data=gp::buffer(reinterpret_cast(v),reinterpret_cast(v)+sz); + auto v=allocator.allocate(sz); + if(v!=nullptr) + { + data=gp::buffer(reinterpret_cast(v),reinterpret_cast(v)+sz); + } } } } diff --git a/include/gp/ring_list.hpp b/include/gp/ring_list.hpp index 37a98e8..62b24b6 100644 --- a/include/gp/ring_list.hpp +++ b/include/gp/ring_list.hpp @@ -95,13 +95,22 @@ namespace gp { , alloc{_alloc} {} + ring_list(allocator& _alloc) + : any_node{nullptr} + , sz{0} + , alloc{_alloc} + {} + template bool insert(Args&&... elem) { allocator& used_allocator = alloc; - void* mem = used_allocator.allocate(sizeof(V)); + void* mem; + [[unlikely]] if( + nullptr == (mem = used_allocator.allocate(sizeof(V))) + ) return false; T* p = new(mem) V(elem...); node* to_insert = nullptr; - if( + [[unlikely]] if( nullptr == (to_insert = reinterpret_cast(used_allocator.allocate(sizeof(node)))) ) return false; to_insert = new(to_insert) node(p); diff --git a/tests/gp_test.cpp b/tests/gp_test.cpp index 8b15735..c52824f 100644 --- a/tests/gp_test.cpp +++ b/tests/gp_test.cpp @@ -3,6 +3,7 @@ #include "gp/array.hpp" #include "gp/indexed_array.hpp" #include "gp/allocator/aggregator.hpp" +#include "gp/allocator/arena.hpp" #include "gp/allocator/buddy.hpp" #include "gp/allocator/dummy.hpp" #include "gp/algorithm/repeat.hpp" @@ -414,6 +415,35 @@ struct aggregator_test : public test_scaffold { } auto duration = std::chrono::steady_clock::now() - start; } + void* a = allocator.allocate(8); + gp_config::assertion(allocator.try_reallocate(a, 16) == false, "could reallocate? was it implemented?"); + gp_config::assertion(allocator.deallocate(nullptr) == false, "error, could free an invalid pointer"); + allocator.deallocate(a); + { + gp::ring_list list{allocator}; + list.insert(8); + list.insert(16); + list.insert(32); + } + { + gp::array work_array; + gp::arena<> alloc_work(work_array.begin().data, work_array.size()); + gp::ring_list, false> list{alloc_work}; + gp_config::assertion(list.insert(8) == true, "could allocate in list with good enough allocator"); + gp_config::assertion(list.insert(8) == true, "could allocate in list with good enough allocator"); + gp_config::assertion(list.insert(8) == true, "could allocate in list with good enough allocator"); + } + { + gp::array once_array; + gp::arena<> alloc_once(once_array.begin().data, once_array.size()); + gp::ring_list, false> list{alloc_once}; + gp_config::assertion(list.insert(8) == false, "could allocate in list with insufficient allocator"); + } + { + gp::arena<> alloc_none(nullptr, 0); + gp::ring_list, false> list{alloc_none}; + gp_config::assertion(list.insert(8) == false, "could allocate in list with fake allocator"); + } return res; } }; From cb2dfecc60581f96e8e720e4bd2d2b6d25173eff Mon Sep 17 00:00:00 2001 From: Ludovic 'Archivist' Lagouardette Date: Wed, 9 Sep 2020 11:08:02 +0200 Subject: [PATCH 5/5] Fixed some previously unnoticed bugs --- include/gp/algorithm/move.hpp | 9 +-- include/gp/array.hpp | 2 +- include/gp/buffer.hpp | 2 +- include/gp/quotient_filter.hpp | 1 + tests.cpp | 6 +- tests/gp_test.cpp | 102 ++++++++++++++++++++++++++++++++- tests/quotient_filter.cpp | 68 +++++++++++++++++++++- 7 files changed, 178 insertions(+), 12 deletions(-) diff --git a/include/gp/algorithm/move.hpp b/include/gp/algorithm/move.hpp index c50fde4..1184511 100644 --- a/include/gp/algorithm/move.hpp +++ b/include/gp/algorithm/move.hpp @@ -58,11 +58,12 @@ namespace gp{ return nameless_range{out, dest.end()}; } - template - nameless_range move_uninitialized(range_in src, range_out dest) + template + nameless_range::type::associated_iterator> move_uninitialized(range_in&& src, range_out&& dest) { + using T = typename gp::remove_reference::type; if(src.size()>dest.size()) - return nameless_range(dest.begin(), dest.end()); + return nameless_range::type::associated_iterator>(dest.begin(), dest.end()); auto in = src.begin(); auto in_close = src.end(); auto out = dest.begin(); @@ -70,6 +71,6 @@ namespace gp{ { new(&*(out++)) T{gp::move(*(in++))}; } - return nameless_range{out, dest.end()}; + return nameless_range::type::associated_iterator>{out, dest.end()}; } } \ No newline at end of file diff --git a/include/gp/array.hpp b/include/gp/array.hpp index ce09add..68e84ba 100644 --- a/include/gp/array.hpp +++ b/include/gp/array.hpp @@ -33,7 +33,7 @@ namespace gp{ array(array&& values) { - gp::move_uninitialized( + gp::move_uninitialized( values, *this ); diff --git a/include/gp/buffer.hpp b/include/gp/buffer.hpp index 3ea66f9..44143b2 100644 --- a/include/gp/buffer.hpp +++ b/include/gp/buffer.hpp @@ -81,7 +81,7 @@ namespace gp{ } else { - if(size()*sizeof(T)/sizeof(U)) + if((size()*sizeof(T))%sizeof(U) == 0) { return buffer(reinterpret_cast(&*begin_elem), size()*sizeof(T)/sizeof(U)); } diff --git a/include/gp/quotient_filter.hpp b/include/gp/quotient_filter.hpp index 9bb35b8..14040ba 100644 --- a/include/gp/quotient_filter.hpp +++ b/include/gp/quotient_filter.hpp @@ -193,6 +193,7 @@ namespace gp { if(slot.r == r) { slot.is_deleted = true; + slot.is_occupied = false; } } skip.next(); diff --git a/tests.cpp b/tests.cpp index 5d167d9..4e1e63e 100644 --- a/tests.cpp +++ b/tests.cpp @@ -18,13 +18,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) { @@ -33,7 +33,7 @@ int main() } catch (...) { std::cout << test->name << " failed with an exception" << std::endl; value = -1; - } + }*/ failed += (value != 0); } std::cout << std::dec << "Runned "< #include @@ -553,11 +554,108 @@ struct indexed_array_test : public test_scaffold { { // 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 +append_test dummy_khxurgsd3(new indexed_array_test{}); + + + +struct move_uninitialized_test : public test_scaffold { + move_uninitialized_test() { + name = __FILE__ ":8"; + } + + struct tester { + size_t* const incremented; + + tester(size_t* ptr) + : incremented(ptr) + {} + + tester(tester&& oth) + : incremented(oth.incremented) + { + ++*incremented; + } + }; + + virtual int run() { + int res = 0; + { + size_t counter; + using src_t = gp::array; + src_t *source = reinterpret_cast(malloc(sizeof(src_t))); + gp::array buffer; + for(auto& a : *source) { + new(&a) tester(&counter); + } + gp::move_uninitialized(*source, buffer.as_buffer().cast()); + free(source); + } + return res; + } +}; + +append_test dummy_hkfyr5f5(new move_uninitialized_test{}); + + + +struct clamp_test : public test_scaffold { + clamp_test() { + name = __FILE__ ":9"; + } + + virtual int run() { + int res = 0; + { + res += gp::clamp(0.0, -1.0, 1.0); + res += gp::clamp(-1.0, 1.0, 0.0); + res += gp::max(-1, -2, 0, -3); + } + return res; + } +}; + +append_test dummy_gsdh25f5(new clamp_test{}); + +struct buffer_test : public test_scaffold { + buffer_test() { + name = __FILE__ ":10"; + } + + virtual int run() { + int res = 0; + { + gp::array data; + gp::array data_e; + gp::buffer handle = data.as_buffer(); + handle[12] = '&'; + gp_config::assertion(*(handle.begin()+12) == '&', "Could not assign to the buffer"); + res += 1; + try { + handle[24] = 16; + res += 1; + handle[-1] = 16; + res += 1; + handle[1024] = 16; + } catch (...) { + res -= 1; + } + res += 1; + try { + auto cast = handle.cast>(); + } catch (...) { + res -= 1; + } + auto cast = handle.template cast>().template cast>(); + gp_config::assertion(false == (data == data_e), "Different arrays should return false here"); + } + return res; + } +}; + +append_test dummy_gs87ytf5f5(new buffer_test{}); \ No newline at end of file diff --git a/tests/quotient_filter.cpp b/tests/quotient_filter.cpp index d816b13..e90a4c0 100644 --- a/tests/quotient_filter.cpp +++ b/tests/quotient_filter.cpp @@ -124,4 +124,70 @@ struct qfilter3_test : public test_scaffold { } }; -append_test dummy_kjdflu3(new qfilter3_test{}); \ No newline at end of file +append_test dummy_kjdflu3(new qfilter3_test{}); + +struct qfilter4_test : public test_scaffold { + + qfilter4_test() { + } + + virtual int run() { + gp::quotient_filter<> test_filter; + + for(int a = 0 ; a < 10000; a++) + { + test_filter.set_hash(a); + } + + for(int a = 0 ; a < 10000; a++) + { + test_filter.remove_hash(a); + } + + for(int a = 0 ; a < 10000; a++) + { + gp_config::assertion(!test_filter.test_hash(a), "everything should have been removed"); + } + + for(int a = 0 ; a < 10000; a++) + { + test_filter.set_hash(a); + } + + for(int a = 0 ; a < 10000; a++) + { + gp_config::assertion(test_filter.test_hash(a), "everything should have been set"); + } + + return 0; + } +}; + +append_test dummy_kj54ghu3(new qfilter4_test{}); + +struct qfilter5_test : public test_scaffold { + + qfilter5_test() { + } + + virtual int run() { + gp::quotient_filter test_filter; + + for(int a = 0 ; a < 65536; a++) + { + test_filter.set_hash(a); + } + + int res = 1; + + try { + test_filter.set_hash(123456); + } catch(gp::runtime_error e) { + res = 0; + } + + return res; + } +}; + +append_test dummy_k65421u3(new qfilter5_test{}); \ No newline at end of file