|
|
- #pragma once
- #include <gp/algorithm/tmp_manip.hpp>
- #include <type_traits>
- #include <new>
- #include "gp_config.hpp"
- #include "gp/exception.hpp"
- #include "gp/memory.hpp"
- #include "gp/function.hpp"
-
-
- namespace gp{
-
- template<typename ...T>
- class fixed_variant{
- std::size_t index = std::numeric_limits<std::size_t>::max();
- char buffer[max_size<T...>()];
- gp::function<void(void*)> dtor = [](void*){};
- static_assert(all_of_fixed_size<T...>::value, "not fixed");
- public:
- template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
- constexpr fixed_variant(U& value)
- : index{r_index_of<U, T...>::value}
- {
- new(buffer) U(value);
- dtor = gp::function([](void* thing){((U*)thing)->~U();});
- }
-
- template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
- constexpr fixed_variant(U&& value)
- : index{r_index_of<U, T...>::value}
- {
- new(buffer) U(std::move(value));
- dtor = gp::function([](void* thing){((U*)thing)->~U();});
- }
-
-
-
- template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
- void operator=(U& value)
- {
- if(index != std::numeric_limits<std::size_t>::max())
- {
- dtor((void*)buffer);
- }
- index = r_index_of<U, T...>::value;
- new(buffer) U(value);
- dtor = gp::function([](void* thing){((U*)thing)->~U();});
- }
-
- template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
- void operator=(U&& value)
- {
- if(index != std::numeric_limits<std::size_t>::max())
- {
- dtor((void*)buffer);
- }
- index = r_index_of<U, T...>::value;
- new(buffer) U(std::move(value));
- dtor = gp::function([](void* thing){((U*)thing)->~U();});
- }
-
- ~fixed_variant()
- {
- if(index != std::numeric_limits<std::size_t>::max())
- {
- dtor((void*)buffer);
- }
- }
-
- template<typename U>
- constexpr U& value()
- {
- if constexpr (gp_config::has_exceptions)
- {
- if(r_index_of<U, T...>::value != index)
- {
- throw bad_variant_access<U>{};
- }
- }
- return *reinterpret_cast<U*>(buffer);
- }
-
- template<typename U>
- constexpr U& is_a()
- {
- if(r_index_of<U, T...>::value == index)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- };
-
- template<typename allocator_t = gp_config::memory_module::default_allocator, typename ...T>
- class variant{
- std::size_t index = std::numeric_limits<std::size_t>::max();
- void* ptr;
- gp::function<void(void*)> dtor = [](void*){};
- allocator_t allocator;
- public:
- template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
- constexpr variant(U& value)
- : index{r_index_of<U, T...>::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<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
- constexpr variant(U&& value)
- : index{r_index_of<U, T...>::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<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
- void operator=(U& value)
- {
- if(index != std::numeric_limits<std::size_t>::max())
- {
- dtor(ptr);
- allocator.deallocate(ptr);
- }
- index = r_index_of<U, T...>::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<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
- void operator=(U&& value)
- {
- if(index != std::numeric_limits<std::size_t>::max())
- {
- dtor(ptr);
- allocator.deallocate(ptr);
- }
- index = r_index_of<U, T...>::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<std::size_t>::max())
- {
- dtor(ptr);
- allocator.deallocate(ptr);
- }
- }
-
- template<typename U>
- constexpr U& value()
- {
- if constexpr (gp_config::has_exceptions)
- {
- if(r_index_of<U, T...>::value != index)
- {
- throw bad_variant_access<U>{};
- }
- }
- return *reinterpret_cast<U*>(ptr);
- }
-
- template<typename U>
- constexpr U& is_a()
- {
- if(r_index_of<U, T...>::value == index)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- };
- }
|