Переглянути джерело

Update of the stable version

devel
Ludovic 'Archivist' Lagouardette 4 роки тому
джерело
коміт
bf90e8544b
17 змінених файлів з 1349 додано та 123 видалено
  1. +4
    -0
      .gitignore
  2. +67
    -1
      README.md
  3. +26
    -0
      include/gp/algorithm/rotate.hpp
  4. +1
    -1
      include/gp/allocator/buddy.hpp
  5. +85
    -11
      include/gp/array.hpp
  6. +24
    -0
      include/gp/buffer.hpp
  7. +113
    -36
      include/gp/function.hpp
  8. +130
    -0
      include/gp/indexed_array.hpp
  9. +116
    -21
      include/gp/iterator.hpp
  10. +351
    -0
      include/gp/math.hpp
  11. +196
    -0
      include/gp/math/fp_math.hpp
  12. +76
    -0
      include/gp/math/integer_math.hpp
  13. +0
    -0
      include/gp/math/q_math.hpp
  14. +22
    -35
      include/gp_config.hpp
  15. +6
    -3
      tests.cpp
  16. +16
    -0
      tests/allocator.hpp
  17. +116
    -15
      tests/gp_test.cpp

+ 4
- 0
.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

+ 67
- 1
README.md Переглянути файл

@ -1,3 +1,69 @@
# gplib
General Purpose library for POSIX systems
General Purpose library for Freestanding C++ environment and POSIX systems.
> Expects C++17
## Datastructures
### `buffer`
Also named "slices" in other languages, they are a combination of a pointer and a size.
### `array`
A fixed size, inplace array.
### `indexed_array`
A resizable, fragmentation resistant array, it associates elements with fixed indices. It will reuse deleted indices.
### `optional`
A Maybe monad, will not allocate for final classes or primitives.
### `variant` and `fixed_variant`
### `ring_list`
### `bloomfilter`
### `quotient_filter`
## Algorithms
## Tools
### Allocators
### Renderer
### Internal file-system
## GP Configuration
### `enum class gp_errorcodes`
This `enum` should not contain any non-zero value.
- `infinite_skipstone`: used when a linear probing reaches infinity lookup
### Generic elements
- `constexpr bool gp_config::has_exceptions`: enables or disables exceptions throwing
- `constexpr bool gp_config::has_buffer_bounds`: enables or disables bound checking
- `constexpr size_t gp_config::arc4random_strength`: determines the amount of shuffling of the arc4random PRNG
- `constexpr /* T */ gp_config::assertion`: `T` is a callable type taking a boolean predicate and a `const char*`
- `typedef /* T */ file_descriptor_t`: `T` is an integer type. No negative value should be expected
### Rendering and mathematics
- `using gp_config::rendering::default_type`: provide a numeric type for rendering and for the mathematical framework
- `constexpr default_type gp_config::rendering::epsilon`: a small value of the default type (example for float: `0.001f`)
- `#define GP_CONFIG__RENDERING__COLOR_T`: a configuration define for storing a color for rendering purposes
### Memory
- `using gp_config::memory_module::default_allocator`: a default constructible allocator type
- `constexpr bool gp_config::memory_module::is_ok`: true if the default allocator is able to allocate, false if not

+ 26
- 0
include/gp/algorithm/rotate.hpp Переглянути файл

@ -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;
}
}

+ 1
- 1
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 <type_traits>
#include <gp/algorithm/tmp_manip.hpp>
#include <gp/algorithm/modifiers.hpp>

+ 85
- 11
include/gp/array.hpp Переглянути файл

@ -5,20 +5,74 @@
namespace gp{
template<typename T, std::size_t sz>
class array{
T ary[sz];
public:
using associated_iterator = pointer_iterator<T>;
using associated_const_iterator = pointer_iterator<T>;
T ary[sz];
using associated_iterator = pointer_iterator<T, 1>;
using associated_const_iterator = const_pointer_iterator<T, 1>;
using associated_riterator = pointer_iterator<T, -1>;
using associated_const_riterator = const_pointer_iterator<T, -1>;
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<typename ...U>
array(U&& ...v)
: ary{gp::forward(v...)}
array(U&& ...values)
: ary{gp::move((T&&)values)...}
{}
array(array&& values)
{
gp::move_uninitialized<T>(
values,
*this
);
}
template<>
array<T[sz]>(T (& oth)[sz]) {
gp::move_uninitialized<T>(
gp::nameless_range(oth, oth+sz),
gp::nameless_range(begin(), end())
);
}
template<>
array<T[sz]>(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<T, 1> begin()
{
return associated_iterator(&ary[0]);
}
constexpr associated_iterator end()
constexpr pointer_iterator<T, 1> end()
{
return associated_iterator(&ary[sz]);
}
constexpr associated_const_iterator cbegin() const
constexpr const_pointer_iterator<T, 1> cbegin() const
{
return associated_const_iterator(&ary[0]);
}
constexpr const_pointer_iterator<T, 1> cend() const
{
return associated_const_iterator(&ary[sz]);
}
constexpr pointer_iterator<T, -1> rbegin()
{
return associated_riterator(&ary[sz-1]);
}
constexpr pointer_iterator<T, -1> rend()
{
return associated_riterator(ary-1);
}
constexpr const_pointer_iterator<T, -1> crbegin() const
{
return ary;
return f">associated_const_riterator(&ary[sz-1]);
}
constexpr associated_const_iterator cend() const
constexpr const_pointer_iterator<T, -1> crend() const
{
return ary+sz;
return f">associated_const_riterator(ary-1);
}
constexpr bool operator==(const array& oth) const

+ 24
- 0
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};
}
}
};
}

