#include <type_traits>
#include <typeinfo>
#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 *);
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<typename T>
+ using EnableNotVariant = typename std::enable_if<!std::is_same<typename std::remove_cv<typename std::remove_reference<T>::type>::type, Variant>::value>::type;
+
const Functions *funcs = nullptr;
alignas(void *) char storage[INTERNAL_SIZE];
public:
Variant() = default;
- template<typename T>
- Variant(const T &v) { assign(v); }
+ template<typename T, typename = EnableNotVariant<T>>
+ Variant(T &&v) { assign(std::forward<T>(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<typename T>
- Variant &operator=(const T &v) { assign(v); return *this; }
+ template<typename T, typename = EnableNotVariant<T>>
+ Variant &operator=(T &&v) { assign(std::forward<T>(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<typename T>
- void assign(const T &);
+ void assign(T &&);
void copy_from(const Variant &);
+ void move_from(Variant &&);
template<typename T>
T &get();
const T &value() const { return const_cast<Variant *>(this)->get<T>(); }
template<typename T>
- bool has_type() const { return funcs==get_functions<typename std::remove_cv<T>::type>(); }
+ bool has_type() const { return type_equals(funcs, get_functions<typename std::remove_cv<T>::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<typename T>
DEPRECATED bool check_type() const { return has_type<T>(); }
operator T() const { return value<T>(); }
private:
+ static bool type_equals(const Functions *, const Functions *);
+
template<typename T>
static constexpr bool is_small() { return (sizeof(T)<=INTERNAL_SIZE && alignof(T)<=alignof(void *)); }
static const std::type_info &get_type() { return typeid(T); }
template<typename T>
- static EnableSmall<T, void> create(char *s, const T &v)
- { new(s) T(v); }
+ static EnableSmall<T, void> create(char *s, T &&v)
+ { new(s) typename std::remove_reference<T>::type(std::forward<T>(v)); }
template<typename T>
- static EnableLarge<T, void> create(char *s, const T &v)
- { *reinterpret_cast<T **>(s) = new T(v); }
+ static EnableLarge<T, void> create(char *s, T &&v)
+ { using V = typename std::remove_reference<T>::type; *reinterpret_cast<V **>(s) = new V(std::forward<T>(v)); }
template<typename T>
static typename std::enable_if<!IsEqualityComparable<T>::value, bool>::type compare(const char *, const char *)
static EnableLarge<T, void> clone(char *s, const char *v)
{ *reinterpret_cast<T **>(s) = new T(**reinterpret_cast<const T *const *>(v)); }
+ template<typename T>
+ static EnableSmall<T, void> move(char *s, char *v)
+ { new(s) T(std::move(*reinterpret_cast<T *>(v))); }
+
+ template<typename T>
+ static EnableLarge<T, void> move(char *s, char *v)
+ { T *&p = *reinterpret_cast<T **>(v); *reinterpret_cast<T **>(s) = p; p = nullptr; }
+
template<typename T>
static EnableSmall<T, void> destroy(char *s)
{ reinterpret_cast<T *>(s)->~T(); }
};
-template<typename T>
-inline void Variant::assign(const T &v)
+inline void Variant::clear()
{
if(funcs)
funcs->destroy(storage);
+ funcs = nullptr;
+}
- funcs = get_functions<typename std::remove_cv<T>::type>();
- create(storage, v);
+template<typename T>
+inline void Variant::assign(T &&v)
+{
+ clear();
+ funcs = get_functions<typename std::remove_cv<typename std::remove_reference<T>::type>::type>();
+ create(storage, std::forward<T>(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<typename T>
inline T &Variant::get()
{
return **reinterpret_cast<T **>(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<typename T>
inline const Variant::Functions *Variant::get_functions()
{
&get_type<T>,
&compare<T>,
&clone<T>,
+ &move<T>,
&destroy<T>
};
return &funcs;