#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;
|
|
}
|
|
}
|
|
};
|
|
}
|