WIP: first round of implementation

finally got all those copy / assgnment flavours straight.

Still unsolved: unable to instantiate the Variant template
for a type with private assignment operator (like e.g. Time )
The problem is our virtual assignement operator, which forces
instantiation of the implementation (for the VTable), even if
the actual assignment is never invoked.
This commit is contained in:
Fischlurch 2015-04-17 19:33:25 +02:00
parent 8794aec35a
commit c32685ada8
2 changed files with 185 additions and 56 deletions

View file

@ -61,6 +61,7 @@
//#include "lib/util.hpp"
#include <type_traits>
#include <typeindex>
//#include <utility>
//#include <string>
//#include <array>
@ -68,12 +69,49 @@
namespace lib {
using std::move;
using std::string;
using std::move;
using std::forward;
using util::unConst;
namespace error = lumiera::error;
using error::LUMIERA_ERROR_WRONG_TYPE;
namespace { // implementation helpers
using std::is_constructible;
using std::remove_reference;
using meta::NullType;
using meta::Node;
template<typename X, typename TYPES>
struct CanBuildFrom
: CanBuildFrom<typename remove_reference<X>::type
,typename TYPES::List
>
{ };
template<typename X, typename TYPES>
struct CanBuildFrom<X, Node<X, TYPES>>
{
using Type = X;
};
template<typename X, typename T,typename TYPES>
struct CanBuildFrom<X, Node<T, TYPES>>
{
using Type = typename CanBuildFrom<X,TYPES>::Type;
};
template<typename X>
struct CanBuildFrom<X, NullType>
{
static_assert (0 > sizeof(X), "No type in Typelist can be built from the given argument");
};
}//(End) implementation helpers
/**
@ -104,6 +142,9 @@ 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;
};
@ -115,14 +156,14 @@ namespace lib {
static_assert (SIZ >= sizeof(TY), "Variant record: insufficient embedded Buffer size");
TY&
get() const ///< core operation: target is contained within the inline buffer
access() const ///< core operation: target is contained within the inline buffer
{
return *reinterpret_cast<TY*> (unConst(this)->ptr());
}
~Buff()
{
get().~TY();
access().~TY();
}
Buff (TY const& obj)
@ -137,43 +178,28 @@ namespace lib {
Buff (Buff const& oBuff)
{
new(Buffer::ptr()) TY(oBuff.get());
new(Buffer::ptr()) TY(oBuff.access());
}
Buff (Buff && rBuff)
{
new(Buffer::ptr()) TY(move (rBuff.get()));
new(Buffer::ptr()) TY(move (rBuff.access()));
}
Buff&
operator= (TY const& obj)
void
assignValue (TY const& ob)
{
if (&obj != Buffer::ptr())
get() = obj;
return *this;
if (&ob != Buffer::ptr())
this->access() = ob;
}
Buff&
operator= (TY && robj)
void
assignValue (TY && rob)
{
get() = move(robj);
return *this;
this->access() = move(rob);
}
Buff&
operator= (Buff const& ref)
{
if (&ref != this)
get() = ref.get();
return *this;
}
Buff&
operator= (Buff && rref)
{
get() = move(rref.get());
return *this;
}
/* == virtual access functions == */
@ -181,7 +207,33 @@ namespace lib {
virtual void
copyInto (void* targetStorage) const override
{
new(targetStorage) Buff(get());
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()));
}
static Buff&
downcast (Buffer& b)
{
Buff* buff = dynamic_cast<Buff*> (&b);
if (!buff)
throw error::Logic("Variant type mismatch: "
"the given variant record does not hold "
"a value of the type requested here"
,error::LUMIERA_ERROR_WRONG_TYPE);
else
return *buff;
}
};
@ -192,22 +244,91 @@ namespace lib {
* @note Invariant: always contains a valid Buffer subclass */
char storage_[BUFFSIZE];
protected: /* === internal interface for managing the storage === */
Buffer&
buffer()
{
return *reinterpret_cast<Buffer*> (&storage_);
}
Buffer const&
buffer() const
{
return *reinterpret_cast<const Buffer*> (&storage_);
}
template<typename X>
Buff<X>&
buff()
{
return Buff<X>::downcast(this->buffer());
}
public:
Variant()
{
UNIMPLEMENTED("default constructed element of first type");
using DefaultType = typename TYPES::List::Head;
new(storage_) Buff<DefaultType> (DefaultType());
}
Variant (Variant& ref)
{
ref.buffer().copyInto (&storage_);
}
Variant (Variant const& ref)
{
ref.buffer().copyInto (&storage_);
}
Variant (Variant&& rref)
{
rref.buffer().copyInto (&storage_);
}
template<typename X>
Variant(X const& x)
Variant(X&& x)
{
UNIMPLEMENTED("place buffer to hold element of type X");
using StorageType = typename CanBuildFrom<X, TYPES>::Type;
new(storage_) Buff<StorageType> (forward<X>(x));
}
template<typename X>
Variant(X && x)
Variant&
operator= (X&& x)
{
UNIMPLEMENTED("place buffer and move element of type X");
using RawType = typename remove_reference<X>::type;
static_assert (meta::isInList<RawType, typename TYPES::List>(),
"Type error: the given variant could never hold the required type");
buff<RawType>().assignValue (forward<X>(x));
return *this;
}
Variant&
operator= (Variant& ovar)
{
buffer() = ovar.buffer();
return *this;
}
Variant&
operator= (Variant const& ovar)
{
buffer() = ovar.buffer();
return *this;
}
Variant&
operator= (Variant&& rvar)
{
buffer().operator= (move(rvar.buffer()));
return *this;
}
@ -226,7 +347,10 @@ namespace lib {
X&
get()
{
UNIMPLEMENTED("value access");
static_assert (meta::isInList<X, typename TYPES::List>(),
"Type error: the given variant could never hold the required type");
return buff<X>().access();
}

View file

@ -30,16 +30,12 @@
//#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
#include <iostream>
//#include <map>
//using boost::lexical_cast;
#include <vector>
//#include <vector>
using util::contains;
using std::string;
using std::cout;
using std::endl;
namespace lib {
@ -50,6 +46,14 @@ namespace test{
using lib::time::Time;
using lib::time::TimeVar;
using util::contains;
using std::string;
using std::cout;
using std::endl;
using error::LUMIERA_ERROR_WRONG_TYPE;
namespace { // test fixture...
}//(End) test fixture
@ -88,11 +92,12 @@ namespace test{
{
Time someTime;
TestVariant v0;
TestVariant v1(11);
TestVariant v2("lololo");
TestVariant v1(11L);
TestVariant v2(string("lololo"));
TestVariant v3(someTime);
VERIFY_ERROR (WRONG_TYPE, TestVariant(3.1415));
//// does not compile....
// TestVariant evil(3.1415);
cout << string(v0) <<endl
<< string(v1) <<endl
@ -126,7 +131,7 @@ namespace test{
TestVariant v3(someTime);
TestVariant v2(someStr);
TestVariant v1; v1 = someVal;
TestVariant v1 = int64_t(someVal);
TestVariant v0; v0 = true;
CHECK (true == v0.get<bool>() );
@ -150,10 +155,10 @@ namespace test{
VERIFY_ERROR (WRONG_TYPE, v3.get<int64_t>());
VERIFY_ERROR (WRONG_TYPE, v3.get<string>() );
// does not compile:
v0.get<long>();
v1.get<double>();
v3.get<TimeVar>();
//// does not compile...
// v0.get<int>();
// v1.get<double>();
// v3.get<TimeVar>();
struct Accessor
: TestVariant::Visitor
@ -208,20 +213,20 @@ namespace test{
void
verifyAssignment()
{
TestVariant v1("boo");
TestVariant v2(23);
TestVariant v3(42);
TestVariant v1(string("boo"));
TestVariant v2(23L);
TestVariant v3(42L);
v1 = "booo";
v1 = string("booo");
v2 = v3;
v3 = 24;
v3 = 24L;
CHECK ("booo" == v1.get<string>());
CHECK (42 == v2.get<int64_t>());
CHECK (24 == v3.get<int64_t>());
VERIFY_ERROR (WRONG_TYPE, v1 = v2 );
VERIFY_ERROR (WRONG_TYPE, v1 = 22 );
VERIFY_ERROR (WRONG_TYPE, v2 = "2");
VERIFY_ERROR (WRONG_TYPE, v1 = 22L );
VERIFY_ERROR (WRONG_TYPE, v2 = string("2"));
}
};