diff --git a/CMakeLists.txt b/CMakeLists.txt index a07b213..7d05f1e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,6 +210,7 @@ set( fc_sources src/variant.cpp src/exception.cpp src/variant_object.cpp + src/static_variant.cpp src/thread/thread.cpp src/thread/thread_specific.cpp src/thread/future.cpp diff --git a/include/fc/static_variant.hpp b/include/fc/static_variant.hpp index 1b2628b..6c0ef5b 100644 --- a/include/fc/static_variant.hpp +++ b/include/fc/static_variant.hpp @@ -1,4 +1,4 @@ -/** This source adapted from https://github.com/kmicklas/variadic-static_variant +/** This source adapted from https://github.com/kmicklas/variadic-static_variant. Now available at https://github.com/kmicklas/variadic-variant. * * Copyright (C) 2013 Kenneth Micklas * @@ -176,6 +176,41 @@ struct type_info<> { static const size_t size = 0; }; +template +size_t size( TTag ) +{ + return 0; +} + +template +size_t size( TTag tag ) +{ + if (tag <= 0) + { + return sizeof(A); + } + + return size( --tag ); +} + + +class dynamic_storage +{ + char* storage; +public: + dynamic_storage(); + + ~dynamic_storage(); + + void* data() const; + + void alloc( size_t size ); + + void release(); +}; + + + } // namespace impl template @@ -213,40 +248,57 @@ class static_variant { static_assert(impl::type_info::no_reference_types, "Reference types are not permitted in static_variant."); static_assert(impl::type_info::no_duplicates, "static_variant type arguments contain duplicate types."); + template + using type_in_typelist = typename std::enable_if::pos != -1, X>::type; // type is in typelist of static_variant. + using tag_type = int64_t; tag_type _tag; - char storage[impl::type_info::size]; + impl::dynamic_storage storage; - template + template> void init(const X& x) { _tag = impl::position::pos; - new(storage) X(x); + storage.alloc( sizeof(X) ); + new(storage.data()) X(x); } - template + template> void init(X&& x) { _tag = impl::position::pos; - new(storage) X( std::move(x) ); + storage.alloc( sizeof(X) ); + new(storage.data()) X( std::move(x) ); } + void init(tag_type tag) + { + FC_ASSERT( tag >= 0 ); + FC_ASSERT( tag < count() ); + _tag = tag; + storage.alloc( impl::size( tag ) ); + impl::storage_ops<0, Types...>::con(_tag, storage.data()); + } + + void clean() + { + impl::storage_ops<0, Types...>::del(_tag, storage.data() ); + storage.release(); + } + + template friend struct impl::copy_construct; template friend struct impl::move_construct; public: - template + template> struct tag { - static_assert( - impl::position::pos != -1, - "Type not in static_variant." - ); static const int value = impl::position::pos; }; + static_variant() { - _tag = 0; - impl::storage_ops<0, Types...>::con(0, storage); + init(0); } template @@ -254,6 +306,7 @@ public: { cpy.visit( impl::copy_construct(*this) ); } + static_variant( const static_variant& cpy ) { cpy.visit( impl::copy_construct(*this) ); @@ -264,40 +317,32 @@ public: mv.visit( impl::move_construct(*this) ); } - template + template> static_variant(const X& v) { - static_assert( - impl::position::pos != -1, - "Type not in static_variant." - ); init(v); } + ~static_variant() { - impl::storage_ops<0, Types...>::del(_tag, storage); + clean(); } - - template + template> static_variant& operator=(const X& v) { - static_assert( - impl::position::pos != -1, - "Type not in static_variant." - ); - this->~static_variant(); + clean(); init(v); return *this; } static_variant& operator=( const static_variant& v ) { if( this == &v ) return *this; - this->~static_variant(); + clean(); v.visit( impl::copy_construct(*this) ); return *this; } static_variant& operator=( static_variant&& v ) { if( this == &v ) return *this; - this->~static_variant(); + clean(); v.visit( impl::move_construct(*this) ); return *this; } @@ -310,52 +355,40 @@ public: return a.which() < b.which(); } - template + template> X& get() { - static_assert( - impl::position::pos != -1, - "Type not in static_variant." - ); if(_tag == impl::position::pos) { - void* tmp(storage); - return *reinterpret_cast(tmp); + return *reinterpret_cast(storage.data()); } else { FC_THROW_EXCEPTION( fc::assert_exception, "static_variant does not contain a value of type ${t}", ("t",fc::get_typename::name()) ); - // std::string("static_variant does not contain value of type ") + typeid(X).name() - // ); } } - template + template> const X& get() const { - static_assert( - impl::position::pos != -1, - "Type not in static_variant." - ); if(_tag == impl::position::pos) { - const void* tmp(storage); - return *reinterpret_cast(tmp); + return *reinterpret_cast(storage.data()); } else { FC_THROW_EXCEPTION( fc::assert_exception, "static_variant does not contain a value of type ${t}", ("t",fc::get_typename::name()) ); } } template typename visitor::result_type visit(visitor& v) { - return visit( _tag, v, (void*) storage ); + return visit( _tag, v, (void*) storage.data() ); } template typename visitor::result_type visit(const visitor& v) { - return visit( _tag, v, (void*) storage ); + return visit( _tag, v, (void*) storage.data() ); } template typename visitor::result_type visit(visitor& v)const { - return visit( _tag, v, (const void*) storage ); + return visit( _tag, v, (const void*) storage.data() ); } template typename visitor::result_type visit(const visitor& v)const { - return visit( _tag, v, (const void*) storage ); + return visit( _tag, v, (const void*) storage.data() ); } template @@ -394,9 +427,8 @@ public: void set_which( tag_type w ) { FC_ASSERT( w >= 0 ); FC_ASSERT( w < count() ); - this->~static_variant(); - _tag = w; - impl::storage_ops<0, Types...>::con(_tag, storage); + clean(); + init(w); } tag_type which() const {return _tag;} diff --git a/src/static_variant.cpp b/src/static_variant.cpp new file mode 100644 index 0000000..97c69d9 --- /dev/null +++ b/src/static_variant.cpp @@ -0,0 +1,31 @@ +#include + + +namespace fc { namespace impl { + +dynamic_storage::dynamic_storage() : storage(nullptr) {}; + +dynamic_storage::~dynamic_storage() +{ + release(); +} + +void* dynamic_storage::data() const +{ + assert( storage != nullptr ); + return (void*)storage; +} + +void dynamic_storage::alloc( size_t size ) +{ + release(); + storage = new char[size]; +} + +void dynamic_storage::release() +{ + delete [] storage; + storage = nullptr; +} + +}}