#pragma once // All fake types should be defined here as a interface. #include #include #include namespace sha { template TO value_as(FROM &&ref) { return std::move((*reinterpret_cast(&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 T &as() { return (*reinterpret_cast(this)); } template const T &as() const { return (*reinterpret_cast(this)); } }; // Every type which will be passed by value must extends this class. template 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 Sized(T &&d) : data(value_as< typename std::aligned_storage::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 T &as() { return (*reinterpret_cast(&data)); } template const T &as() const { return (*reinterpret_cast(&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), alignof(std::set)> // 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)); // assert(alignof(Accessor)==alignof(std::set)); typename std::aligned_storage::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 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); }; }