X-Git-Url: http://git.tdb.fi/?p=libs%2Fcore.git;a=blobdiff_plain;f=source%2Fcore%2Fvariant.h;h=af204f2233f3c7759665a0f6b729bd52459d4326;hp=5de5a726f2dde80ee987c582851bbac2ca0523e6;hb=HEAD;hpb=5d51c374869f13f762039f58c03f3c5d75c12f07 diff --git a/source/core/variant.h b/source/core/variant.h index 5de5a72..5cb1b93 100644 --- a/source/core/variant.h +++ b/source/core/variant.h @@ -5,17 +5,18 @@ #include #include #include "meta.h" +#include "mspcore_api.h" namespace Msp { -class type_mismatch: public std::runtime_error +class MSPCORE_API type_mismatch: public std::runtime_error { public: type_mismatch(const std::type_info &, const std::type_info &); }; -class Variant +class MSPCORE_API Variant { public: static constexpr unsigned INTERNAL_SIZE = 2*sizeof(void *); @@ -25,30 +26,39 @@ public: const std::type_info &(*get_type)(); bool (*compare)(const char *, const char *); void (*clone)(char *, const char *); + void (*move)(char *, char *); void (*destroy)(char *); }; private: + template + using EnableNotVariant = typename std::enable_if::type>::type, Variant>::value>::type; + const Functions *funcs = nullptr; alignas(void *) char storage[INTERNAL_SIZE]; public: Variant() = default; - template - Variant(const T &v) { assign(v); } + template> + Variant(T &&v) { assign(std::forward(v)); } Variant(const Variant &v) { copy_from(v); } - ~Variant() { if(funcs) funcs->destroy(storage); } + Variant(Variant &&v) { move_from(std::move(v)); } + ~Variant() { clear(); } - template - Variant &operator=(const T &v) { assign(v); return *this; } + template> + Variant &operator=(T &&v) { assign(std::forward(v)); return *this; } Variant &operator=(const Variant &v) { if(&v!=this) copy_from(v); return *this; } + Variant &operator=(Variant &&v) { if(&v!=this) move_from(std::move(v)); return *this; } + + void clear(); private: template - void assign(const T &); + void assign(T &&); void copy_from(const Variant &); + void move_from(Variant &&); template T &get(); @@ -95,12 +105,12 @@ private: static const std::type_info &get_type() { return typeid(T); } template - static EnableSmall create(char *s, const T &v) - { new(s) T(v); } + static EnableSmall create(char *s, T &&v) + { new(s) typename std::remove_reference::type(std::forward(v)); } template - static EnableLarge create(char *s, const T &v) - { *reinterpret_cast(s) = new T(v); } + static EnableLarge create(char *s, T &&v) + { using V = typename std::remove_reference::type; *reinterpret_cast(s) = new V(std::forward(v)); } template static typename std::enable_if::value, bool>::type compare(const char *, const char *) @@ -122,6 +132,14 @@ private: static EnableLarge clone(char *s, const char *v) { *reinterpret_cast(s) = new T(**reinterpret_cast(v)); } + template + static EnableSmall move(char *s, char *v) + { new(s) T(std::move(*reinterpret_cast(v))); } + + template + static EnableLarge move(char *s, char *v) + { T *&p = *reinterpret_cast(v); *reinterpret_cast(s) = p; p = nullptr; } + template static EnableSmall destroy(char *s) { reinterpret_cast(s)->~T(); } @@ -132,26 +150,36 @@ private: }; -template -inline void Variant::assign(const T &v) +inline void Variant::clear() { if(funcs) funcs->destroy(storage); + funcs = nullptr; +} - funcs = get_functions::type>(); - create(storage, v); +template +inline void Variant::assign(T &&v) +{ + clear(); + funcs = get_functions::type>::type>(); + create(storage, std::forward(v)); } inline void Variant::copy_from(const Variant &v) { - if(funcs) - funcs->destroy(storage); - - funcs = v.funcs; - if(funcs) + clear(); + if((funcs = v.funcs)) funcs->clone(storage, v.storage); } +inline void Variant::move_from(Variant &&v) +{ + clear(); + if((funcs = v.funcs)) + funcs->move(storage, v.storage); + v.clear(); +} + template inline T &Variant::get() { @@ -182,6 +210,7 @@ inline const Variant::Functions *Variant::get_functions() &get_type, &compare, &clone, + &move, &destroy }; return &funcs;