memgraph/poc/isolation/header.hpp
Kruno Tomola Fabro 77a3298d1e tmp
2016-08-28 15:47:13 +01:00

156 lines
4.1 KiB
C++

#pragma once
// All fake types should be defined here as a interface.
#include <cassert>
#include <type_traits>
#include <utility>
namespace sha
{
template <class TO, class FROM>
TO value_as(FROM &&ref)
{
return std::move((*reinterpret_cast<TO *>(&ref)));
}
// Sized
class Name;
class Db;
// Unsized
class Accessor;
// Marks types which will be passed only be ref/pointer.
class Unsized
{
public:
// This will assure that this class/derived classes can't be instantiated,
// copyed or moved.
// This way the other side can't "accidentaly" create/copy/move or destroy
// this type because that would be errornus.
Unsized() = delete;
Unsized(const Unsized &other) = delete;
Unsized(Unsized &&other) = delete;
~Unsized() = delete;
Unsized &operator=(const Unsized &other) = delete;
Unsized &operator=(Unsized &&other) = delete;
protected:
template <class T>
T &as()
{
return (*reinterpret_cast<T *>(this));
}
template <class T>
const T &as() const
{
return (*reinterpret_cast<const T *>(this));
}
};
// Every type which will be passed by value must extends this class.
template <std::size_t size_B, std::size_t alignment_B>
class Sized
{
public:
// This will assure that this/derived class can't be instantiated.
// This way if other side can't "accidentaly" create this/derived type
// because that would be errornus.
Sized() = delete;
// This constructr also serves as a check for correctness of size and
// aligment.
Sized(std::size_t _size_B, std::size_t _alignment_B)
{
assert(size_B == _size_B);
assert(alignment_B == _alignment_B);
}
// This constructr also serves as a check for correctness of size and
// aligment.
template <class T>
Sized(T &&d)
: data(value_as<
typename std::aligned_storage<size_B, alignment_B>::type>(
std::move(d)))
{
static_assert(size_B == sizeof(T), "Border class size mismatch");
static_assert(alignment_B == alignof(T),
"Border class aligment mismatch");
}
protected:
template <class T>
T &as()
{
return (*reinterpret_cast<T *>(&data));
}
template <class T>
const T &as() const
{
return (*reinterpret_cast<const T *>(&data));
}
private:
// Here the first argument for template is size of struct in bytes. While
// the second one is aligment of struct in bytes. Every class which will be
// passed by value must have this kind of aligned storage with correct size
// and aligment for that type. Unit tests to check this must be present.
// Example would be:
// std::aligned_storage<sizeof(std::set<int>), alignof(std::set<int>)>
// While the resoults of sizeof and alignof would be passed as template
// argumetns.
// This values would be checked in tests like the following for example
// above:
// assert(sizeof(Accessor)==sizeof(std::set<int>));
// assert(alignof(Accessor)==alignof(std::set<int>));
typename std::aligned_storage<size_B, alignment_B>::type data;
};
// Type which will be passed by value so it's real size matters.
class Accessor : private Sized<16, 8>
{
// The only border classes which can create this class.
friend Db;
private:
// The only valid concstructor for original class
template <class T>
Accessor(T &&d) : Sized(std::move(d))
{
}
public:
// If the underlying type can't be copyed or moved this two constructors
// would be deleted.
Accessor(const Accessor &other);
Accessor(Accessor &&other);
~Accessor();
// If the underlying type can't be copyed or moved this two operators
// would be deleted.
Accessor &operator=(const Accessor &other);
Accessor &operator=(Accessor &&other);
int get_prop(Name &name);
};
// Type which will be passed by ref/pointer only so it's size doesnt matter.
class Name : private Unsized
{
};
// Type which will be passed by ref/pointer only so it's size doesnt matter.
class Db : private Unsized
{
public:
Accessor access();
Name &get_name(const char *str);
};
}