diff --git a/dbzero/dbzero/dbzero.pyi b/dbzero/dbzero/dbzero.pyi index 2c5bc1a2..ce20f76c 100644 --- a/dbzero/dbzero/dbzero.pyi +++ b/dbzero/dbzero/dbzero.pyi @@ -11,48 +11,6 @@ from .interfaces import ( # Core workspace management functions -def init(path: str, config: Optional[Dict[str, Any]] = None, lock_flags: Optional[Dict[str, Any]] = None) -> None: - """Initialize the dbzero environment in a specified directory and apply global configurations. - - This function sets up the underlying state management engine. - It must be called once per process before interacting with any data. - If you need to switch to a different working directory, you should first call - dbzero.close() and then dbzero.init() again with the new path. - - Parameters - ---------- - path : str - The path to the data files directory. If the directory doesn't exist, - it will be created. - config : dict, optional - Dictionary to override default configuration settings: - - * autocommit (bool, default True) to enable automatic commits - * autocommit_interval (int, default 250) for commit interval in milliseconds - * cache_size (int, default 2 GiB) for main object cache size in bytes - * lang_cache_size (int, optional) for language model data cache size - lock_flags : dict, optional - Dictionary with configuration of locking behavior when opening the prefix in read-write mode. - - * blocking (bool, default False) to wait when trying to acquire the lock - * timeout (int) to set maximum waiting time in seconds when blocking wait is enabled - * force_unlock (bool, default False) to force unlocking of existing lock - - - Examples - -------- - Basic initialization: - - >>> import dbzero - >>> dbzero.init("/tmp/my-app-db") - - With custom configuration: - - >>> config = {"autocommit": False, "cache_size": 1 << 30} - >>> dbzero.init("/tmp/my-app-db", config=config) - """ - ... - def open(prefix_name: str, open_mode: str = "rw", **kwargs: Any) -> None: """Open a data prefix and set it as the current working context. @@ -951,7 +909,7 @@ def find(*query_criteria: Union[Tag, List[Tag], Tuple[Tag], QueryObject, TagSet] * List of tags (OR): Objects with at least one of the specified tags * Tuple of tags (AND): Objects with all of the specified tags * Query: Result of another query - * TagSet: Logical set operation. + * TagSet: Set logical operation. prefix : str, optional Optional data prefix to run the query on. If omitted, the prefix to run the query is resolved from query criteria. diff --git a/src/dbzero/core/collections/b_index/bindex_types.hpp b/src/dbzero/core/collections/b_index/bindex_types.hpp index 41fb1f35..c3ed0273 100644 --- a/src/dbzero/core/collections/b_index/bindex_types.hpp +++ b/src/dbzero/core/collections/b_index/bindex_types.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -124,7 +125,7 @@ DB0_PACKED_END using node_stack = typename bindex_tree_t::join_stack; DB0_PACKED_BEGIN - class DB0_PACKED_ATTR bindex_container : public o_fixed + class DB0_PACKED_ATTR bindex_container : public o_fixed_versioned { public : // common dbzero object header (not copied) diff --git a/src/dbzero/core/collections/pools/RC_LimitedPool.hpp b/src/dbzero/core/collections/pools/RC_LimitedPool.hpp index 2c49a679..515fa071 100644 --- a/src/dbzero/core/collections/pools/RC_LimitedPool.hpp +++ b/src/dbzero/core/collections/pools/RC_LimitedPool.hpp @@ -1,6 +1,7 @@ #pragma once #include "LimitedPool.hpp" +#include #include #include #include @@ -11,7 +12,7 @@ namespace db0::pools { DB0_PACKED_BEGIN - struct DB0_PACKED_ATTR o_rc_limited_pool: public o_fixed + struct DB0_PACKED_ATTR o_rc_limited_pool: public o_fixed_versioned { Address m_pool_map_address = {}; diff --git a/src/dbzero/core/collections/range_tree/IndexBase.hpp b/src/dbzero/core/collections/range_tree/IndexBase.hpp index 00a7ac5d..053a3db8 100644 --- a/src/dbzero/core/collections/range_tree/IndexBase.hpp +++ b/src/dbzero/core/collections/range_tree/IndexBase.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -29,7 +30,7 @@ namespace db0 }; DB0_PACKED_BEGIN - struct DB0_PACKED_ATTR o_index: public o_fixed + struct DB0_PACKED_ATTR o_index: public o_fixed_versioned { // common object header o_unique_header m_header; @@ -37,7 +38,6 @@ DB0_PACKED_BEGIN IndexDataType m_data_type = IndexDataType::Auto; // address of the actual index instance Address m_index_addr = {}; - std::array m_reserved = {0, 0}; o_index(IndexType, IndexDataType); // header not copied diff --git a/src/dbzero/core/collections/range_tree/RangeTree.hpp b/src/dbzero/core/collections/range_tree/RangeTree.hpp index 63f9ca82..54c97a5a 100644 --- a/src/dbzero/core/collections/range_tree/RangeTree.hpp +++ b/src/dbzero/core/collections/range_tree/RangeTree.hpp @@ -5,6 +5,7 @@ #include #include "RangeTreeBlock.hpp" #include "RT_NullBlock.hpp" +#include #include #include #include @@ -51,7 +52,7 @@ DB0_PACKED_BEGIN DB0_PACKED_END DB0_PACKED_BEGIN - struct DB0_PACKED_ATTR o_range_tree: public o_fixed + struct DB0_PACKED_ATTR o_range_tree: public o_fixed_versioned { std::uint32_t m_max_block_size; // address of the underlying v_bindex diff --git a/src/dbzero/core/collections/vector/VLimitedMatrix.hpp b/src/dbzero/core/collections/vector/VLimitedMatrix.hpp index df6db853..b1a1b43f 100644 --- a/src/dbzero/core/collections/vector/VLimitedMatrix.hpp +++ b/src/dbzero/core/collections/vector/VLimitedMatrix.hpp @@ -2,6 +2,7 @@ #include "v_bvector.hpp" #include "v_sorted_vector.hpp" +#include #include #include #include @@ -14,7 +15,7 @@ namespace db0 template DB0_PACKED_BEGIN - struct DB0_PACKED_ATTR o_limited_matrix: public o_fixed > + struct DB0_PACKED_ATTR o_limited_matrix: public o_fixed_versioned > { // Points to v_bvector representing the entire Dimension 1 PtrT m_dim1_ptr = {}; diff --git a/src/dbzero/core/collections/vector/v_bvector.hpp b/src/dbzero/core/collections/vector/v_bvector.hpp index 401a46a1..ebdebd0a 100644 --- a/src/dbzero/core/collections/vector/v_bvector.hpp +++ b/src/dbzero/core/collections/vector/v_bvector.hpp @@ -6,6 +6,7 @@ #include #include #include "v_bdata_block.hpp" +#include #include #include #include @@ -18,7 +19,7 @@ namespace db0 DB0_PACKED_BEGIN template - struct DB0_PACKED_ATTR o_bvector: public o_fixed > + struct DB0_PACKED_ATTR o_bvector: public o_fixed_versioned > { // common dbzero object header db0::o_unique_header m_header; diff --git a/src/dbzero/core/memory/MetaAllocator.hpp b/src/dbzero/core/memory/MetaAllocator.hpp index a8a42c74..f0e76119 100644 --- a/src/dbzero/core/memory/MetaAllocator.hpp +++ b/src/dbzero/core/memory/MetaAllocator.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -20,7 +21,7 @@ namespace db0 class SlabManager; DB0_PACKED_BEGIN - struct DB0_PACKED_ATTR o_realm: public o_fixed + struct DB0_PACKED_ATTR o_realm: public o_fixed_versioned { Address m_slab_defs_ptr; Address m_capacity_items_ptr; @@ -31,7 +32,7 @@ DB0_PACKED_BEGIN DB0_PACKED_END DB0_PACKED_BEGIN - struct DB0_PACKED_ATTR o_meta_header: public o_fixed + struct DB0_PACKED_ATTR o_meta_header: public o_fixed_versioned { // NOTE: when needed, this values can be changed to 4 (or 8?) or 1 (no realms) static constexpr std::size_t NUM_REALMS = 2; diff --git a/src/dbzero/core/serialization/Base.hpp b/src/dbzero/core/serialization/Base.hpp index 76fe5c31..fa2035a7 100644 --- a/src/dbzero/core/serialization/Base.hpp +++ b/src/dbzero/core/serialization/Base.hpp @@ -33,6 +33,9 @@ DB0_PACKED_BEGIN std::uint16_t objVer() const { return 0; } + template static std::uint16_t objVer(buf_t at) { + return 0; + } }; template @@ -52,6 +55,9 @@ DB0_PACKED_BEGIN std::uint16_t objVer() const { return storedVersion; } + template static std::uint16_t objVer(buf_t at) { + return reinterpret_cast((const std::byte*)(at))->objVer(); + } }; template @@ -135,9 +141,7 @@ DB0_PACKED_BEGIN } template static Foundation::SafeSize sizeOfMembers(buf_t at) { - return Foundation::sizeOfMembers( - baseSize(), at, reinterpret_cast((const std::byte*)(at))->objVer() - ); + return Foundation::sizeOfMembers(baseSize(), at, getObjVer(at)); } Foundation::SafeSize sizeOfMembers() const @@ -258,11 +262,18 @@ DB0_PACKED_BEGIN return ver_type::implVer(); } + template static std::uint16_t getObjVer(buf_t at) { + return ver_type::objVer(at); + } + std::uint16_t getObjVer() const { return ver_type::objVer(); } static inline T &__ref(void *buf) { +#ifndef NDEBUG + reinterpret_cast(buf)->assertImplVersion(); +#endif return *reinterpret_cast(buf); } diff --git a/src/dbzero/core/serialization/Ext.hpp b/src/dbzero/core/serialization/Ext.hpp index 28c2fcff..8bb7c44d 100644 --- a/src/dbzero/core/serialization/Ext.hpp +++ b/src/dbzero/core/serialization/Ext.hpp @@ -65,7 +65,7 @@ DB0_PACKED_BEGIN template < typename T, typename super_t, - std::uint16_t VER=0, bool STORE_VER=false + std::uint16_t VER=0, bool STORE_VER=true > class DB0_PACKED_ATTR o_ext : public super_t{ using this_type = o_ext; @@ -236,7 +236,7 @@ DB0_PACKED_BEGIN // measures space requirement of the base overlaid type // plus size of all fixed size members of derived type - template static Meter measureBase(Args&& ...args) + template static std::size_t measureBase(Args&& ...args) { std::size_t result = super_t::measure(std::forward(args)...); // adjust for fixed size members in derived class diff --git a/src/dbzero/core/serialization/FixedVersioned.hpp b/src/dbzero/core/serialization/FixedVersioned.hpp new file mode 100644 index 00000000..5648056d --- /dev/null +++ b/src/dbzero/core/serialization/FixedVersioned.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +namespace db0 +{ + +DB0_PACKED_BEGIN + +template +class DB0_PACKED_ATTR o_fixed_versioned : private version_base, public o_fixed { + typedef version_base ver_type; + +public: + using o_fixed::o_fixed; + + static constexpr bool getIsVerStored() { + return ver_type::isVerStored(); + } + + static constexpr std::uint16_t getImplVer() { + return ver_type::implVer(); + } + + template static std::uint16_t getObjVer(buf_t at) { + return ver_type::objVer(at); + } + + std::uint16_t getObjVer() const { + return ver_type::objVer(); + } +}; + +DB0_PACKED_END + +} diff --git a/src/dbzero/core/serialization/micro_array.hpp b/src/dbzero/core/serialization/micro_array.hpp index 03226dc7..375b1896 100644 --- a/src/dbzero/core/serialization/micro_array.hpp +++ b/src/dbzero/core/serialization/micro_array.hpp @@ -97,7 +97,7 @@ DB0_PACKED_BEGIN typename std::enable_if >::type getSizeAndOffset() const { std::pair result; - const std::byte *buf = (const std::byte*)this; + const std::byte *buf = this->beginOfDynamicArea(); result.first = packed_int32::read(buf); result.second = packed_int32::read(buf); return result; @@ -119,19 +119,19 @@ DB0_PACKED_BEGIN static std::size_t measure(const T *begin = nullptr, const T *end = nullptr, unsigned int offset = 0) { return measure(end - begin, offset); } - - std::size_t sizeOf() const; template static std::size_t safeSizeOf(BufT buf) { - auto start = buf; - auto size = packed_int32::__const_ref(buf).value(); - buf += packed_int32::safeSizeOf(buf); + std::size_t size; if constexpr (has_offset) { - buf += packed_int32::safeSizeOf(buf); + size = super_t::sizeOfMembers(buf) + (packed_int32::type()) + (packed_int32::type()); + } else { + size = super_t::sizeOfMembers(buf) + (packed_int32::type()); } - buf += size * sizeof(T); - return buf - start; + return size + super_t::__const_ref(buf).size() * sizeof(T); } inline T *begin() @@ -219,17 +219,6 @@ DB0_PACKED_BEGIN return measure(size, offset); } - template - std::size_t o_micro_array::sizeOf() const - { - auto result = packed_size().sizeOf(); - if constexpr (has_offset) { - result += packed_offset().sizeOf(); - } - result += packed_size().value() * sizeof(T); - return result; - } - template std::size_t o_micro_array::size() const { return packed_size().value(); diff --git a/src/dbzero/core/storage/BDevStorage.hpp b/src/dbzero/core/storage/BDevStorage.hpp index cf39a1a4..30d0b1f7 100644 --- a/src/dbzero/core/storage/BDevStorage.hpp +++ b/src/dbzero/core/storage/BDevStorage.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include "SparseIndex.hpp" #include "SparsePair.hpp" #include "CFile.hpp" @@ -22,7 +23,7 @@ namespace db0 { DB0_PACKED_BEGIN - struct DB0_PACKED_ATTR o_prefix_config: public o_fixed + struct DB0_PACKED_ATTR o_prefix_config: public o_fixed_versioned { // magic number for the .db0 file static constexpr std::uint64_t DB0_MAGIC = 0x0DB0DB0DB0DB0DB0; diff --git a/src/dbzero/core/storage/MetaIOStream.hpp b/src/dbzero/core/storage/MetaIOStream.hpp index 1312b117..c211c1d1 100644 --- a/src/dbzero/core/storage/MetaIOStream.hpp +++ b/src/dbzero/core/storage/MetaIOStream.hpp @@ -22,10 +22,10 @@ DB0_PACKED_BEGIN }; // The single log item, possibly associated with multiple managed streams - class DB0_PACKED_ATTR o_meta_log: public o_base + class DB0_PACKED_ATTR o_meta_log: public o_base { protected: - friend class o_base; + friend class o_base; o_meta_log(StateNumType state_num, const std::vector &); @@ -39,10 +39,8 @@ DB0_PACKED_BEGIN template static std::size_t safeSizeOf(T buf) { - auto _buf = buf; - buf += o_simple::__const_ref(buf).sizeOf(); - buf += o_list::safeSizeOf(buf); - return buf - _buf; + return sizeOfMembers(buf) + (o_list::type()); } }; diff --git a/src/dbzero/core/storage/SparseIndexBase.hpp b/src/dbzero/core/storage/SparseIndexBase.hpp index 9fe29183..440b6106 100644 --- a/src/dbzero/core/storage/SparseIndexBase.hpp +++ b/src/dbzero/core/storage/SparseIndexBase.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -125,7 +126,7 @@ DB0_PACKED_BEGIN }; // tree-level header type - struct DB0_PACKED_ATTR o_sparse_index_header: o_fixed + struct DB0_PACKED_ATTR o_sparse_index_header: o_fixed_versioned { PageNumT m_next_page_num = 0; StateNumT m_max_state_num = 0; diff --git a/src/dbzero/object_model/CommonBase.hpp b/src/dbzero/object_model/CommonBase.hpp index d6a33470..4c74eab6 100644 --- a/src/dbzero/object_model/CommonBase.hpp +++ b/src/dbzero/object_model/CommonBase.hpp @@ -9,7 +9,7 @@ namespace db0::object_model DB0_PACKED_BEGIN - class DB0_PACKED_ATTR o_common_base: public db0::o_base + class DB0_PACKED_ATTR o_common_base: public db0::o_base { public: // common object header diff --git a/src/dbzero/object_model/class/Class.hpp b/src/dbzero/object_model/class/Class.hpp index 300d0525..77b09de7 100644 --- a/src/dbzero/object_model/class/Class.hpp +++ b/src/dbzero/object_model/class/Class.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -57,7 +58,7 @@ namespace db0::object_model using VFidelityVector = db0::v_bvector >; DB0_PACKED_BEGIN - struct DB0_PACKED_ATTR o_class: public db0::o_fixed + struct DB0_PACKED_ATTR o_class: public db0::o_fixed_versioned { // common object header db0::o_object_header m_header; @@ -76,8 +77,6 @@ DB0_PACKED_BEGIN UniqueAddress m_singleton_address = {}; const std::uint32_t m_base_class_ref; const std::uint32_t m_num_bases; - // unused, reserved for future purposes - std::array m_reserved = {0, 0, 0, 0}; o_class(RC_LimitedStringPool &, const std::string &name, std::optional module_name, const VFieldMatrix &, const VFidelityVector &, const Schema &, const char *type_id, const char *prefix_name, ClassFlags, diff --git a/src/dbzero/object_model/class/ClassFactory.hpp b/src/dbzero/object_model/class/ClassFactory.hpp index b4f3598a..c570a7df 100644 --- a/src/dbzero/object_model/class/ClassFactory.hpp +++ b/src/dbzero/object_model/class/ClassFactory.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -26,7 +27,7 @@ DB0_PACKED_BEGIN using namespace db0; using namespace db0::pools; - struct DB0_PACKED_ATTR o_class_factory: public o_fixed + struct DB0_PACKED_ATTR o_class_factory: public o_fixed_versioned { // 4 variants of class identification db0::db0_ptr m_class_map_ptrs[4]; diff --git a/src/dbzero/object_model/class/Field.hpp b/src/dbzero/object_model/class/Field.hpp index 2ab8f87a..19d3d56d 100644 --- a/src/dbzero/object_model/class/Field.hpp +++ b/src/dbzero/object_model/class/Field.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -22,7 +23,7 @@ namespace db0::object_model DB0_PACKED_BEGIN - struct DB0_PACKED_ATTR o_field: public db0::o_fixed + struct DB0_PACKED_ATTR o_field: public db0::o_fixed_versioned { LP_String m_name; diff --git a/src/dbzero/object_model/class/Schema.hpp b/src/dbzero/object_model/class/Schema.hpp index 39064cef..0905415b 100644 --- a/src/dbzero/object_model/class/Schema.hpp +++ b/src/dbzero/object_model/class/Schema.hpp @@ -2,6 +2,7 @@ #include "FieldID.hpp" #include +#include #include #include #include @@ -59,7 +60,7 @@ DB0_PACKED_BEGIN db0::bindings::TypeId getTypeId(SchemaTypeId); std::string getTypeName(SchemaTypeId); - struct DB0_PACKED_ATTR o_type_item: public db0::o_fixed + struct DB0_PACKED_ATTR o_type_item: public db0::o_fixed_versioned { using FieldLoc = std::pair; SchemaTypeId m_type_id = SchemaTypeId::UNDEFINED; @@ -85,7 +86,7 @@ DB0_PACKED_BEGIN o_type_item &operator=(std::tuple); }; - struct DB0_PACKED_ATTR o_schema: public db0::o_fixed + struct DB0_PACKED_ATTR o_schema: public db0::o_fixed_versioned { using TypeVector = db0::v_sorted_vector; using total_func = std::function; diff --git a/src/dbzero/object_model/dict/Dict.hpp b/src/dbzero/object_model/dict/Dict.hpp index 991cc576..8c007ecf 100644 --- a/src/dbzero/object_model/dict/Dict.hpp +++ b/src/dbzero/object_model/dict/Dict.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -30,7 +31,7 @@ namespace db0::object_model class DictIterator; DB0_PACKED_BEGIN - struct DB0_PACKED_ATTR o_dict: public db0::o_fixed + struct DB0_PACKED_ATTR o_dict: public db0::o_fixed_versioned { // common object header o_unique_header m_header; diff --git a/src/dbzero/object_model/enum/Enum.hpp b/src/dbzero/object_model/enum/Enum.hpp index 8fa9aacb..bd338257 100644 --- a/src/dbzero/object_model/enum/Enum.hpp +++ b/src/dbzero/object_model/enum/Enum.hpp @@ -2,6 +2,7 @@ #include "EnumValue.hpp" #include "EnumDef.hpp" +#include #include #include #include @@ -21,7 +22,7 @@ DB0_PACKED_BEGIN using namespace db0::pools; using LP_String = db0::LP_String; - struct DB0_PACKED_ATTR o_enum: public o_fixed + struct DB0_PACKED_ATTR o_enum: public o_fixed_versioned { db0::o_object_header m_header; // enum type name diff --git a/src/dbzero/object_model/enum/EnumDef.hpp b/src/dbzero/object_model/enum/EnumDef.hpp index 9c49a7d0..c30d23c9 100644 --- a/src/dbzero/object_model/enum/EnumDef.hpp +++ b/src/dbzero/object_model/enum/EnumDef.hpp @@ -46,11 +46,11 @@ DB0_PACKED_BEGIN void serialize(std::vector &buffer) const; }; - class DB0_PACKED_ATTR o_enum_def: public db0::o_base + class DB0_PACKED_ATTR o_enum_def: public db0::o_base { protected: using self = o_enum_def; - using super_t = db0::o_base; + using super_t = db0::o_base; using o_string = db0::o_string; friend super_t; diff --git a/src/dbzero/object_model/enum/EnumFactory.hpp b/src/dbzero/object_model/enum/EnumFactory.hpp index b3973913..d75a8248 100644 --- a/src/dbzero/object_model/enum/EnumFactory.hpp +++ b/src/dbzero/object_model/enum/EnumFactory.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -19,7 +20,7 @@ DB0_PACKED_BEGIN using EnumPtr = db0::db0_ptr; using VEnumMap = db0::v_map; - struct DB0_PACKED_ATTR o_enum_factory: public o_fixed + struct DB0_PACKED_ATTR o_enum_factory: public o_fixed_versioned { // 4 variants of enum identification db0::db0_ptr m_enum_map_ptrs[4]; diff --git a/src/dbzero/object_model/enum/EnumValue.hpp b/src/dbzero/object_model/enum/EnumValue.hpp index 01e5fbbb..2260907f 100644 --- a/src/dbzero/object_model/enum/EnumValue.hpp +++ b/src/dbzero/object_model/enum/EnumValue.hpp @@ -29,11 +29,11 @@ namespace db0::object_model DB0_PACKED_BEGIN - class DB0_PACKED_ATTR o_enum_value_repr: public db0::o_base + class DB0_PACKED_ATTR o_enum_value_repr: public db0::o_base { protected: using self = o_enum_value_repr; - using super_t = db0::o_base; + using super_t = db0::o_base; friend super_t; o_enum_value_repr(const EnumDef &, const char *str_repr, const char *prefix_name = nullptr); @@ -127,10 +127,10 @@ DB0_PACKED_END DB0_PACKED_BEGIN - class DB0_PACKED_ATTR o_enum_value: public db0::o_base + class DB0_PACKED_ATTR o_enum_value: public db0::o_base { protected: - using super_t = db0::o_base; + using super_t = db0::o_base; friend super_t; o_enum_value(std::uint64_t fixture_uuid, std::uint32_t enum_uid, LP_String value, diff --git a/src/dbzero/object_model/object/ValueTable.cpp b/src/dbzero/object_model/object/ValueTable.cpp index 272680cb..5e0f4f61 100644 --- a/src/dbzero/object_model/object/ValueTable.cpp +++ b/src/dbzero/object_model/object/ValueTable.cpp @@ -29,13 +29,6 @@ namespace db0::object_model const o_unbound_array &PosVT::values() const { return getDynAfter(types(), o_unbound_array::type()); } - - std::size_t PosVT::sizeOf() const - { - return sizeOfMembers() - (TypesArrayT::type()) - (o_unbound_array::measure(this->size())); - } std::size_t PosVT::size() const { return types().size(); diff --git a/src/dbzero/object_model/object/ValueTable.hpp b/src/dbzero/object_model/object/ValueTable.hpp index cdcfdd73..eaac08ad 100644 --- a/src/dbzero/object_model/object/ValueTable.hpp +++ b/src/dbzero/object_model/object/ValueTable.hpp @@ -16,7 +16,7 @@ DB0_PACKED_BEGIN /** * Positionally-encoded value table */ - class DB0_PACKED_ATTR PosVT: public o_base + class DB0_PACKED_ATTR PosVT: public o_base { public: @@ -34,7 +34,7 @@ DB0_PACKED_BEGIN }; protected: - using super_t = o_base; + using super_t = o_base; friend super_t; // Create empty value table @@ -60,18 +60,15 @@ DB0_PACKED_BEGIN std::size_t size() const; unsigned int offset() const; - - std::size_t sizeOf() const; static std::size_t measure(const Data &, unsigned int offset); template static std::size_t safeSizeOf(BufT buf) { - auto start = buf; - auto size = TypesArrayT::__const_ref(buf).size(); - buf += TypesArrayT::safeSizeOf(buf); - buf += o_unbound_array::measure(size); - return buf - start; + std::size_t size = super_t::__const_ref(buf).size(); + return super_t::sizeOfMembers(buf) + (TypesArrayT::type()) + (o_unbound_array::measure(size)); } // Try finding element with a specific index @@ -91,10 +88,10 @@ DB0_PACKED_END * Indexed value table */ DB0_PACKED_BEGIN - class DB0_PACKED_ATTR IndexVT: public o_base + class DB0_PACKED_ATTR IndexVT: public o_base { protected: - using super_t = o_base; + using super_t = o_base; friend super_t; /** @@ -115,7 +112,8 @@ DB0_PACKED_BEGIN static std::size_t measure(const XValue *begin = nullptr, const XValue *end = nullptr); template static std::size_t safeSizeOf(BufT buf) { - return o_micro_array::safeSizeOf(buf); + return super_t::sizeOfMembers(buf) + (o_micro_array::type()); } /** diff --git a/src/dbzero/object_model/object/o_object.cpp b/src/dbzero/object_model/object/o_object.cpp index da425c6e..3770f0ea 100644 --- a/src/dbzero/object_model/object/o_object.cpp +++ b/src/dbzero/object_model/object/o_object.cpp @@ -25,6 +25,10 @@ namespace db0::object_model std::size_t o_object_base::measure() { return super_t::measureMembers(); } + + std::size_t o_object_base::measure(std::pair) { + return super_t::measureMembers(); + } o_object::o_object(std::uint32_t class_ref, std::pair ref_counts, std::uint8_t num_type_tags, const PosVT::Data &pos_vt_data, unsigned int pos_vt_offset, @@ -38,11 +42,11 @@ namespace db0::object_model (IndexVT::type(), index_vt_begin, index_vt_end); } - std::size_t o_object::measure(std::uint32_t class_ref, std::pair, std::uint8_t, + std::size_t o_object::measure(std::uint32_t class_ref, std::pair ref_counts, std::uint8_t, const PosVT::Data &pos_vt_data, unsigned int pos_vt_offset, const XValue *index_vt_begin, const XValue *index_vt_end) { - return super_t::measureBase() + return super_t::measureMembersFromBase(ref_counts) (PosVT::type(), pos_vt_data, pos_vt_offset) (packed_int32::type(), class_ref) (IndexVT::type(), index_vt_begin, index_vt_end); diff --git a/src/dbzero/object_model/object/o_object.hpp b/src/dbzero/object_model/object/o_object.hpp index 28bafd10..94def2d4 100644 --- a/src/dbzero/object_model/object/o_object.hpp +++ b/src/dbzero/object_model/object/o_object.hpp @@ -12,10 +12,10 @@ namespace db0::object_model { DB0_PACKED_BEGIN - class DB0_PACKED_ATTR o_object_base: public db0::o_base + class DB0_PACKED_ATTR o_object_base: public db0::o_base { protected: - using super_t = db0::o_base; + using super_t = db0::o_base; public: static constexpr unsigned char REALM_ID = 1; diff --git a/src/dbzero/object_model/object_header.hpp b/src/dbzero/object_model/object_header.hpp index 31a3ee7d..8a04ec24 100644 --- a/src/dbzero/object_model/object_header.hpp +++ b/src/dbzero/object_model/object_header.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -14,7 +15,7 @@ namespace db0 /// Common object header DB0_PACKED_BEGIN - struct DB0_PACKED_ATTR o_object_header: public o_fixed + struct DB0_PACKED_ATTR o_object_header: public o_fixed_versioned { using RefCounterT = o_ref_counter; // ref-counter to hold tags / objects reference counts separately diff --git a/src/dbzero/object_model/set/Set.hpp b/src/dbzero/object_model/set/Set.hpp index 1aa3c291..b13b975c 100644 --- a/src/dbzero/object_model/set/Set.hpp +++ b/src/dbzero/object_model/set/Set.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -29,7 +30,7 @@ namespace db0::object_model class SetIterator; DB0_PACKED_BEGIN - struct DB0_PACKED_ATTR o_set: public db0::o_fixed + struct DB0_PACKED_ATTR o_set: public db0::o_fixed_versioned { // common object header o_unique_header m_header; diff --git a/src/dbzero/object_model/tags/TagIndex.hpp b/src/dbzero/object_model/tags/TagIndex.hpp index 4a2cc275..1f372aea 100644 --- a/src/dbzero/object_model/tags/TagIndex.hpp +++ b/src/dbzero/object_model/tags/TagIndex.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -22,7 +23,7 @@ namespace db0::object_model class EnumFactory; DB0_PACKED_BEGIN - struct DB0_PACKED_ATTR o_tag_index: public o_fixed + struct DB0_PACKED_ATTR o_tag_index: public o_fixed_versioned { Address m_base_index_short_ptr = {}; Address m_base_index_long_ptr = {}; diff --git a/src/dbzero/object_model/tuple/Tuple.hpp b/src/dbzero/object_model/tuple/Tuple.hpp index 2aa1d241..c68373f1 100644 --- a/src/dbzero/object_model/tuple/Tuple.hpp +++ b/src/dbzero/object_model/tuple/Tuple.hpp @@ -25,10 +25,10 @@ namespace db0::object_model class TupleIterator; DB0_PACKED_BEGIN - class DB0_PACKED_ATTR o_tuple: public o_base + class DB0_PACKED_ATTR o_tuple: public o_base { protected: - using super_t = o_base; + using super_t = o_base; friend super_t; o_tuple(std::size_t size); diff --git a/src/dbzero/workspace/Fixture.hpp b/src/dbzero/workspace/Fixture.hpp index ac8009b3..099caef1 100644 --- a/src/dbzero/workspace/Fixture.hpp +++ b/src/dbzero/workspace/Fixture.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -50,7 +51,7 @@ DB0_PACKED_BEGIN /** * Fixture header placed at a fixed well-known address (e.g. 0x0) */ - struct DB0_PACKED_ATTR o_fixture: public o_fixed + struct DB0_PACKED_ATTR o_fixture: public o_fixed_versioned { // auto-generated fixture UUID std::uint64_t m_UUID; diff --git a/tests/unit_tests/ObjectTests.cpp b/tests/unit_tests/ObjectTests.cpp index b33026e1..77283669 100644 --- a/tests/unit_tests/ObjectTests.cpp +++ b/tests/unit_tests/ObjectTests.cpp @@ -38,7 +38,7 @@ namespace tests data.m_types = std::vector { StorageClass::INT64, StorageClass::POOLED_STRING }; data.m_values = std::vector { Value(0), Value(0) }; - ASSERT_EQ ( 44u, o_object::measure(0, {0, 0}, 0, data, 0) ); + ASSERT_EQ ( 52u, o_object::measure(0, {0, 0}, 0, data, 0) ); } TEST_F( ObjectTest , testObjectInitializerCanBeFoundIfAdded ) diff --git a/tests/unit_tests/ValueTableTest.cpp b/tests/unit_tests/ValueTableTest.cpp index f7406593..192cd904 100644 --- a/tests/unit_tests/ValueTableTest.cpp +++ b/tests/unit_tests/ValueTableTest.cpp @@ -49,7 +49,7 @@ namespace tests data.m_types = std::vector { StorageClass::INT64, StorageClass::POOLED_STRING }; data.m_values = std::vector { Value(0), Value(0) }; - ASSERT_EQ ( 20u, PosVT::measure(data, 0) ); + ASSERT_EQ ( 22u, PosVT::measure(data, 0) ); } TEST_F( ValueTableTest , testMicroArrayCanBeCreatedWithValues ) @@ -114,11 +114,11 @@ namespace tests using PosVTObject = v_object; PosVTObject cut(*fixture, data, 0); auto size_of = cut->sizeOf(); - ASSERT_EQ(20u, size_of); - ASSERT_EQ(0, (char*)&cut->types() - (char*)cut.getData()); + ASSERT_EQ(22u, size_of); + ASSERT_EQ(2, (char*)&cut->types() - (char*)cut.getData()); auto offset_values = (char*)&cut->values() - (char*)cut.getData(); ASSERT_EQ((char*)&cut->values(), (char*)cut->values().begin()); - ASSERT_EQ(4u, offset_values); + ASSERT_EQ(6u, offset_values); ASSERT_EQ(2u, cut->size()); workspace.close(); diff --git a/tests/unit_tests/VersionTest.cpp b/tests/unit_tests/VersionTest.cpp new file mode 100644 index 00000000..87d6d392 --- /dev/null +++ b/tests/unit_tests/VersionTest.cpp @@ -0,0 +1,1322 @@ +#include +#include +#include +#include + +#include +#include +#include + +using namespace db0; + +namespace tests { + +DB0_PACKED_BEGIN + +class DB0_PACKED_ATTR VersionNone : public o_base{ + friend o_base; +protected: + VersionNone(uint32_t i, const std::string &s1, const std::string &s2) + : ii(i) + { + if(fehler == 0){ + arrangeMembers() + (o_string::type(), s1) + (o_string::type(), s2); + return ; + } + if(fehler == 1){ + arrangeMembers() + (o_string::type(), s1) + [1] + (o_string::type(), s2); + return ; + } + if(fehler == 2){ + auto arr = arrangeMembers() + (o_string::type(), s1); + + arr = arr[2] + (o_string::type(), s2); + return ; + } + THROW(InputException, "Wrong fehler!"); + } + +public: + uint32_t ii; + + static unsigned int fehler; + + static size_t measure (uint32_t /* i */, const std::string &s1, const std::string &s2){ + if(fehler==0) + return measureMembers() + (o_string::type(), s1) + (o_string::type(), s2); + if(fehler==1) + return measureMembers() + (o_string::type(), s1) + [1] + (o_string::type(), s2); + if(fehler==2){ + Meter met = measureMembers() + (o_string::type(), s1); + + met = met[1] + (o_string::type(), s2); + return met; + } + THROW(InputException, "Wrong fehler!"); + } + + template static size_t safeSizeOf (buf_t buf){ + if(fehler==0) + return sizeOfMembers(buf) + (o_string::type()) + (o_string::type()); + if(fehler==1) + return sizeOfMembers(buf) + (o_string::type()) + [1] + (o_string::type()); + if(fehler==2){ + SafeSize ssi = sizeOfMembers(buf) + (o_string::type()); + + ssi = ssi[2] + (o_string::type()); + return ssi; + } + THROW(InputException, "Wrong fehler!"); + } + + const o_string& getS1() const { + return getDynFirst(o_string::type()); + } + const o_string& getS2() const { + return getDynAfter(getS1(), o_string::type()); + } +}; + +unsigned int VersionNone::fehler=0; + +//note - 0'th version without declaring it, but this is versioned object! +class DB0_PACKED_ATTR VersionZero : public o_base{ + friend o_base; +protected: + VersionZero(uint32_t i, const std::string &s1) + : ii(i) + { + std::string s2("Zosia"); + + if(fehler == 0){ + arrangeMembers() + (o_string::type(), s1); + return ; + } + if(fehler == 1){ + arrangeMembers() + (o_string::type(), s1) + [1] + (o_string::type(), s2); + } + if(fehler == 2){ + auto arr = arrangeMembers() + (o_string::type(), s1); + arr = arr[2] + (o_string::type(), s2); + } + THROW(InputException, "Wrong fehler!"); + } + +public: + uint32_t ii; + + static unsigned int fehler; + + static size_t measure (uint32_t /* i */, const std::string &s1){ + + std::string s2("Zosia"); + + if(fehler==0) + return measureMembers() + (o_string::type(), s1); + if(fehler==1) + return measureMembers() + (o_string::type(), s1) + [1] + (o_string::type(), s2); + if(fehler==2){ + Meter met = measureMembers() + (o_string::type(), s1); + + met = met[1] + (o_string::type(), s2); + return met; + } + THROW(InputException, "Wrong fehler!"); + } + + template static size_t safeSizeOf (buf_t buf){ + if(fehler==0) + return sizeOfMembers(buf) + (o_string::type()); + if(fehler==1) + return sizeOfMembers(buf) + (o_string::type()) + [1] + (o_string::type()); + if(fehler==2){ + SafeSize ssi = sizeOfMembers(buf) + (o_string::type()); + + ssi = ssi[1] + (o_string::type()); + return ssi; + } + THROW(InputException, "Wrong fehler!"); + } + + const o_string& getS1() const { + return getDynFirst(o_string::type()); + } + const o_string& getS1Throw() const { //insufficient version to get, and no alternative... + return getDynFirst(o_string::type(), 1); + } +}; + +unsigned int VersionZero::fehler=0; + +//note - 1'st version +//layout identical to VersionNull, so its memory compatible type + +class DB0_PACKED_ATTR VersionOne : public o_base{ + friend o_base; +protected: + VersionOne(uint32_t i, const std::string &s1, const std::string& s2) + : ii(i) + { + //another way of constructing the object + arrangeMembers() + (o_string::type(), s1) + [1] + (o_string::type(), s2); + + //another way of constructing the object + auto arr = arrangeMembers() + (o_string::type(), s1); + arr = arr[1] + (o_string::type(), s2); + + if(fehler==1){ + arrangeMembers() + (o_string::type(), s1) + (o_string::type(), s2); + } + if(fehler==2){ + auto arr = arrangeMembers() + (o_string::type(), s1); + arr = arr + (o_string::type(), s2); + } + } + +public: + uint32_t ii; + + static unsigned int fehler; + + static size_t measure (uint32_t /* i */, const std::string &s1, const std::string& s2){ + + size_t res1 = measureMembers() + (o_string::type(), s1) + [1] + (o_string::type(), s2); + + Meter met = measureMembers() + (o_string::type(), s1)[1]; + + met = met + (o_string::type(), s2); + + size_t res2 = met; + + if(res1 != res2) //sa(i)nity check + THROW(InputException, "Impossible"); + + if(fehler==0) + return met; + + if(fehler==1){ + return measureMembers() + (o_string::type(), s1) + (o_string::type(), s2); + } + + if(fehler==2){ + Meter met = measureMembers() + (o_string::type(), s1); + + met + (o_string::type(), s2); + return met; + } + THROW(InputException, "Wrong fehler!"); + } + + template static size_t safeSizeOf (buf_t buf){ + size_t res1 = sizeOfMembers(buf) + (o_string::type()) + [1] + (o_string::type()); + + SafeSize ssi = sizeOfMembers(buf) + (o_string::type())[1]; + ssi = ssi + (o_string::type()); + + size_t res2 = ssi; + + if(res1 != res2) //sa(i)nity check + THROW(InputException, "Impossible"); + + if(fehler==0) + return ssi; + if(fehler==1) + return sizeOfMembers(buf) + (o_string::type()) + (o_string::type()); + if(fehler==2){ + SafeSize ssi = sizeOfMembers(buf) + (o_string::type()); + + ssi = ssi + (o_string::type()); + return ssi; + } + THROW(InputException, "Wrong fehler!"); + } + + const o_string& getS1() const { + return getDynFirst(o_string::type()); + } + const o_string& getS2Throw() const { //insufficient version to get, and no alternative... + return getDynAfter(getS1(), o_string::type(), 1); + } + const o_string& getS2RedirS1() const { //insufficient version to get, and alternative is S1... + return getDynAfter(getS1(), o_string::type(), getS1(), 1); + } +}; + +unsigned int VersionOne::fehler=0; + +// //inheritance after non-versioned + +class DB0_PACKED_ATTR VerNoneExt : public o_ext{ + friend o_ext; + typedef o_ext Super; +protected: + VerNoneExt(const std::string &ex1, uint32_t i, const std::string &s1, const std::string &s2) + : Super(i, s1, s2) + { + arrangeMembers() + (o_string::type(), ex1); + } + +public: + static unsigned int fehler; + + static size_t measure (const std::string &ex1, uint32_t i, const std::string &s1, const std::string &s2){ + return measureMembersFromBase(i, s1, s2) + (o_string::type(), ex1); + } + + template static size_t safeSizeOf (buf_t buf){ + return sizeOfMembers(buf) + (o_string::type()); + } + + const o_string &getEx1() const { + return getDynFirst(o_string::type()); + } +}; + + +class DB0_PACKED_ATTR VerNoneExt0 : public o_ext{ + friend o_ext; + typedef o_ext Super; +protected: + VerNoneExt0(const std::string &ex1, uint32_t i, const std::string &s1, const std::string &s2) + : Super(i, s1, s2) + { + arrangeMembers() + (o_string::type(), ex1); + } + +public: + static unsigned int fehler; + + static size_t measure (const std::string &ex1, uint32_t i, const std::string &s1, const std::string &s2){ + return measureMembersFromBase(i, s1, s2) + (o_string::type(), ex1); + } + + template static size_t safeSizeOf (buf_t buf){ + return sizeOfMembers(buf) + (o_string::type()); + } + + const o_string &getEx1() const { + return getDynFirst(o_string::type()); + } +}; + +class DB0_PACKED_ATTR VerNoneExt1 : public o_ext{ + friend o_ext; + typedef o_ext Super; +protected: + VerNoneExt1(const std::string &ex2, const std::string &ex1, uint32_t i, const std::string &s1, const std::string &s2) + : Super(i, s1, s2) + { + arrangeMembers() + (o_string::type(), ex1) + [1] + (o_string::type(), ex2); + } + +public: + static unsigned int fehler; + + static size_t measure (const std::string &ex2, const std::string &ex1, uint32_t i, const std::string &s1, const std::string &s2){ + return measureMembersFromBase(i, s1, s2) + (o_string::type(), ex1) + [1] + (o_string::type(), ex2); + } + + template static size_t safeSizeOf (buf_t buf){ + return sizeOfMembers(buf) + (o_string::type()) + [1] + (o_string::type()); + } + + const o_string &getEx1() const { + return getDynFirst(o_string::type()); + } + + const o_string &getEx2Throw() const { + return getDynAfter(getEx1(), o_string::type(), 1); + } + + const o_string &getEx2Redir() const { + return getDynAfter(getEx1(), o_string::type(), getEx1(), 1); + } +}; + + +// no versioned inheritance after versioned + +class DB0_PACKED_ATTR Ver0ExtNone : public o_ext{ + friend o_ext; + typedef o_ext Super; +protected: + Ver0ExtNone(const std::string &ex1, uint32_t i, const std::string &s1) + : Super(i, s1) + { + arrangeMembers() + (o_string::type(), ex1); + } + +public: + static size_t measure (const std::string &ex1, uint32_t i, const std::string &s1){ + return measureMembersFromBase(i, s1) + (o_string::type(), ex1); + } + + template static size_t safeSizeOf (buf_t buf){ + return sizeOfMembers(buf) + (o_string::type()); + } + + const o_string &getEx1() const { + return getDynFirst(o_string::type()); + } +}; + +class DB0_PACKED_ATTR Ver1ExtNone : public o_ext{ + friend o_ext; + typedef o_ext Super; +protected: + Ver1ExtNone(const std::string &ex1, uint32_t i, const std::string &s1, const std::string& s2) + : Super(i, s1, s2) + { + arrangeMembers() + (o_string::type(), ex1); + } + +public: + static size_t measure (const std::string &ex1, uint32_t i, const std::string &s1, const std::string& s2){ + return measureMembersFromBase(i, s1, s2) + (o_string::type(), ex1); + } + + template static size_t safeSizeOf (buf_t buf){ + return sizeOfMembers(buf) + (o_string::type()); + } + + const o_string &getEx1() const { + return getDynFirst(o_string::type()); + } +}; + +//versioned from versioned obj +//quick tip +//ver 00 <- can be read from 00 01 10 11 +//ver 01 <- can be read from 01 11 +//ver 10 <- can be read from 10 11 +//ver 11 <- can be read from 11 + +class DB0_PACKED_ATTR Ver0Ext0 : public o_ext{ + friend o_ext; + typedef o_ext Super; +protected: + Ver0Ext0(const std::string &ex1, uint32_t i, const std::string &s1) + : Super(i, s1) + { + arrangeMembers() + (o_string::type(), ex1); + } + +public: + static size_t measure (const std::string &ex1, uint32_t i, const std::string &s1){ + return measureMembersFromBase(i, s1) + (o_string::type(), ex1); + } + + template static size_t safeSizeOf (buf_t buf){ + return sizeOfMembers(buf) + (o_string::type()); + } + + const o_string &getEx1() const { + return getDynFirst(o_string::type()); + } +}; + +class DB0_PACKED_ATTR Ver1Ext0 : public o_ext{ + friend o_ext; + typedef o_ext Super; +protected: + Ver1Ext0(const std::string &ex1, uint32_t i, const std::string &s1, const std::string &s2) + : Super(i, s1, s2) + { + arrangeMembers() + (o_string::type(), ex1); + } + +public: + static size_t measure (const std::string &ex1, uint32_t i, const std::string &s1, const std::string &s2){ + return measureMembersFromBase(i, s1, s2) + (o_string::type(), ex1); + } + + template static size_t safeSizeOf (buf_t buf){ + return sizeOfMembers(buf) + (o_string::type()); + } + + const o_string &getEx1() const { + return getDynFirst(o_string::type()); + } +}; + +class DB0_PACKED_ATTR Ver0Ext1 : public o_ext{ + friend o_ext; + typedef o_ext Super; +protected: + Ver0Ext1(const std::string &ex2, const std::string &ex1, uint32_t i, const std::string &s1) + : Super(i, s1) + { + arrangeMembers() + (o_string::type(), ex1) + [1] + (o_string::type(), ex2); + } + +public: + static size_t measure (const std::string &ex2, const std::string &ex1, uint32_t i, const std::string &s1){ + return measureMembersFromBase(i, s1) + (o_string::type(), ex1) + [1] + (o_string::type(), ex2); + } + + template static size_t safeSizeOf (buf_t buf){ + return sizeOfMembers(buf) + (o_string::type()) + [1] + (o_string::type()); + } + + const o_string &getEx1() const { + return getDynFirst(o_string::type()); + } + const o_string &getEx2Throw() const { + return getDynAfter(getEx1(), o_string::type(), 1); + } + const o_string &getEx2RedirS1() const { + return getDynAfter(getEx1(), o_string::type(), getEx1(), 1); + } +}; + +class DB0_PACKED_ATTR Ver1Ext1 : public o_ext{ + friend o_ext; + typedef o_ext Super; +protected: + Ver1Ext1(const std::string &ex2, const std::string &ex1, uint32_t i, const std::string &s1, const std::string &s2) + : Super(i, s1, s2) + { + arrangeMembers() + (o_string::type(), ex1) + [1] + (o_string::type(), ex2); + } + +public: + static size_t measure (const std::string &ex2, const std::string &ex1, uint32_t i, const std::string &s1, const std::string &s2){ + return measureMembersFromBase(i, s1, s2) + (o_string::type(), ex1) + [1] + (o_string::type(), ex2); + } + + template static size_t safeSizeOf (buf_t buf){ + return sizeOfMembers(buf) + (o_string::type()) + [1] + (o_string::type()); + } + + const o_string &getEx1() const { + return getDynFirst(o_string::type()); + } + const o_string &getEx2Throw() const { + return getDynAfter(getEx1(), o_string::type(), 1); + } + const o_string &getEx2RedirS1() const { + return getDynAfter(getEx1(), o_string::type(), getEx1(), 1); + } +}; + +class DB0_PACKED_ATTR o_base_type : public o_fixed { + int a; + int b; + double d; + +public: + o_base_type (int a = 0, int b = 0, double d = 0) + : a(a) + , b(b) + , d(d) + { + } + + std::string toString () const { + std::stringstream _str; + _str << a << "." << b; + return _str.str(); + } + + std::string sumString () const { + std::stringstream _str; + _str << sum(); + return _str.str(); + } + + double sum () const { + return a + b; + } + + // returns number + int getNumber (int num) const { + return num; + } + + // this is lexical_cast requirement + friend std::ostream& operator<<(std::ostream& os, const o_base_type & /* value */) { + return os << "instance of o_base_type"; + } +}; + +class DB0_PACKED_ATTR o_derived_type : public o_ext { + using super_t = o_ext; + int c; +public: + struct Initializer{ + int a, b, c; + }; + + o_derived_type (const Initializer& i) + : o_derived_type(i.a, i.b, i.c) + {} + + o_derived_type (int a, int b, int c) + : super_t(a, b) + , c(c) + { + } + + std::string toString () const { + std::stringstream _str; + _str << o_base_type::toString() << "." << c; + return _str.str(); + } +}; + +class VersionTest : public MemspaceTestBase { +}; + +TEST_F( VersionTest, testNonVerObjects) { + /////////////////////////////// + //test access of nonversioned object + // + std::vector mem_mgr(65536); + + VersionNone::fehler=0; + + ASSERT_NO_THROW(VersionNone::__new(mem_mgr.data(), 44, "Ala", "Zosia")); + ASSERT_NO_THROW(VersionNone::measure(44, "Ala", "Zosia")); + ASSERT_NO_THROW(VersionNone::safeSizeOf(mem_mgr.data())); + + ASSERT_EQ(VersionNone::getIsVerStored(), false); + ASSERT_EQ(VersionNone::__ref(mem_mgr.data()).getObjVer(), 0); + + VersionNone::fehler=1; + //versioning is forbidden for non-versioned type + //in VERY FULL DEBUG MODE +#ifdef VERY_FULL_DEBUG + ASSERT_ANY_THROW(VersionNone::measure(44, "Ala", "Zosia")); + ASSERT_ANY_THROW(VersionNone::safeSizeOf(mem_mgr.data())); + + VersionNone::fehler=2; + //versioning is forbidden for non-versioned type + //in VERY FULL DEBUG MODE + ASSERT_ANY_THROW(VersionNone::measure(44, "Ala", "Zosia")); + ASSERT_ANY_THROW(VersionNone::safeSizeOf(mem_mgr.data())); +#endif +} + +TEST_F( VersionTest, testVerObject){ + /////////////////////////////// + //test acces of lower version obj from misc code... + // + std::vector mem_mgr(65536); + + VersionZero::fehler=0; + VersionOne::fehler=0; + + ASSERT_NO_THROW(VersionZero::__new(mem_mgr.data(), 44, "Ala")); + ASSERT_NO_THROW(VersionZero::measure(44, "Ala")); + ASSERT_NO_THROW(VersionZero::safeSizeOf(mem_mgr.data())); + + ASSERT_EQ (VersionZero::getIsVerStored(), true); + ASSERT_EQ (VersionOne ::getIsVerStored(), true); + ASSERT_NO_THROW(VersionZero::__ref(mem_mgr.data())); + ASSERT_NO_THROW(VersionOne ::__ref(mem_mgr.data())); + ASSERT_EQ (VersionZero::__ref(mem_mgr.data()).getObjVer(), 0); + ASSERT_EQ (VersionOne ::__ref(mem_mgr.data()).getObjVer(), 0); + ASSERT_EQ (VersionZero::safeSizeOf(mem_mgr.data()), VersionOne::safeSizeOf(mem_mgr.data())); +#ifdef VERY_FULL_DEBUG + ASSERT_ANY_THROW(VersionOne::__ref(mem_mgr.data()).getS2Throw()); +#endif + ASSERT_NO_THROW (VersionOne::__ref(mem_mgr.data()).getS2RedirS1()); + ASSERT_EQ (VersionOne::__ref(mem_mgr.data()).getS2RedirS1().toString(), VersionOne ::__ref(mem_mgr.data()).getS1().toString()); + ASSERT_EQ (VersionOne::__ref(mem_mgr.data()).getS2RedirS1().toString(), VersionZero::__ref(mem_mgr.data()).getS1().toString()); + + ASSERT_EQ(VersionOne::__ref(mem_mgr.data()).getS2RedirS1().toString(), "Ala"); + +#ifdef VERY_FULL_DEBUG + VersionZero::fehler=1; + VersionOne::fehler=1; + //no required version information given + ASSERT_ANY_THROW(VersionZero::measure(44, "Ala")); + ASSERT_ANY_THROW(VersionOne::measure(44, "Ala", "Zosia")); + ASSERT_ANY_THROW(VersionZero::safeSizeOf(mem_mgr.data())); + ASSERT_ANY_THROW(VersionOne::safeSizeOf(mem_mgr.data())); + + + VersionZero::fehler=2; + VersionOne::fehler=2; + //no required version information given + ASSERT_ANY_THROW(VersionZero::measure(44, "Ala")); + ASSERT_ANY_THROW(VersionOne::measure(44, "Ala", "Zosia")); + ASSERT_ANY_THROW(VersionZero::safeSizeOf(mem_mgr.data())); + ASSERT_ANY_THROW(VersionOne::safeSizeOf(mem_mgr.data())); +#endif + + ///////////////////////////////////// + //test access higher ver obj from misc code, note: downversion is not supported by design! + // + + VersionOne::fehler=0; + auto *ptr = mem_mgr.data() + VersionOne::safeSizeOf(mem_mgr.data()); + + VersionZero::fehler=0; + VersionOne::fehler=0; + + ASSERT_NO_THROW (VersionOne::__new(ptr, 44, "Ala", "Zosia")); + ASSERT_EQ (VersionOne::__ref(ptr).getObjVer(), 1); + ASSERT_NO_THROW (VersionOne::__ref(ptr).getS2Throw()); + ASSERT_EQ (VersionOne::__ref(ptr).getS2RedirS1().toString(), "Zosia"); + ASSERT_EQ (VersionOne::__ref(ptr).getS2Throw().toString(), "Zosia"); + +#ifdef VERY_FULL_DEBUG + ASSERT_ANY_THROW(VersionZero::__ref(ptr)); +#endif +} + +TEST_F( VersionTest, testNonVerExtFromNonVer){ + std::vector mem_mgr(65536); + + VersionNone::fehler=0; + + std::byte* ptr = mem_mgr.data(); + + ASSERT_NO_THROW(VerNoneExt::__new(ptr, "Ala", 11, "Zosia", "Kasia")); + ASSERT_NO_THROW(VerNoneExt::__ref(ptr)); + ASSERT_EQ (VerNoneExt::__ref(ptr).getIsVerStored(), false); + ASSERT_EQ (VerNoneExt::__ref(ptr).getSuper().getIsVerStored(), false); + ASSERT_EQ (VerNoneExt::__ref(ptr).getObjVer(), 0); + ASSERT_EQ (VerNoneExt::__ref(ptr).getSuper().getObjVer(), 0); + + ASSERT_EQ (VerNoneExt::__ref(ptr).getEx1().toString(), "Ala"); + ASSERT_EQ (VerNoneExt::__ref(ptr).getS2().toString(), "Kasia"); +} + +TEST_F( VersionTest, testVerExtFromNonVerObject) { + + std::vector mem_mgr(65536); + + VersionNone::fehler=0; + + std::byte* ptr2 = mem_mgr.data(); + + ASSERT_NO_THROW(VerNoneExt0::__new(ptr2, "Ala", 11, "Zosia", "Kasia")); + ASSERT_NO_THROW(VerNoneExt0::__ref(ptr2)); + ASSERT_EQ (VerNoneExt0::__ref(ptr2).getIsVerStored(), true); + ASSERT_EQ (VerNoneExt0::__ref(ptr2).getSuper().getIsVerStored(), false); + ASSERT_EQ (VerNoneExt0::__ref(ptr2).getObjVer(), 0); + ASSERT_EQ (VerNoneExt0::__ref(ptr2).getSuper().getObjVer(), 0); + + std::byte* ptr3 = ptr2 + VerNoneExt0::__ref(ptr2).sizeOf(); + + ASSERT_NO_THROW(VerNoneExt1::__new(ptr3, "Basia", "Ala", 11, "Zosia", "Kasia")); + ASSERT_NO_THROW(VerNoneExt1::__ref(ptr3)); + ASSERT_EQ (VerNoneExt1::__ref(ptr3).getIsVerStored(), true); + ASSERT_EQ (VerNoneExt1::__ref(ptr3).getSuper().getIsVerStored(), false); + ASSERT_EQ (VerNoneExt1::__ref(ptr3).getObjVer(), 1); + ASSERT_EQ (VerNoneExt1::__ref(ptr3).getSuper().getObjVer(), 0); + + ASSERT_NO_THROW (VerNoneExt1::__ref(ptr2)); + +#ifdef VERY_FULL_DEBUG + ASSERT_ANY_THROW(VerNoneExt0::__ref(ptr3)); +#endif + + ASSERT_EQ (VerNoneExt1::__ref(ptr2).sizeOf(), VerNoneExt0::__ref(ptr2).sizeOf()); + +#ifdef VERY_FULL_DEBUG + ASSERT_ANY_THROW(VerNoneExt1::__ref(ptr2).getEx2Throw()); +#endif + + ASSERT_NO_THROW (VerNoneExt1::__ref(ptr3).getEx2Throw()); + + ASSERT_EQ (VerNoneExt1::__ref(ptr2).getEx2Redir().toString(), VerNoneExt1::__ref(ptr2).getEx1().toString()); + ASSERT_EQ (VerNoneExt1::__ref(ptr2).getEx2Redir().toString(), VerNoneExt0::__ref(ptr2).getEx1().toString()); + + ASSERT_EQ (VerNoneExt1::__ref(ptr2).getEx2Redir().toString(), "Ala"); + ASSERT_EQ (VerNoneExt1::__ref(ptr3).getEx2Redir().toString(), "Basia"); + + ASSERT_EQ (VerNoneExt1::__ref(ptr2).getS2().toString(), "Kasia"); +} + +TEST_F( VersionTest, testNonVerExtFromVer) { + std::vector mem_mgr(65536); + + VersionNone::fehler=0; + + std::byte* ptr = mem_mgr.data(); + + ASSERT_NO_THROW(Ver0ExtNone::__new(ptr, "Ala", 11, "Zosia")); + ASSERT_NO_THROW(Ver0ExtNone::__ref(ptr)); + + ASSERT_EQ(Ver0ExtNone::__ref(ptr).getIsVerStored(), false); + ASSERT_EQ(Ver0ExtNone::__ref(ptr).getSuper().getIsVerStored(), true); + ASSERT_EQ(Ver0ExtNone::__ref(ptr).getObjVer(), 0); + ASSERT_EQ(Ver0ExtNone::__ref(ptr).getSuper().getObjVer(), 0); + ASSERT_EQ(Ver0ExtNone::__ref(ptr).getS1().toString(), "Zosia"); + + std::byte* ptr2 = ptr + Ver0ExtNone::__ref(ptr).sizeOf(); + + ASSERT_NO_THROW(Ver1ExtNone::__new(ptr2, "Ala", 11, "Zosia", "Kasia")); + ASSERT_NO_THROW(Ver1ExtNone::__ref(ptr2)); + + ASSERT_EQ(Ver1ExtNone::__ref(ptr2).getIsVerStored(), false); + ASSERT_EQ(Ver1ExtNone::__ref(ptr2).getSuper().getIsVerStored(), true); + ASSERT_EQ(Ver1ExtNone::__ref(ptr2).getObjVer(), 0); + ASSERT_EQ(Ver1ExtNone::__ref(ptr2).getSuper().getObjVer(), 1); + ASSERT_EQ(Ver1ExtNone::__ref(ptr2).getS2Throw().toString(), "Kasia"); + + ASSERT_NO_THROW (Ver1ExtNone::__ref(ptr)); + +#ifdef VERY_FULL_DEBUG + ASSERT_ANY_THROW(Ver1ExtNone::__ref(ptr).getS2Throw()); +#endif + ASSERT_EQ(Ver1ExtNone::__ref(ptr).getS2RedirS1().toString(), "Zosia"); +} + +//versioned from versioned obj +//quick tip +//ver 00 <- can be read from 00 01 10 11 +//ver 01 <- can be read from 01 11 +//ver 10 <- can be read from 10 11 +//ver 11 <- can be read from 11 + +TEST_F( VersionTest, testVerExtFromVer) { + std::vector mem_mgr(65536); + + VersionNone::fehler=0; + + std::byte* ptr = mem_mgr.data(); + + ASSERT_NO_THROW(Ver0Ext0::__new(ptr, "Ala", 11, "Zosia")); + ASSERT_NO_THROW(Ver0Ext0::__ref(ptr)); + + ASSERT_EQ(Ver0Ext0::__ref(ptr).getIsVerStored(), true); + ASSERT_EQ(Ver0Ext0::__ref(ptr).getSuper().getIsVerStored(), true); + ASSERT_EQ(Ver0Ext0::__ref(ptr).getObjVer(), 0); + ASSERT_EQ(Ver0Ext0::__ref(ptr).getSuper().getObjVer(), 0); + ASSERT_EQ(Ver0Ext0::__ref(ptr).getS1().toString(), "Zosia"); + + std::byte* ptr2 = ptr + Ver0Ext0::__ref(ptr).sizeOf(); + + ASSERT_NO_THROW(Ver1Ext0::__new(ptr2, "Ala", 11, "Zosia", "Kasia")); + ASSERT_NO_THROW(Ver1Ext0::__ref(ptr2)); + + ASSERT_EQ(Ver1Ext0::__ref(ptr2).getIsVerStored(), true); + ASSERT_EQ(Ver1Ext0::__ref(ptr2).getSuper().getIsVerStored(), true); + ASSERT_EQ(Ver1Ext0::__ref(ptr2).getObjVer(), 0); + ASSERT_EQ(Ver1Ext0::__ref(ptr2).getSuper().getObjVer(), 1); + ASSERT_EQ(Ver1Ext0::__ref(ptr2).getS1().toString(), "Zosia"); + + std::byte* ptr3 = ptr2 + Ver1Ext0::__ref(ptr2).sizeOf(); + + ASSERT_NO_THROW(Ver0Ext1::__new(ptr3, "Basia", "Ala", 11, "Zosia")); + ASSERT_NO_THROW(Ver0Ext1::__ref(ptr3)); + + ASSERT_EQ(Ver0Ext1::__ref(ptr3).getIsVerStored(), true); + ASSERT_EQ(Ver0Ext1::__ref(ptr3).getSuper().getIsVerStored(), true); + ASSERT_EQ(Ver0Ext1::__ref(ptr3).getObjVer(), 1); + ASSERT_EQ(Ver0Ext1::__ref(ptr3).getSuper().getObjVer(), 0); + ASSERT_EQ(Ver0Ext1::__ref(ptr3).getEx1().toString(), "Ala"); + + std::byte* ptr4 = ptr3 + Ver0Ext1::__ref(ptr3).sizeOf(); + + ASSERT_NO_THROW(Ver1Ext1::__new(ptr4, "Basia", "Ala", 11, "Zosia", "Kasia")); + ASSERT_NO_THROW(Ver1Ext1::__ref(ptr4)); + + ASSERT_EQ(Ver1Ext1::__ref(ptr4).getIsVerStored(), true); + ASSERT_EQ(Ver1Ext1::__ref(ptr4).getSuper().getIsVerStored(), true); + ASSERT_EQ(Ver1Ext1::__ref(ptr4).getObjVer(), 1); + ASSERT_EQ(Ver1Ext1::__ref(ptr4).getSuper().getObjVer(), 1); + ASSERT_EQ(Ver1Ext1::__ref(ptr4).getEx1().toString(), "Ala"); + + //downgrade checks.... + ASSERT_NO_THROW(Ver1Ext0::__ref(ptr)); + ASSERT_EQ(Ver1Ext0::__ref(ptr).sizeOf(), Ver0Ext0::__ref(ptr).sizeOf()); + ASSERT_NO_THROW(Ver0Ext1::__ref(ptr)); + ASSERT_EQ(Ver0Ext1::__ref(ptr).sizeOf(), Ver0Ext0::__ref(ptr).sizeOf()); + ASSERT_NO_THROW(Ver1Ext1::__ref(ptr)); + ASSERT_EQ(Ver1Ext1::__ref(ptr).sizeOf(), Ver0Ext0::__ref(ptr).sizeOf()); + +#ifdef VERY_FULL_DEBUG + ASSERT_ANY_THROW(Ver0Ext0::__ref(ptr3)); //get ext[0]base[0] from ext[1]base[0] + ASSERT_ANY_THROW(Ver1Ext0::__ref(ptr3)); //get ext[0]base[1] from ext[1]base[0] +#endif + + ASSERT_NO_THROW (Ver1Ext1::__ref(ptr3)); //get ext[1]base[1] from ext[1]base[0] + ASSERT_EQ(Ver1Ext1::__ref(ptr3).sizeOf(), Ver0Ext1::__ref(ptr3).sizeOf()); + +#ifdef VERY_FULL_DEBUG + ASSERT_ANY_THROW(Ver0Ext0::__ref(ptr2)); //get ext[0]base[0] from ext[0]base[1] + ASSERT_ANY_THROW(Ver0Ext1::__ref(ptr2)); //get ext[1]base[0] from ext[0]base[1] +#endif + ASSERT_NO_THROW (Ver1Ext1::__ref(ptr2)); //get ext[1]base[1] from ext[0]base[1] + ASSERT_EQ(Ver1Ext1::__ref(ptr2).sizeOf(), Ver1Ext0::__ref(ptr2).sizeOf()); + +#ifdef VERY_FULL_DEBUG + ASSERT_ANY_THROW(Ver0Ext0::__ref(ptr4)); //get ext[0]base[0] from ext[0]base[1] + ASSERT_ANY_THROW(Ver0Ext1::__ref(ptr4)); //get ext[1]base[0] from ext[0]base[1] + ASSERT_ANY_THROW(Ver1Ext0::__ref(ptr4)); //get ext[1]base[1] from ext[0]base[1] +#endif +} + +class DB0_PACKED_ATTR Ver0Ext0Wrong : public o_ext{ + friend o_ext; + typedef o_ext Super; +protected: + Ver0Ext0Wrong(uint32_t i, const std::string &s1) + : Super(i, s1) + { + arrangeMembers(); + } + +public: + unsigned int fehler_macher; //well, this is simply wrong! + + static size_t measure (uint32_t i, const std::string &s1){ + return measureMembersFromBase(i, s1); + } + + template static size_t safeSizeOf (buf_t buf){ + return sizeOfMembers(buf); + } +}; + +TEST_F( VersionTest, testExtendedFromDynamicBaseButWithStaticMember) { + std::vector mem_mgr(65536); + + VersionNone::fehler=0; + + std::byte* ptr = mem_mgr.data(); + //it will throw and this is what it should be - CRITICAL ERROR!! +#ifdef VERY_FULL_DEBUG + ASSERT_ANY_THROW(Ver0Ext0Wrong::__new(ptr, 12, "Ala")); +#else + (void)ptr; +#endif +} + +class DB0_PACKED_ATTR Base : public o_base{ +public: + std::uint8_t i1 = 1; + + Base(){ + arrangeMembers(); + } + static size_t measure (){ + return measureMembers(); + } + template static size_t safeSizeOf (buf_t buf){ + return sizeOfMembers(buf); + } +}; + +class DB0_PACKED_ATTR ExtNoVer : public o_ext{ +public: + std::uint8_t i2 = 2; + + ExtNoVer(){ + arrangeMembers(); + } + static size_t measure (){ + return measureMembersFromBase(); + } + template static size_t safeSizeOf (buf_t buf){ + return sizeOfMembers(buf); + } +}; + +class DB0_PACKED_ATTR ExtVer : public o_ext{ +public: + std::uint8_t i2 = 3; + + ExtVer(){ + arrangeMembers(); + } + static size_t measure (){ + return measureMembersFromBase(); + } + template static size_t safeSizeOf (buf_t buf){ + return sizeOfMembers(buf); + } +}; + +class DB0_PACKED_ATTR ExtExtNoVer : public o_ext{ +public: + std::uint8_t i3 = 4; + + ExtExtNoVer(){ + arrangeMembers(); + } + static size_t measure (){ + return measureMembersFromBase(); + } + template static size_t safeSizeOf (buf_t buf){ + return sizeOfMembers(buf); + } +}; +/* triggers compilation error, because of dynamic versioning +class DB0_PACKED_ATTR ExtExtVer : public o_ext{ +public: + int i3 = 0; + + ExtExtVer(){ + arrangeMembers(); + } + static size_t measure (){ + return measureMembersFromBase(); + } + template static size_t safeSizeOf (buf_t buf){ + return sizeOfMembers(buf); + } +}; +*/ +class DB0_PACKED_ATTR ExtDynExtVer : public o_ext{ +public: + + ExtDynExtVer(){ + arrangeMembers(); + } + static size_t measure (){ + return measureMembersFromBase(); + } + template static size_t safeSizeOf (buf_t buf){ + return sizeOfMembers(buf); + } +}; + +TEST_F( VersionTest, testExtendedFromExtendedButWithStaticMember) { + std::vector mem_mgr(65536); + + VersionNone::fehler=0; + + std::byte* ptr = mem_mgr.data(); + + auto &ev = ExtVer::__new(ptr); ptr += ev.sizeOf(); + auto &env = ExtNoVer::__new(ptr); ptr += env.sizeOf(); + auto &eenv = ExtExtNoVer::__new(ptr); ptr += eenv.sizeOf(); + //line below triggers static assert with appriopriate communicate + //uncomment to check + //auto &eev = ExtExtVer::__new(ptr); ptr += eev.sizeOf(); + auto &edev = ExtDynExtVer::__new(ptr); ptr += edev.sizeOf(); + auto &edev2 = ExtDynExtVer::__new(ptr); ptr += edev2.sizeOf(); +} + +class DB0_PACKED_ATTR o_test_user : public o_base { +public: + o_test_user(const std::string &first_name, const std::string &last_name) + { + arrangeMembers() + (o_string::type(), first_name) + (o_string::type(), last_name); + } + + static std::size_t measure(const std::string &first_name, const std::string &last_name) { + return measureMembers() + (o_string::type(), first_name) + (o_string::type(), last_name); + } + + template static std::size_t safeSizeOf(buf_t buf) { + return sizeOfMembers(buf) + (o_string::type()) + (o_string::type()); + } + + const o_string& getFirstName() const { + return getDynFirst(o_string::type()); + } + + const o_string& getLastName() const { + return getDynAfter(getFirstName(), o_string::type()); + } +}; + +class DB0_PACKED_ATTR o_test_user_v2 : public o_base { +public: + o_test_user_v2(std::uint64_t id, const std::string &last_name, const std::string &first_name) + { + arrangeMembers() + (o_simple::type(), id) + (o_string::type(), last_name) + (o_string::type(), first_name); + } + + static std::size_t measure(std::uint64_t id, const std::string &last_name, const std::string &first_name) { + return measureMembers() + (o_simple::type(), id) + (o_string::type(), last_name) + (o_string::type(), first_name); + } + + template static std::size_t safeSizeOf(buf_t buf) { + if(getObjVer(buf) == 0) { + return sizeOfMembers(buf) + (o_string::type()) + (o_string::type()); + } + return sizeOfMembers(buf) + (o_simple::type()) + (o_string::type()) + (o_string::type()); + } + + const o_simple& getID() const { + return getDynFirst(o_simple::type(), 1); + } + + const o_string& getFirstName() const { + if(getObjVer() == 0) { + return getDynFirst(o_string::type()); + } + return getDynAfter(getLastName(), o_string::type(), 1); + } + + const o_string& getLastName() const { + if(getObjVer() == 0) { + return getDynAfter(getFirstName(), o_string::type()); + } + return getDynAfter(getID(), o_string::type(), 1); + } +}; + +TEST_F(VersionTest, testRearrangedMembersInVersionedObject) { + std::size_t obj1_measure = o_test_user::measure("Jan", "Kowalski"); + auto obj1 = std::make_unique(obj1_measure); + auto obj1_ptr = obj1.get(); + o_test_user::__new(obj1_ptr, "Jan", "Kowalski"); + ASSERT_EQ(o_test_user::__ref(obj1_ptr).getFirstName(), "Jan"); + ASSERT_EQ(o_test_user::__ref(obj1_ptr).getLastName(), "Kowalski"); + std::size_t obj1_size = o_test_user::__ref(obj1_ptr).sizeOf(); + ASSERT_EQ(obj1_measure, obj1_size); + + std::size_t obj2_measure = o_test_user_v2::measure(1234, "Kowalski", "Jan"); + auto obj2 = std::make_unique(obj2_measure); + auto obj2_ptr = obj2.get(); + o_test_user_v2::__new(obj2_ptr, 1234, "Kowalski", "Jan"); + ASSERT_EQ(o_test_user_v2::__ref(obj2_ptr).getID(), 1234); + ASSERT_EQ(o_test_user_v2::__ref(obj2_ptr).getFirstName(), "Jan"); + ASSERT_EQ(o_test_user_v2::__ref(obj2_ptr).getLastName(), "Kowalski"); + std::size_t obj2_size = o_test_user_v2::__ref(obj2_ptr).sizeOf(); + ASSERT_EQ(obj2_measure, obj2_size); + ASSERT_EQ(obj2_size, obj1_size + 8); + + ASSERT_EQ(o_test_user_v2::__ref(obj1_ptr).getFirstName(), "Jan"); + ASSERT_EQ(o_test_user_v2::__ref(obj1_ptr).getLastName(), "Kowalski"); + ASSERT_ANY_THROW(o_test_user_v2::__ref(obj1_ptr).getID()); +} + +struct DB0_PACKED_ATTR o_test_array_v1 : public o_fixed { +public: + std::array data; + + o_test_array_v1() { + std::fill(data.begin(), data.end(), 0); + } +}; + +struct DB0_PACKED_ATTR o_test_array_v2 : public o_fixed { +public: + std::array data; + + o_test_array_v2() { + std::fill(data.begin(), data.end(), 0); + } +}; + +template +class DB0_PACKED_ATTR o_test_content : public o_base, VER, true> { + using super_t = o_base; + +public: + o_test_content() { + if(VER == 0) { + this->arrangeMembers()(o_test_array_v1::type()); + } + if(VER == 1) { + this->arrangeMembers()(o_test_array_v2::type()); + } + } + + static std::size_t measure() { + if(VER == 0) { + return super_t::measureMembers()(o_test_array_v1::type()); + } + if(VER == 1) { + return super_t::measureMembers()(o_test_array_v2::type()); + } + } + + template static std::size_t safeSizeOf(buf_t buf) { + if(super_t::getObjVer(buf) == 0) { + return super_t::sizeOfMembers(buf)(o_test_array_v1::type()); + } + return super_t::sizeOfMembers(buf)(o_test_array_v2::type()); + } + + std::uint64_t* begin() { + return reinterpret_cast(this->beginOfDynamicArea()); + } + + std::uint64_t* end() { + return reinterpret_cast(this->beginOfDynamicArea() + this->sizeOf() - this->baseSize()); + } + + std::size_t length() { + return end() - begin(); + } + + std::uint64_t operator[](std::size_t i) { + return *(begin() + i); + } +}; + +TEST_F(VersionTest, testFixedContentReplaceInVersionedObject) { + using o_test_content_v1 = o_test_content<0>; + using o_test_content_v2 = o_test_content<1>; + + std::size_t obj1_measure = o_test_content_v1::measure(); + auto obj1 = std::make_unique(obj1_measure); + auto obj1_ptr = obj1.get(); + o_test_content_v1::__new(obj1_ptr); + std::size_t obj1_size = o_test_content_v1::__ref(obj1_ptr).sizeOf(); + ASSERT_EQ(obj1_measure, obj1_size); + ASSERT_EQ(o_test_content_v1::__ref(obj1_ptr).length(), 4); + { + auto &obj1_ref = o_test_content_v1::__ref(obj1_ptr); + ASSERT_EQ(std::count(obj1_ref.begin(), obj1_ref.end(), 0), 4); + std::iota(obj1_ref.begin(), obj1_ref.end(), 1); + } + for(std::size_t i = 0; i != 4; ++i) { + ASSERT_EQ(o_test_content_v1::__ref(obj1_ptr)[i], i + 1); + } + + std::size_t obj2_measure = o_test_content_v2::measure(); + auto obj2 = std::make_unique(obj2_measure); + auto obj2_ptr = obj2.get(); + o_test_content_v2::__new(obj2_ptr); + std::size_t obj2_size = o_test_content_v2::__ref(obj2_ptr).sizeOf(); + ASSERT_EQ(obj2_measure, obj2_size); + ASSERT_EQ(o_test_content_v2::__ref(obj2_ptr).length(), 8); + { + auto &obj2_ref = o_test_content_v2::__ref(obj2_ptr); + ASSERT_EQ(std::count(obj2_ref.begin(), obj2_ref.end(), 0), 8); + std::iota(obj2_ref.begin(), obj2_ref.end(), 1); + } + for(std::size_t i = 0; i != 8; ++i) { + ASSERT_EQ(o_test_content_v2::__ref(obj2_ptr)[i], i + 1); + } + + auto &obj1_ref = o_test_content_v1::__ref(obj1_ptr); + auto &obj1_backref = o_test_content_v2::__ref(obj1_ptr); + ASSERT_EQ(obj1_ref.sizeOf(), obj1_backref.sizeOf()); + ASSERT_EQ(obj1_ref.length(), obj1_backref.length()); + ASSERT_TRUE(std::equal(obj1_ref.begin(), obj1_ref.end(), obj1_backref.begin(), obj1_backref.end())); +} + +DB0_PACKED_END + +} //namespace tests