@ -0,0 +1,20 @@ | |||
#pragma once | |||
#include <stddef.h> | |||
namespace gp{ | |||
template <typename range, typename F> | |||
void indexed_foreach(range n, F f) { | |||
for(size_t idx = 0; idx < n.size(); ++idx) | |||
{ | |||
f(idx, n[idx]); | |||
} | |||
} | |||
template <typename range, typename F> | |||
void foreach(range n, F f) { | |||
for(auto& elem : n) | |||
{ | |||
f(elem); | |||
} | |||
} | |||
} |
@ -0,0 +1,26 @@ | |||
#pragma once | |||
#include "gp_config.hpp" | |||
#include "gp/algorithm/move.hpp" | |||
namespace gp{ | |||
template<typename T> | |||
T identity(T v){return v;} | |||
template<typename T> | |||
T& identity(T& v){return v;} | |||
template<typename it, typename transform> | |||
auto&& min_of(it beg, it end, transform fn = identity) { | |||
gp_config::assertion(beg == end, "min_of provided with empty range"); | |||
auto fn_v = fn(*beg); | |||
++beg; | |||
while(beg != end) { | |||
auto n_fn_v = fn(*beg); | |||
if(n_fn_v < fn_v) { | |||
fn_v = n_fn_v; | |||
} | |||
++beg; | |||
} | |||
return gp::move(fn_v); | |||
} | |||
} |
@ -0,0 +1,26 @@ | |||
#pragma once | |||
#include "gp/algorithm/move.hpp" | |||
namespace gp { | |||
template<typename iterator> | |||
iterator rotate(iterator first, iterator new_first, iterator last) | |||
{ | |||
if(first == new_first) return last; | |||
if(new_first == last) return first; | |||
iterator in = new_first; | |||
iterator out = first; | |||
iterator mv = first; | |||
while(in != last) { | |||
if(out == mv) mv = in; | |||
gp::swap((*out++), (*in++)); | |||
} | |||
// rotate the remaining sequence into place | |||
(rotate)(out, mv, last); | |||
return out; | |||
} | |||
} |
@ -0,0 +1,130 @@ | |||
#pragma once | |||
#include <stddef.h> | |||
#include "gp_config.hpp" | |||
#include "gp/algorithm/move.hpp" | |||
#include "gp/iterator.hpp" | |||
namespace gp{ | |||
template<typename T, size_t _capacity> | |||
class indexed_array{ | |||
size_t data_top = 0; | |||
size_t available_indexes_top = 0; | |||
size_t remove_top = 0; | |||
T data_table[_capacity]; | |||
size_t available_indexes[_capacity]; | |||
size_t translation_table[_capacity]; | |||
size_t reverse_translation_table[_capacity]; | |||
size_t remove_table[_capacity]; | |||
public: | |||
indexed_array() {} | |||
size_t push(T&& value) { | |||
size_t index; | |||
gp_config::assertion(data_top+1 != _capacity, "Indexed array capacity exceeded"); | |||
if(available_indexes_top) { | |||
available_indexes_top--; | |||
index = available_indexes[available_indexes_top]; | |||
} else { | |||
index = data_top; | |||
} | |||
new(&data_table[data_top]) T(gp::move(value)); | |||
translation_table[index] = data_top; | |||
reverse_translation_table[data_top] = index; | |||
++data_top; | |||
return index; | |||
} | |||
void pop(size_t idx) { | |||
size_t v_idx = translation_table[idx]; | |||
available_indexes[available_indexes_top] = idx; | |||
++available_indexes_top; | |||
translation_table[idx] = -1; | |||
--data_top; | |||
if(v_idx < data_top) { | |||
size_t u_idx = reverse_translation_table[data_top]; | |||
data_table[v_idx] = gp::move(data_table[data_top]); | |||
::operator delete(&data_table[data_top], &data_table[data_top]); | |||
data_table[data_top].~T(); | |||
translation_table[u_idx] = v_idx; | |||
reverse_translation_table[v_idx] = u_idx; | |||
} | |||
} | |||
void reset() { | |||
auto it = data_table; | |||
auto end = data_table+data_top; | |||
while(it != end) { | |||
::operator delete(it, it); | |||
++it; | |||
} | |||
data_top = 0; | |||
available_indexes_top = 0; | |||
remove_top = 0; | |||
} | |||
void mark_internal_for_removal(size_t i_idx) { | |||
remove_table[remove_top] = reverse_translation_table[i_idx]; | |||
++remove_top; | |||
} | |||
void mark_for_removal(size_t idx) { | |||
remove_table[remove_top] = idx; | |||
++remove_top; | |||
} | |||
void sweep_removed() { | |||
auto it = remove_table; | |||
auto end = remove_table+remove_top; | |||
while(it != end) { | |||
pop(*it); | |||
++it; | |||
} | |||
} | |||
bool has(size_t idx) { | |||
if(idx > data_top) return false; | |||
if(translation_table[idx] == -1) return false; | |||
return true; | |||
} | |||
pointer_iterator<T> begin() | |||
{ | |||
return data_table; | |||
} | |||
pointer_iterator<T> end() | |||
{ | |||
return data_table+data_top; | |||
} | |||
const_pointer_iterator<T> cbegin() | |||
{ | |||
return data_table; | |||
} | |||
const_pointer_iterator<T> cend() | |||
{ | |||
return data_table+data_top; | |||
} | |||
size_t size() { | |||
return data_top; | |||
} | |||
size_t capacity() { | |||
return _capacity; | |||
} | |||
T& operator[](size_t idx) { | |||
gp_config::assertion(idx < data_top, "Bad indexed array access"); | |||
return data_table[translation_table[idx]]; | |||
} | |||
}; | |||
} |
@ -0,0 +1,167 @@ | |||
#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 | |||
namespace gp { | |||
template<typename T = gp_config::rendering::default_type> | |||
struct vec2_g { | |||
T x; | |||
T 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 oth) { | |||
return {x+oth.x, y+oth.y}; | |||
} | |||
vec2_g normalize() { | |||
T ilen = fast_isqrt(x*x+y*y); | |||
return {x*ilen, y*ilen}; | |||
} | |||
}; | |||
template<typename T = gp_config::rendering::default_type> | |||
struct vec3_g { | |||
T x; | |||
T y; | |||
T 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 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}; | |||
} | |||
}; | |||
template<typename T = gp_config::rendering::default_type> | |||
struct vec4_g { | |||
T x; | |||
T y; | |||
T z; | |||
T 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 oth) { | |||
return {x+oth.x, y+oth.y, z+oth.z, w+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}; | |||
} | |||
}; | |||
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; | |||
} | |||
} |
@ -0,0 +1,196 @@ | |||
#pragma once | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
#include <limits> | |||
#include "gp/algorithm/repeat.hpp" | |||
namespace gp{ | |||
template<typename T> | |||
constexpr T pi; | |||
template<> | |||
constexpr float pi<float> = 3.1415926535897932384626433832795028841971693993751058209749445923078164062; | |||
template<> | |||
constexpr double pi<double> = 3.1415926535897932384626433832795028841971693993751058209749445923078164062; | |||
template<typename T> | |||
T abs(T); | |||
template<> | |||
float abs<float>(float value) { | |||
static_assert(sizeof(float) == 4, "bad float size"); | |||
union { | |||
float fp; | |||
uint32_t ab; | |||
} p; | |||
p.fp = value; | |||
p.ab &= 0x7fFFffFF; | |||
return p.fp; | |||
} | |||
template<> | |||
double abs<double>(double value) { | |||
static_assert(sizeof(double) == 8, "bad double size"); | |||
union { | |||
double fp; | |||
uint64_t ab; | |||
} p; | |||
p.fp = value; | |||
p.ab &= 0x7fFFffFFffFFffFF; | |||
return p.fp; | |||
} | |||
template<typename T> | |||
T floor(T); | |||
template<> | |||
float floor<float>(float value) { | |||
static_assert(sizeof(float) == 4, "bad float size"); | |||
if( | |||
value >= std::numeric_limits<int32_t>::max() | |||
|| value <= std::numeric_limits<int32_t>::min() | |||
|| value != value | |||
) { | |||
return value; | |||
} | |||
int32_t ret = value; | |||
float ret_d = ret; | |||
if(value == ret_d || value >= 0) { | |||
return ret; | |||
} else { | |||
return ret-1; | |||
} | |||
} | |||
template<> | |||
double floor<double>(double value) { | |||
static_assert(sizeof(double) == 8, "bad double size"); | |||
if( | |||
value >= std::numeric_limits<int64_t>::max() | |||
|| value <= std::numeric_limits<int64_t>::min() | |||
|| value != value | |||
) { | |||
return value; | |||
} | |||
int64_t ret = value; | |||
double ret_d = ret; | |||
if(value == ret_d || value >= 0) { | |||
return ret; | |||
} else { | |||
return ret-1; | |||
} | |||
} | |||
template<typename T> | |||
T sign(T); | |||
template<> | |||
float sign<float>(float value) { | |||
static_assert(sizeof(float) == 4, "bad float size"); | |||
if(!value) return 0; | |||
union { | |||
float fp; | |||
uint32_t ab; | |||
} p; | |||
p.fp = value; | |||
p.ab &= 0x7fFFffFF; | |||
return value/p.fp; | |||
} | |||
template<> | |||
double sign<double>(double value) { | |||
static_assert(sizeof(double) == 8, "bad double size"); | |||
if(!value) return 0; | |||
union { | |||
double fp; | |||
uint64_t ab; | |||
} p; | |||
p.fp = value; | |||
p.ab &= 0x7fFFffFFffFFffFF; | |||
return value/p.fp; | |||
} | |||
template<size_t steps, typename T, size_t accuracy = 1000000> | |||
T sin_taylor(T value) { | |||
const T acc = T{1}/T{accuracy}; | |||
T B = value; | |||
T C = 1; | |||
T ret = B/C; | |||
for(size_t i = 1; (i < steps) && (abs<>(B/C) > acc); ++i) { | |||
B *= -1*value*value; | |||
C *= 2*i*(2*i+1); | |||
ret += B/C; | |||
} | |||
return ret; | |||
} | |||
float sin(float v) { | |||
v += pi<float>; | |||
v = v - 2*pi<float>*floor(v/(2*pi<float>)); | |||
v -= pi<float>; | |||
float s = sign(v); | |||
v *= s; | |||
return sin_taylor<10>(v)*s; | |||
} | |||
double sin(double v) { | |||
v += pi<double>; | |||
v = v - 2*pi<double>*floor(v/(2*pi<double>)); | |||
v -= pi<double>; | |||
float s = sign(v); | |||
v *= s; | |||
return sin_taylor<10>(v)*s; | |||
} | |||
// TODO: replace with an actual implementation | |||
float cos(float v) { | |||
return sin(v+pi<float>/2); | |||
} | |||
// TODO: replace with an actual implementation | |||
double cos(double v) { | |||
return sin(v+pi<float>/2); | |||
} | |||
template<size_t cycles = 5> | |||
float isqrt(float v) { | |||
int32_t i; | |||
float x2, y; | |||
constexpr float threehalfs = 1.5F; | |||
x2 = v * 0.5F; | |||
y = v; | |||
i = * ( int32_t * ) &y; | |||
i = 0x5F375A86 - ( i >> 1 ); | |||
y = * ( float * ) &i; | |||
gp::repeat(cycles, [&](){ | |||
y = y * ( threehalfs - ( x2 * y * y ) ); | |||
}); | |||
return y; | |||
} | |||
template<size_t cycles = 5> | |||
double isqrt(double v) { | |||
int64_t i; | |||
double x2, y; | |||
constexpr double threehalfs = 1.5F; | |||
x2 = v * 0.5F; | |||
y = v; | |||
i = * ( int64_t * ) &y; | |||
i = 0x5FE6EB50C7B537A9 - ( i >> 1 ); | |||
y = * ( double * ) &i; | |||
gp::repeat(cycles, [&](){ | |||
y = y * ( threehalfs - ( x2 * y * y ) ); | |||
}); | |||
return y; | |||
} | |||
float fast_isqrt(float v) {return isqrt<1>(v);} | |||
double fast_isqrt(double v) {return isqrt<1>(v);} | |||
} |
@ -0,0 +1,76 @@ | |||
#pragma once | |||
#include "gp_config.hpp" | |||
#include "gp/math.hpp" | |||
#include "gp/function.hpp" | |||
#include "gp/algorithm/min_of.hpp" | |||
#include "gp/indexed_array.hpp" | |||
using vec2 = gp::vec2_g<>; | |||
using vec3 = gp::vec3_g<>; | |||
using vec4 = gp::vec4_g<>; | |||
struct camera{ | |||
vec3 position; | |||
vec3 normal; | |||
}; | |||
using index_t = size_t; | |||
using distance_t = gp_config::rendering::default_type; | |||
using color_t = GP_CONFIG__RENDERING__COLOR_T; | |||
struct render_point{ | |||
distance_t distance; | |||
index_t material; | |||
bool operator<(const render_point& rhs) { | |||
return distance < rhs.distance; | |||
} | |||
}; | |||
using sdf_t = gp::function<render_point(vec3)>; | |||
using material_t = gp::function<color_t(vec3)>; | |||
class renderer { | |||
using g_t = gp_config::rendering::default_type; | |||
constexpr static auto epsilon = gp_config::rendering::epsilon; | |||
public: | |||
gp::indexed_array<sdf_t, 4096> scene_elements; | |||
gp::indexed_array<material_t, 4096> materials; | |||
material_t sky_box = [](vec3) -> color_t { return vec4{0,0,0,0};}; | |||
vec2 _resolution{128,64}; | |||
camera _camera{{0, 0, -1}, {0, 0, 0}}; | |||
vec2 _fov{90, 45}; | |||
distance_t projection_start = 1; | |||
distance_t projection_end = 50; | |||
size_t passes = 12; | |||
renderer() = default; | |||
color_t render(vec2 pixel) { | |||
g_t depth = projection_start; | |||
vec3 target{0,0,0}; | |||
target = target.normalize(); | |||
vec3 render_target{_camera.position}; | |||
for(int i = 0; i < passes; ++i) { | |||
render_target = _camera.position+depth*target; | |||
render_point distance = gp::min_of( | |||
scene_elements.begin(), | |||
scene_elements.end(), | |||
[&](auto& p){ | |||
return p(render_target); | |||
} | |||
); | |||
if(distance.distance < epsilon) { | |||
return materials[distance.material](render_target); | |||
} | |||
depth += distance.distance; | |||
if(depth >= projection_end) { | |||
break; | |||
} | |||
} | |||
return sky_box(render_target); | |||
} | |||
}; |
@ -0,0 +1,385 @@ | |||
#pragma once | |||
#include <stddef.h> | |||
#include "gp_config.hpp" | |||
#include "gp/variant.hpp" | |||
#include "gp/optional.hpp" | |||
#include "gp/buffer.hpp" | |||
#include "gp/allocator/aggregator.hpp" | |||
namespace gp { | |||
class vfs { | |||
public: | |||
struct bad_file final { | |||
static constexpr auto _what = "bad_file"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct faulty_buffer final { | |||
static constexpr auto _what = "faulty_buffer"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct interrupted final { | |||
static constexpr auto _what = "interrupted"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct io_error final { | |||
static constexpr auto _what = "io_error"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct is_directory final { | |||
static constexpr auto _what = "is_directory"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct try_again final { | |||
static constexpr auto _what = "try_again"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct not_connected final { | |||
static constexpr auto _what = "not_connected"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct impossible_io final { | |||
static constexpr auto _what = "impossible_io"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct negative_offset final { | |||
static constexpr auto _what = "negative_offset"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct is_pipe final { | |||
static constexpr auto _what = "is_pipe"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct buffer_too_big final { | |||
static constexpr auto _what = "buffer_too_big"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct path_not_directory final { | |||
static constexpr auto _what = "path_not_directory"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct name_too_long final { | |||
static constexpr auto _what = "name_too_long"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct does_not_exist final { | |||
static constexpr auto _what = "does_not_exist"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct may_loop final { | |||
static constexpr auto _what = "may_loop"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct invalid_flags final { | |||
static constexpr auto _what = "invalid_flags"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct is_read_only final { | |||
static constexpr auto _what = "is_read_only"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct fd_limit_reached final { | |||
static constexpr auto _what = "fd_limit_reached"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct file_limit_reached final { | |||
static constexpr auto _what = "file_limit_reached"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct no_locking final { | |||
static constexpr auto _what = "no_locking"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct would_block final { | |||
static constexpr auto _what = "would_block"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct no_inodes final { | |||
static constexpr auto _what = "no_inodes"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct no_space final { | |||
static constexpr auto _what = "no_space"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct quota_reached final { | |||
static constexpr auto _what = "quota_reached"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct cannot_write_shared_text final { | |||
static constexpr auto _what = "cannot_write_shared_text"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct faulty_filename final { | |||
static constexpr auto _what = "faulty_filename"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct exists_already final { | |||
static constexpr auto _what = "exists_already"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct is_append_only final { | |||
static constexpr auto _what = "is_append_only"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct unimplemented_operation final { | |||
static constexpr auto _what = "unimplemented_operation"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct is_busy final { | |||
static constexpr auto _what = "is_busy"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct bad_relative_path final { | |||
static constexpr auto _what = "bad_relative_path"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct no_permissions final { | |||
static constexpr auto _what = "no_permissions"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct success final { | |||
static constexpr auto _what = "success"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct too_big final { | |||
static constexpr auto _what = "too_big"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct network_down final { | |||
static constexpr auto _what = "network_down"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct destination_not_available final { | |||
static constexpr auto _what = "destination_not_available"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
struct insufficient_buffer_space final { | |||
static constexpr auto _what = "insufficient_buffer_space"; | |||
constexpr auto what() { | |||
return _what; | |||
} | |||
}; | |||
using read_return = gp::fixed_variant< | |||
typename buffer<char>::associated_iterator, // iterator to last element read | |||
bad_file, | |||
faulty_buffer, | |||
interrupted, | |||
io_error, | |||
is_directory, | |||
try_again, | |||
not_connected, | |||
impossible_io, | |||
negative_offset, | |||
is_pipe, | |||
buffer_too_big | |||
>; | |||
using open_return = gp::fixed_variant< | |||
gp_config::file_descriptor_t, | |||
path_not_directory, | |||
name_too_long, | |||
does_not_exist, | |||
may_loop, | |||
is_directory, | |||
invalid_flags, | |||
is_read_only, | |||
fd_limit_reached, | |||
file_limit_reached, | |||
impossible_io, | |||
interrupted, | |||
no_locking, | |||
would_block, | |||
no_space, | |||
no_inodes, | |||
quota_reached, | |||
io_error, | |||
cannot_write_shared_text, | |||
faulty_filename, | |||
exists_already, | |||
is_append_only, | |||
unimplemented_operation, | |||
is_busy, | |||
bad_relative_path, | |||
no_permissions | |||
>; | |||
using close_return = gp::fixed_variant< | |||
success, | |||
bad_file, | |||
interrupted, | |||
io_error | |||
>; | |||
using write_return = gp::fixed_variant< | |||
typename buffer<char>::associated_iterator, | |||
bad_file, | |||
no_space, | |||
quota_reached, | |||
too_big, | |||
interrupted, | |||
io_error, | |||
faulty_buffer, | |||
is_pipe, | |||
try_again, | |||
network_down, | |||
destination_not_available, | |||
impossible_io, | |||
buffer_too_big, | |||
negative_offset, | |||
insufficient_buffer_space | |||
>; | |||
class file_flags{}; | |||
class file_permissions{}; | |||
private: | |||
struct virtual_fs | |||
{ | |||
virtual ~virtual_fs() = default; | |||
virtual open_return open(buffer<char>, file_flags, file_permissions) = 0; | |||
virtual read_return read(gp_config::file_descriptor_t, buffer<char>) = 0; | |||
virtual write_return write(gp_config::file_descriptor_t, buffer<char>, size_t) = 0; | |||
virtual close_return close(gp_config::file_descriptor_t) = 0; | |||
}; | |||
template<typename concrete> | |||
class abstract_fs final : public virtual_fs{ | |||
concrete internal_representation; | |||
public: | |||
abstract_fs(abstract_fs& v) = delete; | |||
abstract_fs(abstract_fs&& v) | |||
: internal_representation{v.internal_representation} | |||
{} | |||
abstract_fs(concrete& v) = delete; | |||
abstract_fs(concrete&& v) | |||
: internal_representation{v} | |||
{} | |||
virtual ~abstract_fs() override = default; | |||
virtual open_return open(buffer<char> path, file_flags flags, file_permissions perms) override { | |||
return internal_representation.open(path, flags, perms); | |||
} | |||
virtual read_return read(gp_config::file_descriptor_t fd, buffer<char> buff) override { | |||
return internal_representation.read(fd, buff); | |||
} | |||
virtual write_return write(gp_config::file_descriptor_t fd, buffer<char> buff, size_t offset) override { | |||
return internal_representation.write(fd, buff, offset); | |||
} | |||
virtual close_return close(gp_config::file_descriptor_t fd) override { | |||
return internal_representation.close(fd); | |||
} | |||
}; | |||
reference_wrapper<aggregator> allocator; | |||
virtual_fs* file_system; | |||
public: | |||
template<typename T> | |||
vfs(T&& v, reference_wrapper<aggregator> _ref) | |||
: allocator{_ref} | |||
, file_system{new(allocator.get().allocate(sizeof(T))) T(gp::move(v))} | |||
{} | |||
open_return open(buffer<char> path, file_flags flags, file_permissions perms) { | |||
return file_system->open(path, flags, perms); | |||
} | |||
read_return read(gp_config::file_descriptor_t fd, buffer<char> buff) { | |||
return file_system->read(fd, buff); | |||
} | |||
write_return write(gp_config::file_descriptor_t fd, buffer<char> buff, size_t offset) { | |||
return file_system->write(fd, buff, offset); | |||
} | |||
close_return close(gp_config::file_descriptor_t fd) { | |||
return file_system->close(fd); | |||
} | |||
~vfs() { | |||
file_system->~virtual_fs(); | |||
allocator.get().deallocate(file_system); | |||
} | |||
}; | |||
} |
@ -1,2 +0,0 @@ | |||
#pragma once | |||
// UNIMPLEMENTED: see filename |
@ -1,2 +1,2 @@ | |||
#pragma once | |||
// UNIMPLEMENTED: see filename | |||
// UNIMPLEMENTED: see filename |
@ -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); | |||
} | |||
}; |
@ -0,0 +1,47 @@ | |||
#include "test_scaffold.h" | |||
#include "gp/math.hpp" | |||
#include "gp/rendering/renderer.hpp" | |||
#include <cmath> | |||
struct sin_test : public test_scaffold { | |||
sin_test() { | |||
name = __FILE__ ":1"; | |||
} | |||
virtual int run() { | |||
int res = 0; | |||
for(float i = 0; i < 100; i += 0.1) { | |||
float v = gp::sin(i); | |||
float ref = sin(i); | |||
res += 0.3 < gp::abs<float>(ref - v)*100.0/(gp::abs(ref+0.00000001)); | |||
} | |||
for(float i = 0; i < 100; i += 0.1) { | |||
float v = gp::cos(i); | |||
float ref = cos(i); | |||
res += 0.3 < gp::abs<float>(ref - v)*100.0/(gp::abs(ref+0.00000001)); | |||
} | |||
return res; | |||
} | |||
}; | |||
append_test dummy_mldffh6f(new sin_test{}); | |||
struct render_test : public test_scaffold { | |||
render_test() { | |||
name = __FILE__ ":2"; | |||
} | |||
virtual int run() { | |||
int res = 0; | |||
renderer a; | |||
return res; | |||
} | |||
}; | |||
append_test dummy_ml8576f(new render_test{}); |