General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

223 lines
6.0 KiB

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