diff --git a/src/lib/variant.hpp b/src/lib/variant.hpp index 72e732e08..949cb508f 100644 --- a/src/lib/variant.hpp +++ b/src/lib/variant.hpp @@ -77,10 +77,16 @@ namespace lib { namespace error = lumiera::error; + template + class Variant; + namespace { // implementation helpers using std::is_constructible; using std::remove_reference; + using std::remove_const; + using std::is_same; + using std::enable_if; using meta::NullType; using meta::Node; @@ -111,6 +117,168 @@ namespace lib { }; + template + struct Bare + { + using Type = typename remove_const< + typename remove_reference::type>::type; + }; + + template + struct is_Variant + { + static constexpr bool value = false; + }; + + template + struct is_Variant> + { + static constexpr bool value = true; + }; + + template + struct use_if_is_Variant + : enable_if::Type>::value, V> + { }; + + + template + class FullCopySupport + : public B + { + virtual void + copyInto (void* targetStorage) const override + { + D const& src = static_cast (*this); + new(targetStorage) D(src); + } + + virtual void + moveInto (void* targetStorage) override + { + D& src = static_cast (*this); + new(targetStorage) D(move(src)); + } + + virtual void + copyInto (B& target) const override + { + D& t = D::downcast(target); + D const& s = static_cast (*this); + t = s; + } + + virtual void + moveInto (B& target) override + { + D& t = D::downcast(target); + D& s = static_cast (*this); + t = move(s); + } + }; + + + template + class CloneSupport + : public B + { + virtual void + copyInto (void* targetStorage) const override + { + D const& src = static_cast (*this); + new(targetStorage) D(src); + } + + virtual void + moveInto (void* targetStorage) override + { + D& src = static_cast (*this); + new(targetStorage) D(move(src)); + } + + virtual void + copyInto (B& target) const override + { + throw error::Logic("Assignment invoked but target is not assignable"); + } + + virtual void + moveInto (B& target) override + { + throw error::Logic("Assignment invoked but target is not assignable"); + } + }; + + + template + class MoveSupport + : public B + { + virtual void + copyInto (void* targetStorage) const override + { + throw error::Logic("Copy construction invoked but target allows only move construction"); + } + + virtual void + moveInto (void* targetStorage) override + { + D& src = static_cast (*this); + new(targetStorage) D(move(src)); + } + + virtual void + copyInto (B& target) const override + { + throw error::Logic("Assignment invoked but target is not assignable"); + } + + virtual void + moveInto (B& target) override + { + throw error::Logic("Assignment invoked but target is not assignable"); + } + }; + + + template + class NoCopyMoveSupport + : public B + { + virtual void + copyInto (void* targetStorage) const override + { + throw error::Logic("Copy construction invoked but target is noncopyable"); + } + + virtual void + moveInto (void* targetStorage) override + { + throw error::Logic("Move construction invoked but target is noncopyable"); + } + + virtual void + copyInto (B& target) const override + { + throw error::Logic("Assignment invoked but target is not assignable"); + } + + virtual void + moveInto (B& target) override + { + throw error::Logic("Assignment invoked but target is not assignable"); + } + }; + + + template + struct CopySupport + { + template + using Policy = NoCopyMoveSupport; + }; + + }//(End) implementation helpers @@ -142,8 +310,11 @@ namespace lib { virtual ~Buffer() {} ///< this is an ABC with VTable virtual void copyInto (void* targetStorage) const =0; - virtual void operator= (Buffer const&) =0; - virtual void operator= (Buffer&&) =0; + virtual void moveInto (void* targetStorage) =0; + virtual void copyInto (Buffer& target) const =0; + virtual void moveInto (Buffer& target) =0; +// virtual void operator= (Buffer const&) =0; +// virtual void operator= (Buffer&&) =0; }; @@ -151,7 +322,7 @@ namespace lib { /** concrete inner capsule specialised for a given type */ template struct Buff - : Buffer + : CopySupport::template Policy> { static_assert (SIZ >= sizeof(TY), "Variant record: insufficient embedded Buffer size"); @@ -210,17 +381,17 @@ namespace lib { new(targetStorage) Buff(this->access()); } - virtual void - operator= (Buffer const& ob) override - { - assignValue (downcast(unConst(ob)).access()); - } - - virtual void - operator= (Buffer&& rref) override - { - assignValue (move (downcast(rref).access())); - } +// virtual void +// operator= (Buffer const& ob) override +// { +// assignValue (downcast(unConst(ob)).access()); +// } +// +// virtual void +// operator= (Buffer&& rref) override +// { +// assignValue (move (downcast(rref).access())); +// } static Buff& downcast (Buffer& b) @@ -246,6 +417,36 @@ namespace lib { + template + struct Assign + { + using RawType = typename remove_reference::type; + static_assert (meta::isInList(), + "Type error: the given variant could never hold the required type"); + + + static void + assign (Buffer& buffer, X&& x) + { + buff().assignValue (forward(x)); + } + + + }; + + template + struct Assign::type> + { + + static void + assign (Buffer& buffer, V&& oVar) + { +// oVar.buffer() +// buff().assignValue (forward(oVar)); + } + }; + + protected: /* === internal interface for managing the storage === */ Buffer& @@ -268,6 +469,11 @@ namespace lib { public: + ~Variant() + { + buffer().~Buffer(); + } + Variant() { using DefaultType = typename TYPES::List::Head; @@ -300,16 +506,18 @@ namespace lib { template Variant& - operator= (X&& x) + operator= (X x) { - using RawType = typename remove_reference::type; - static_assert (meta::isInList(), - "Type error: the given variant could never hold the required type"); +// using RawType = typename remove_reference::type; +// static_assert (meta::isInList(), +// "Type error: the given variant could never hold the required type"); +// +// buff().assignValue (forward(x)); - buff().assignValue (forward(x)); + Assign::assign (this->buffer(), forward (x)); return *this; } - +/* Variant& operator= (Variant& ovar) { @@ -330,7 +538,7 @@ namespace lib { buffer().operator= (move(rvar.buffer())); return *this; } - + */ #ifdef LIB_TEST_TEST_HELPER_H /* == diagnostic helper == */