#pragma once
|
|
|
|
#include "gp_config.hpp"
|
|
|
|
#include <gp/algorithm/tmp_manip.hpp>
|
|
#include "gp/allocator/dummy.hpp"
|
|
#include "gp/exception.hpp"
|
|
#include "gp/function.hpp"
|
|
#include "gp/memory.hpp"
|
|
|
|
#include <type_traits>
|
|
#include <new>
|
|
|
|
|
|
namespace gp{
|
|
|
|
template<typename ...T>
|
|
class fixed_variant final {
|
|
std::size_t index = std::numeric_limits<std::size_t>::max();
|
|
char buffer[max_size<T...>()];
|
|
gp::function<void(void*, void*)> cpytor = [](void*, void*){};
|
|
gp::function<void(void*, void*)> mvtor = [](void*, void*){};
|
|
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(void*)>([](void* thing){((U*)thing)->~U();});
|
|
cpytor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(*(U*)src);});
|
|
mvtor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(gp::move(*(U*)src));});
|
|
}
|
|
|
|
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(void*)>([](void* thing){((U*)thing)->~U();});
|
|
cpytor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(*(U*)src);});
|
|
mvtor = gp::function<void(void*, void*)>([](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<typename U>
|
|
constexpr size_t alt() const {
|
|
return r_index_of<U, T...>::value;
|
|
}
|
|
|
|
size_t type() const {
|
|
return index;
|
|
}
|
|
|
|
void operator=(fixed_variant& value)
|
|
{
|
|
if(index != std::numeric_limits<std::size_t>::max())
|
|
{
|
|
dtor((void*)buffer);
|
|
}
|
|
index = value.index;
|
|
cpytor = value.cpytor;
|
|
dtor = value.dtor;
|
|
mvtor(value.buffer, buffer);
|
|
}
|
|
|
|
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();});
|
|
cpytor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(*(U*)src);});
|
|
mvtor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(gp::move(*(U*)src));});
|
|
}
|
|
|
|
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();});
|
|
cpytor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(*(U*)src);});
|
|
mvtor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(gp::move(*(U*)src));});
|
|
}
|
|
|
|
~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;
|
|
}
|
|
}
|
|
};*/
|
|
}
|