From 998dda01a2db24065e5585c3a1b68fd0ef1780a3 Mon Sep 17 00:00:00 2001 From: Ludovic 'Archivist' Lagouardette Date: Tue, 6 Oct 2020 19:06:14 +0200 Subject: [PATCH] Various fixes to containers and enhancements --- include/gp/enveloppe/cbor.hpp | 58 ++++++++++++++-- include/gp/function.hpp | 120 +++++++++++++++++++++++++++------- include/gp/optional.hpp | 4 +- include/gp/variant.hpp | 37 ++++++++++- include/gp/vector.hpp | 10 +-- tests.cpp | 1 + tests/cbor_test.cpp | 23 +++++++ 7 files changed, 214 insertions(+), 39 deletions(-) create mode 100644 tests/cbor_test.cpp diff --git a/include/gp/enveloppe/cbor.hpp b/include/gp/enveloppe/cbor.hpp index f223c80..0f511da 100644 --- a/include/gp/enveloppe/cbor.hpp +++ b/include/gp/enveloppe/cbor.hpp @@ -1,9 +1,9 @@ #pragma once -#include +#include #include +#include #include -#include namespace gp { @@ -71,16 +71,60 @@ namespace gp { double >; - struct undefined_t{}; + struct undefined_t final {}; - class cbor_value : public gp::fixed_variant< + template + using cbor_composite = gp::fixed_variant< cbor_number, gp::buffer, bool, - gp::vector, - gp::vector>, + gp::vector, + gp::vector>, gp::nullopt_t, undefined_t, cbor_floating_point - >{}; + >; + + class cbor_value { + + cbor_composite contents; + gp::reference_wrapper alloc; + public: + + cbor_value(allocator& alloc_v) + : contents(cbor_composite(undefined_t{})) + , alloc(alloc_v) + {} + + cbor_value(cbor_number number, allocator& alloc_v) + : contents(number) + , alloc(alloc_v) + {} + + cbor_value& operator=(cbor_value& value) { + contents = value.contents; + alloc = value.alloc; + return *this; + } + + cbor_value& operator=(cbor_value&& value) { + gp::swap(contents, value.contents); + gp::swap(alloc, value.alloc); + return *this; + } + + cbor_value& operator=(cbor_composite& value) { + contents = value; + return *this; + } + + + auto new_array() { + return gp::vector{alloc}; + } + + auto new_object() { + return gp::vector>{alloc}; + } + }; } \ No newline at end of file diff --git a/include/gp/function.hpp b/include/gp/function.hpp index 3bb41a6..e60e6a6 100644 --- a/include/gp/function.hpp +++ b/include/gp/function.hpp @@ -5,8 +5,18 @@ #include "gp/algorithm/move.hpp" #include "gp/algorithm/tmp_manip.hpp" #include "gp/allocator/allocator.hpp" +#include "gp/optional.hpp" namespace gp{ + + namespace details { + template + auto ensure(pred a, returner b) { + gp_config::assertion(a(), "could not ensure predicate"); + return b(); + } + } + template class function; @@ -17,7 +27,7 @@ namespace gp{ using invoke_fn_t = ret (*)(fn_ptr, args&&...); using condestruct_fn_t = void (*) (fn_ptr, fn_ptr); - gp::reference_wrapper alloc; + gp::optional> alloc; invoke_fn_t invokator; condestruct_fn_t condestructor; fn_ptr data_ptr; @@ -45,10 +55,10 @@ namespace gp{ public: #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wnull-dereference" -#pragma gcc diagnostic push -#pragma gcc diagnostic ignored "-Wnull-dereference" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnull-dereference" function(allocator& alloc_v) -#pragma gcc pop +#pragma GCC diagnostic pop #pragma clang diagnostic pop : alloc(alloc_v) , invokator(nullptr) @@ -62,54 +72,98 @@ namespace gp{ : alloc(alloc_v) , invokator(reinterpret_cast(invoke)) , condestructor(reinterpret_cast(condestruct)) - , data_ptr((char*)(alloc.get().allocate(sizeof(func)))) - , data_size(sizeof(func)) + , data_ptr( + sizeof(func) <= sizeof(data_ptr) + ? 0 + : details::ensure( + [&](){return alloc.has_value();}, + [&](){return (char*)(alloc.value().get().allocate(sizeof(func)));} + ) + ) + , data_size( + sizeof(func) <= sizeof(data_ptr) + ? 0 + : sizeof(func) + ) { - gp_config::assertion(data_ptr != nullptr, "allocator failed in function"); - if(data_ptr != nullptr) this->condestructor(data_ptr, reinterpret_cast(&f)); + gp_config::assertion(!(alloc.has_value() && data_ptr == nullptr), "allocator failed in function"); + if(data_ptr != nullptr) this->condestructor(data_size < sizeof(data_ptr) ? (char*)&data_ptr : data_ptr, reinterpret_cast(&f)); + } + + template + function(func f, nullopt_t alloc_v = nullopt) + : alloc(alloc_v) + , invokator(reinterpret_cast(invoke)) + , condestructor(reinterpret_cast(condestruct)) + , data_ptr( + sizeof(func) <= sizeof(data_ptr) + ? 0 + : details::ensure( + [&](){return alloc.has_value();}, + [&](){return (char*)(alloc.value().get().allocate(sizeof(func)));} + ) + ) + , data_size( + sizeof(func) <= sizeof(data_ptr) + ? 0 + : sizeof(func) + ) + { + gp_config::assertion(!(alloc.has_value() && data_ptr == nullptr), "allocator failed in function"); + if(data_ptr != nullptr) this->condestructor(data_size < sizeof(data_ptr) ? (char*)&data_ptr : data_ptr, reinterpret_cast(&f)); } function(function const& rhs) : alloc(rhs.alloc) , invokator(rhs.invokator) , condestructor(rhs.condestructor) - , data_ptr(rhs.data_size != 0 ? (char*)(alloc.get().allocate(rhs.data_size)) : nullptr) + , data_ptr( + rhs.data_size <= sizeof(data_ptr) + ? 0 + : details::ensure( + [&](){return alloc.has_value();}, + [&](){return (char*)(alloc.value().get().allocate(rhs.data_size));} + ) + ) , data_size(rhs.data_size) { - gp_config::assertion(data_ptr != nullptr, "allocator failed in function"); + gp_config::assertion(!(alloc.has_value() && data_ptr == nullptr), "allocator failed in function"); if( data_ptr != nullptr and rhs.data_ptr != nullptr - ) this->condestructor(data_ptr, rhs.data_ptr); + ) this->condestructor(data_size <= sizeof(data_ptr) ? (char*)&data_ptr : data_ptr, rhs.data_ptr); } function(function&& rhs) : alloc(rhs.alloc) , invokator(rhs.invokator) , condestructor(rhs.condestructor) - , data_ptr(rhs.data_ptr) + , data_ptr(data_size <= sizeof(data_ptr) ? 0 : rhs.data_ptr) , data_size(rhs.data_size) { + if(data_size <= sizeof(data_ptr) && data_size != 0 && data_ptr != nullptr && alloc.has_value()) { + condestructor((char*)&data_ptr, (char*)&rhs.data_ptr); + condestructor(nullptr, (char*)&rhs.data_ptr); + } rhs.data_ptr = nullptr; } - constexpr function(ret(*fn)(args...), allocator alloc_v) - : alloc(alloc_v) - , invokator(reinterpret_cast(invoke)) - , condestructor(nop_condestruct) - , data_ptr(reinterpret_cast(fn)) - , data_size(0) - {} - ~function(){ if(data_size == 0) { return; } - if(data_ptr != nullptr) { + if(data_size <= 0) { + return; + } + if(data_ptr != nullptr && alloc.has_value()) { condestructor(nullptr, data_ptr); - alloc.get().deallocate(data_ptr); + alloc.value().get().deallocate(data_ptr); data_ptr = nullptr; } + if(data_size < sizeof(data_ptr)) + { + condestructor(nullptr, (char*)&data_ptr); + } } function& operator=(function&& rhs) { @@ -121,6 +175,28 @@ namespace gp{ return *this; } + function& operator=(function& rhs) { + alloc = rhs.alloc; + invokator = rhs.invokator; + condestructor = rhs.condestructor; + condestructor(nullptr, data_ptr); + alloc.value().get().deallocate(data_ptr); + data_ptr = rhs.data_size <= sizeof(data_ptr) + ? 0 + : details::ensure( + [&](){return alloc.has_value();}, + [&](){return (char*)(alloc.value().get().allocate(rhs.data_size));} + ); + + data_size = rhs.data_size; + gp_config::assertion(!(alloc.has_value() && data_ptr == nullptr), "allocator failed in function"); + if( + data_ptr != nullptr + and rhs.data_ptr != nullptr + ) this->condestructor(data_size <= sizeof(data_ptr) ? (char*)&data_ptr : data_ptr, rhs.data_ptr); + return *this; + } + ret operator()(args&&... argv) { return invokator(data_ptr, gp::forward(argv)...); } diff --git a/include/gp/optional.hpp b/include/gp/optional.hpp index fabf45b..7044bda 100644 --- a/include/gp/optional.hpp +++ b/include/gp/optional.hpp @@ -10,12 +10,12 @@ #include namespace gp{ - struct nullopt_t{}; + struct nullopt_t final{}; constexpr nullopt_t nullopt; template - class optional{ + class optional final{ bool ready = false; char buffer[sizeof(T)]; public: diff --git a/include/gp/variant.hpp b/include/gp/variant.hpp index 8fe9986..51a3b0a 100644 --- a/include/gp/variant.hpp +++ b/include/gp/variant.hpp @@ -15,26 +15,41 @@ namespace gp{ template - class fixed_variant{ + class fixed_variant final { std::size_t index = std::numeric_limits::max(); char buffer[max_size()]; + gp::function cpytor = [](void*, void*){}; + gp::function mvtor = [](void*, void*){}; gp::function dtor = [](void*){}; static_assert(all_of_fixed_size::value, "not fixed"); public: - template::value,int>::type> + template//, typename std::enable_if::value,int>::type> constexpr fixed_variant(U& value) : index{r_index_of::value} { new(buffer) U(value); dtor = gp::function([](void* thing){((U*)thing)->~U();}); + cpytor = gp::function([](void* src, void* dest){new(dest) U(*(U*)src);}); + mvtor = gp::function([](void* src, void* dest){new(dest) U(gp::move(*(U*)src));}); } - template::value,int>::type> + template//, typename std::enable_if::value,int>::type> constexpr fixed_variant(U&& value) : index{r_index_of::value} { new(buffer) U(std::move(value)); dtor = gp::function([](void* thing){((U*)thing)->~U();}); + cpytor = gp::function([](void* src, void* dest){new(dest) U(*(U*)src);}); + mvtor = gp::function([](void* src, void* dest){new(dest) U(gp::move(*(U*)src));}); + } + + constexpr fixed_variant(fixed_variant& oth) + : index{oth.index} + , dtor{oth.dtor} + , cpytor{oth.cpytor} + , mvtor{oth.mvtor} + { + cpytor(oth.buffer, buffer); } template @@ -46,6 +61,18 @@ namespace gp{ return index; } + void operator=(fixed_variant& value) + { + if(index != std::numeric_limits::max()) + { + dtor((void*)buffer); + } + index = value.index; + cpytor = value.cpytor; + dtor = value.dtor; + mvtor(value.buffer, buffer); + } + template::value,int>::type> void operator=(U& value) { @@ -56,6 +83,8 @@ namespace gp{ index = r_index_of::value; new(buffer) U(value); dtor = gp::function([](void* thing){((U*)thing)->~U();}); + cpytor = gp::function([](void* src, void* dest){new(dest) U(*(U*)src);}); + mvtor = gp::function([](void* src, void* dest){new(dest) U(gp::move(*(U*)src));}); } template::value,int>::type> @@ -68,6 +97,8 @@ namespace gp{ index = r_index_of::value; new(buffer) U(std::move(value)); dtor = gp::function([](void* thing){((U*)thing)->~U();}); + cpytor = gp::function([](void* src, void* dest){new(dest) U(*(U*)src);}); + mvtor = gp::function([](void* src, void* dest){new(dest) U(gp::move(*(U*)src));}); } ~fixed_variant() diff --git a/include/gp/vector.hpp b/include/gp/vector.hpp index 10c6779..02e2c34 100644 --- a/include/gp/vector.hpp +++ b/include/gp/vector.hpp @@ -7,7 +7,7 @@ namespace gp{ template - class vector{ + class vector final { T* ary; size_t sz; size_t cap; @@ -110,7 +110,7 @@ namespace gp{ if(ary) { for(auto& elem : *this) { - elem->~T(); + elem.~T(); } gp_config::assertion(alloc.get().deallocate(ary), "could not deallocate"); } @@ -128,10 +128,10 @@ namespace gp{ if(alloc.get().try_reallocate(ary, new_data_size)) return true; - if(T* new_ary = alloc.get().allocate(new_data_size); new_ary) { + if(T* new_ary = (T*)alloc.get().allocate(new_data_size); new_ary) { auto new_it = new_ary; - for(auto* elem : *this) { - ++new_it = gp::move(elem); + for(auto& elem : *this) { + *(++new_it) = gp::move(elem); } gp_config::assertion(alloc.get().deallocate(ary), "failed to deallocate old range"); diff --git a/tests.cpp b/tests.cpp index d1c7fbb..eac275a 100644 --- a/tests.cpp +++ b/tests.cpp @@ -2,6 +2,7 @@ #include "allocator.hpp" #include "bloomfilter.cpp" +#include "cbor_test.cpp" #include "gp_test.cpp" #include "math.cpp" #include "meta_test.cpp" diff --git a/tests/cbor_test.cpp b/tests/cbor_test.cpp new file mode 100644 index 0000000..7deedf5 --- /dev/null +++ b/tests/cbor_test.cpp @@ -0,0 +1,23 @@ + +#include +#include +#include +#include "test_scaffold.h" + +struct cbor_test : public test_scaffold { + cbor_test() { + name = __FILE__ ":1"; + } + + virtual int run() { + gp::array store; + gp::arena alloc{&*store.begin(), store.size()}; + gp::cbor_value data{alloc}; + auto gen = data.new_object(); + gen.emplace_back(uint8_t(12), int32_t(-98)); + gen.emplace_back(uint8_t(13), uint32_t(98)); + return 0; + } +}; + +append_test dummy_pg5zhr8bv(new cbor_test{}); \ No newline at end of file