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