X-Git-Url: http://git.tdb.fi/?p=libs%2Fcore.git;a=blobdiff_plain;f=source%2Fcore%2Fvariant.h;h=af204f2233f3c7759665a0f6b729bd52459d4326;hp=934a9e539276e3ad406a6b05b00e01cd3d964ca0;hb=HEAD;hpb=db3397e3b7b9839714ce28d9df2a8f226f2e58b2 diff --git a/source/core/variant.h b/source/core/variant.h index 934a9e5..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(); @@ -61,9 +71,9 @@ public: const T &value() const { return const_cast(this)->get(); } template - bool has_type() const { return funcs==get_functions::type>(); } + bool has_type() const { return type_equals(funcs, get_functions::type>()); } - bool has_same_type(const Variant &v) const { return (funcs && funcs==v.funcs); } + bool has_same_type(const Variant &v) const { return type_equals(funcs, v.funcs); } template DEPRECATED bool check_type() const { return has_type(); } @@ -77,6 +87,8 @@ public: operator T() const { return value(); } private: + static bool type_equals(const Functions *, const Functions *); + template static constexpr bool is_small() { return (sizeof(T)<=INTERNAL_SIZE && alignof(T)<=alignof(void *)); } @@ -93,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 *) @@ -120,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(); } @@ -130,26 +150,36 @@ private: }; -template -inline void Variant::assign(const T &value) +inline void Variant::clear() { if(funcs) funcs->destroy(storage); + funcs = nullptr; +} - funcs = get_functions::type>(); - create(storage, value); +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() { @@ -162,6 +192,16 @@ inline T &Variant::get() return **reinterpret_cast(storage); } +inline bool Variant::type_equals(const Functions *funcs1, const Functions *funcs2) +{ + if(!funcs1 || !funcs2) + return false; + else if(funcs1==funcs2) + return true; + else + return funcs1->get_type()==funcs2->get_type(); +} + template inline const Variant::Functions *Variant::get_functions() { @@ -170,6 +210,7 @@ inline const Variant::Functions *Variant::get_functions() &get_type, &compare, &clone, + &move, &destroy }; return &funcs;