#pragma once #include "gp_config.hpp" #include #include #include "gp/allocator/dummy.hpp" #include "gp/exception.hpp" #include "gp/function.hpp" #include "gp/memory.hpp" #include #include namespace gp{ template class fixed_variant final { std::size_t index = std::numeric_limits::max(); char buffer[max_size()]; gp::function cpytor = {[](void*, void*){}, nullopt}; gp::function mvtor = {[](void*, void*){}, nullopt}; gp::function dtor = {[](void*){}, nullopt}; static_assert(all_of_fixed_size::value, "not fixed"); public: fixed_variant() : fixed_variant(typename first_of::type{}) {} template,T...>::value,int> = 0> fixed_variant(U& value) : index{r_index_of::value} { using actual = gp::remove_cvref_t; dtor = gp::function([](void* thing){ ((actual*)thing)->~actual(); }, nullopt); cpytor = gp::function([](void* src, void* dest){ new(dest) actual(*(actual*)src); }, nullopt); mvtor = gp::function([](void* src, void* dest){ new(dest) actual(gp::move(*(actual*)src)); }, nullopt); cpytor((char*)&value, buffer); } static_assert(list_contains_class::value, "list_contains_class doesn't work properly"); static_assert(list_contains_class::value, "list_contains_class doesn't work properly"); static_assert(list_contains_class::value, "list_contains_class doesn't work properly"); static_assert(list_contains_class::value, "list_contains_class doesn't work properly"); static_assert(!list_contains_class::value, "list_contains_class doesn't work properly"); template,T...>::value,int> = 0> fixed_variant(U&& value) : index{r_index_of::value} { using actual = gp::remove_cvref_t; dtor = gp::function([](void* thing){ ((actual*)thing)->~actual(); }, nullopt); cpytor = gp::function([](void* src, void* dest){ new(dest) actual(*(actual*)src); }, nullopt); mvtor = gp::function([](void* src, void* dest){ new(dest) actual(gp::move(*(actual*)src)); }, nullopt); mvtor((char*)&value, buffer); } fixed_variant(const fixed_variant& oth) : index{oth.index} , dtor{oth.dtor} , cpytor{oth.cpytor} , mvtor{oth.mvtor} { cpytor((char*)oth.buffer, (char*)buffer); } fixed_variant(fixed_variant& oth) : index{oth.index} , dtor{oth.dtor} , cpytor{oth.cpytor} , mvtor{oth.mvtor} { cpytor(oth.buffer, buffer); } fixed_variant(fixed_variant&& oth) : index{oth.index} , dtor{oth.dtor} , cpytor{oth.cpytor} , mvtor{oth.mvtor} { oth.index = std::numeric_limits::max(); mvtor(oth.buffer, buffer); } template constexpr size_t alt() const { return r_index_of::value; } size_t type() const { 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.mvtor; cpytor(value.buffer, buffer); } void operator=(fixed_variant&& value) { if(index != std::numeric_limits::max()) { dtor((void*)buffer); } dtor = value.dtor; cpytor = value.cpytor; mvtor = value.mvtor; index = value.index; value.index = std::numeric_limits::max(); mvtor(value.buffer, buffer); } template::value,int>::type> void operator=(U& value) { if(index != std::numeric_limits::max()) { dtor((void*)buffer); } index = r_index_of::value; new(buffer) U(value); dtor = gp::function([](void* thing){((U*)thing)->~U();}, nullopt); cpytor = gp::function([](void* src, void* dest){new(dest) U(*(U*)src);}, nullopt); mvtor = gp::function([](void* src, void* dest){new(dest) U(gp::move(*(U*)src));}, nullopt); } template::value,int>::type> void operator=(U&& value) { if(index != std::numeric_limits::max()) { dtor((void*)buffer); } new(buffer) U(gp::move(value)); index = r_index_of::value; dtor = gp::function([](void* thing){((U*)thing)->~U();}, nullopt); cpytor = gp::function([](void* src, void* dest){new(dest) U(*(U*)src);}, nullopt); mvtor = gp::function([](void* src, void* dest){new(dest) U(gp::move(*(U*)src));}, nullopt); } ~fixed_variant() { if(index != std::numeric_limits::max() && dtor.ready()) { dtor((void*)buffer); index = std::numeric_limits::max(); } } template constexpr U& value() { if constexpr (gp_config::has_exceptions) { if(r_index_of::value != index) { throw bad_variant_access{}; } } return *reinterpret_cast(buffer); } template constexpr bool is_a() { if(r_index_of::value == index) { return true; } else { return false; } } }; /*template class variant{ std::size_t index = std::numeric_limits::max(); void* ptr; gp::function dtor = [](void*){}; allocator_t allocator; public: template::value,int>::type> constexpr variant(U& value) : index{r_index_of::value} { ptr = (void*)new(allocator.allocate(sizeof(U))) U(value); dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO:replae with delete(p,t) } template::value,int>::type> constexpr variant(U&& value) : index{r_index_of::value} { ptr = (void*)new(allocator.allocate(sizeof(U))) U(std::move(value)); dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO:replae with delete(p,t) } template::value,int>::type> void operator=(U& value) { if(index != std::numeric_limits::max()) { dtor(ptr); allocator.deallocate(ptr); } index = r_index_of::value; ptr = (void*)new(allocator.allocate(sizeof(U))) U(value); dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO:replae with delete(p,t) } template::value,int>::type> void operator=(U&& value) { if(index != std::numeric_limits::max()) { dtor(ptr); allocator.deallocate(ptr); } index = r_index_of::value; ptr = (void*)new(allocator.allocate(sizeof(U))) U(std::move(value)); dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO: replace with delete(p, t) } ~variant() { if(index != std::numeric_limits::max()) { dtor(ptr); allocator.deallocate(ptr); } } template constexpr U& value() { if constexpr (gp_config::has_exceptions) { if(r_index_of::value != index) { throw bad_variant_access{}; } } return *reinterpret_cast(ptr); } template constexpr U& is_a() { if(r_index_of::value == index) { return true; } else { return false; } } };*/ }