+ 113
- 36
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<ret(args...)>{
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<typename fn>
class callable : virtual_callable{
fn internal_representation;
class callable k">final : public virtual_callable{
k">typename gp::remove_reference<fn>::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*)o">&self)->~virtual_callable();
((virtual_callable*)n">self.inplace)->~virtual_callable();
}
else
{
delete self.functor;
}
}
if constexpr (sizeof(callable<T>) <= sizeof(self))
if(!(t.state & ACTIVE))
{
k">new((void*)&self) callable(t);
n">state = ACTIVE | SOO;
n">state = INACTIVE;
k">return;
}
else
{
self = new callable(t);
state = ACTIVE | NO_SOO;
if constexpr (!std::is_same_v<T, function<ret(args...)>>) {
if constexpr (sizeof(callable<T>) <= sizeof(self))
{
new((void*)self.inplace) callable<T>(t);
state = (state_t)(ACTIVE | SOO);
}
else
{
self.functor = new callable<T>(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 <typename T>
function(T t)
function()
{
if constexpr (sizeof(callable<T>) <= sizeof(self))
{
new((void*)&self) callable(t);
state = ACTIVE | SOO;
}
else
{
self = new callable(t);
state = ACTIVE | NO_SOO;
state = INACTIVE;
}
template<typename T>
function<>(T& t)
{
if constexpr (!std::is_same_v<T, function<ret(args...)>>) {
if constexpr (sizeof(callable<T>) <= sizeof(self))
{
new((void*)self.inplace) callable<T>(t);
state = (state_t)(ACTIVE | SOO);
}
else
{
self.functor = new callable<T>(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 <typename T>
function(T& t)
function(T&& t)
{
if constexpr (sizeof(callable<T>) <= 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<T, function<ret(args...)>>) {
if constexpr (sizeof(callable<T>) <= sizeof(self))
{
new((void*)self.inplace) callable<T>(gp::move(t));
state = (state_t)(ACTIVE | SOO);
}
else
{
self.functor = new callable<T>(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 (*p">(self.functor))(arg_list...);
return (*self.functor)(arg_list...);
}
}

+ 130
- 0
include/gp/indexed_array.hpp Переглянути файл

@ -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]];
}
};
}

+ 116
- 21
include/gp/iterator.hpp Переглянути файл

@ -8,7 +8,7 @@ enum class iterator_type_t{
lazy_iterator
};
template<typename T>
template<typename Tp">, int sign = 1>
struct pointer_iterator final
{
T* data;
@ -24,76 +24,171 @@ struct pointer_iterator final
: data{ptr}
{}
constexpr k">operator T&()
constexpr n">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<std::intptr_t>(data) <= reinterpret_cast<std::intptr_t>(oth.data);
}
constexpr bool operator<=(const pointer_iterator oth)
{
return before_or_equal(oth);
}
};
template<typename T, int sign = 1>
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<std::intptr_t>(data) <= reinterpret_cast<std::intptr_t>(oth.data);
}
constexpr bool operator<=(const pointer_iterator& oth)
constexpr bool operator<=(const const_pointer_iterator oth)
{
return before_or_equal(oth);
}

+ 351
- 0
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<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");

+ 196
- 0
include/gp/math/fp_math.hpp Переглянути файл

@ -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);}
}

+ 76
- 0
include/gp/math/integer_math.hpp Переглянути файл

@ -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
include/gp/math/q_math.hpp Переглянути файл


+ 22
- 35
include/gp_config.hpp Переглянути файл

@ -4,46 +4,33 @@
#include <cstdlib>
#include <type_traits>
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<memory_mode_t T = memory_mode_t::other>
constexpr void*(*memory_allocator)(std::size_t)=nullptr;
template<memory_mode_t T = memory_mode_t::other>
constexpr void(*memory_deallocator)(void*)=nullptr;
// C Standard library memory usage
template<>
constexpr void*(*memory_allocator<memory_mode_t::clib>)(std::size_t) = malloc;
template<>
constexpr void(*memory_deallocator<memory_mode_t::clib>)(void*) = free;
#ifdef GP_TESTS
class static_mapper;
#else
namespace gp {
class c_allocator;
}
#endif
// Buffer memory usage only
template<>
constexpr void*(*memory_allocator<memory_mode_t::buffer>)(std::size_t) = nullptr;
template<>
constexpr void(*memory_deallocator<memory_mode_t::buffer>)(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<memory_mode_t::arena_buffer>)(std::size_t) = nullptr;
template<>
constexpr void(*memory_deallocator<memory_mode_t::arena_buffer>)(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<memory_mode> != nullptr )
&& ( memory_deallocator<memory_mode> != nullptr );
constexpr bool is_ok = true;
}
typedef uint32_t file_descriptor_t;
constexpr bool has_exceptions = true;
constexpr bool has_buffer_bounds = true;

+ 6
- 3
tests.cpp Переглянути файл

@ -6,6 +6,9 @@
#include "quotient_filter.cpp"
#include <iostream>
alignas(2048) gp::array<char, 4096> 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;
c1">//try{
k">try{
value = test->run();
if(value)
{
std::cout << std::dec << test->name << " failed with "<< value << std::endl;
}
cm">/*} catch (gp::runtime_error err) {
p">} 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 "<<runned<<" tests with "<<failed<<" failures" << std::endl;

+ 16
- 0
tests/allocator.hpp Переглянути файл

@ -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);
}
};

+ 116
- 15
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 <thread>
#include <chrono>
@ -28,20 +31,6 @@
constexpr bool time_fuzzes = true;
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);
}
};
alignas(2048) gp::array<char, 4096> 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<int, 8> 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<int, 8> 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<int, 8> 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<std::string, 8> 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{});

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