General Purpose library for Freestanding C++ and POSIX systems
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 

258 linhas
7.4 KiB

#pragma once
#include "gp_config.hpp"
#include <gp/algorithm/move.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*){}, nullopt};
gp::function<void(void*, void*)> mvtor = {[](void*, void*){}, nullopt};
gp::function<void(void*)> dtor = {[](void*){}, nullopt};
static_assert(all_of_fixed_size<T...>::value, "not fixed");
void buffswap(fixed_variant& oth) {
char tmp[max_size<T...>()];
mvtor(tmp, buffer);
oth.mvtor(buffer, oth.buffer);
mvtor(oth.buffer, tmp);
}
public:
template<typename U, typename = std::enable_if_t<list_contains_class<gp::remove_cvref_t<U>,T...>::value,int>>
fixed_variant(U& value)
: index{r_index_of<U, T...>::value}
{
using actual = gp::remove_cvref_t<U>;
new(buffer) actual(value);
dtor = gp::function<void(void*)>([](void* thing){((actual*)thing)->~actual();}, nullopt);
cpytor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) actual(*(actual*)src);}, nullopt);
mvtor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) actual(gp::move(*(actual*)src));}, nullopt);
}
static_assert(list_contains_class<int, int>::value, "list_contains_class doesn't work properly");
static_assert(list_contains_class<int, char, int>::value, "list_contains_class doesn't work properly");
static_assert(list_contains_class<int, int, char>::value, "list_contains_class doesn't work properly");
static_assert(list_contains_class<int, char, int, char>::value, "list_contains_class doesn't work properly");
template<typename U, typename = std::enable_if_t<list_contains_class<gp::remove_cvref_t<U>,T...>::value,int>>
fixed_variant(U&& value)
: index{r_index_of<U, T...>::value}
{
using actual = gp::remove_cvref_t<U>;
new(buffer) actual(std::move(value));
dtor = gp::function<void(void*)>([](void* thing){((actual*)thing)->~actual();}, nullopt);
cpytor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) actual(*(actual*)src);}, nullopt);
mvtor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) actual(gp::move(*(actual*)src));}, nullopt);
}
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)
{
mvtor(buffer, oth.buffer);
gp::swap(dtor, oth.dtor);
gp::swap(cpytor, oth.cpytor);
gp::swap(mvtor, oth.mvtor);
gp::swap(index, oth.index);
}
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.mvtor;
cpytor(value.buffer, buffer);
}
void operator=(fixed_variant&& value)
{
buffswap(value);
gp::swap(dtor, value.dtor);
gp::swap(cpytor, value.cpytor);
gp::swap(mvtor, value.mvtor);
gp::swap(index, value.index);
}
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();}, nullopt);
cpytor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(*(U*)src);}, nullopt);
mvtor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(gp::move(*(U*)src));}, nullopt);
}
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;
dtor = gp::function([](void* thing){((U*)thing)->~U();}, nullopt);
cpytor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(*(U*)src);}, nullopt);
mvtor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(gp::move(*(U*)src));}, nullopt);
mvtor(buffer, value.buffer);
}
~fixed_variant()
{
if(index != std::numeric_limits<std::size_t>::max() && dtor.ready())
{
dtor((void*)buffer);
index = std::numeric_limits<std::size_t>::max();
}
}
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;
}
}
};*/
}