diff --git a/lib/binary/reflector.h b/lib/binary/reflector.h index af0d85f..ab34da1 100644 --- a/lib/binary/reflector.h +++ b/lib/binary/reflector.h @@ -9,10 +9,12 @@ #include "../traits.h" +#include #include #include #include +#include #include #include #include @@ -38,12 +40,8 @@ namespace BinaryReflector { // define traits to distinguish between "built-in" types like int, std::string, std::vector, ... and custom structs/classes template using IsBuiltInType = Traits::Any, - Traits::IsIteratable, Traits::IsSpecializationOf, std::is_enum>; + Traits::IsIteratable, Traits::IsSpecializingAnyOf, std::is_enum>; template using IsCustomType = Traits::Not>; -template -using IsSerializable = Traits::All< - Traits::Any>, std::is_base_of, Type>, AdaptedBinarySerializable>, - Traits::Not>>; class BinaryDeserializer; class BinarySerializer; @@ -57,6 +55,8 @@ public: using IoUtilities::BinaryReader::read; template > * = nullptr> void read(Type &pair); + template > * = nullptr> void read(Type &pair); + template > * = nullptr> void read(Type &pair); template , Traits::IsResizable> * = nullptr> void read(Type &iteratable); template > * = nullptr> void read(Type &iteratable); template > * = nullptr> void read(Type &customType); template > * = nullptr> void read(Type &customType); + + std::unordered_map m_pointer; }; class BinarySerializer : public IoUtilities::BinaryWriter { @@ -73,9 +75,13 @@ public: using IoUtilities::BinaryWriter::write; template > * = nullptr> void write(const Type &pair); + template > * = nullptr> void write(const Type &pointer); + template > * = nullptr> void write(const Type &pointer); template , Traits::HasSize> * = nullptr> void write(const Type &iteratable); template > * = nullptr> void write(const Type &customType); template > * = nullptr> void write(const Type &customType); + + std::unordered_map m_pointer; }; inline BinaryDeserializer::BinaryDeserializer(std::istream *stream) @@ -89,6 +95,40 @@ template > *> void BinaryDeserializer::read(Type &pointer) +{ + if (!readBool()) { + pointer.reset(); + return; + } + pointer = std::make_unique(); + read(*pointer); +} + +template > *> void BinaryDeserializer::read(Type &pointer) +{ + const auto occurence = readByte(); + if (!occurence) { + // pointer not set + pointer.reset(); + return; + } + + const auto id = readVariableLengthUIntBE(); + if (occurence == 1) { + // first occurence: make a new pointer + m_pointer[id] = pointer = std::make_shared(); + read(*pointer); + return; + } + // further occurences: copy previous pointer + try { + pointer = std::any_cast(m_pointer[id]); + } catch (const std::bad_any_cast) { + throw ConversionUtilities::ConversionException("Referenced pointer type does not match"); + } +} + template , Traits::IsResizable> *> void BinaryDeserializer::read(Type &iteratable) { const auto size = readVariableLengthUIntBE(); @@ -143,6 +183,31 @@ template > *> void BinarySerializer::write(const Type &pointer) +{ + const bool hasValue = pointer != nullptr; + writeBool(hasValue); + if (hasValue) { + write(*pointer); + } +} + +template > *> void BinarySerializer::write(const Type &pointer) +{ + if (pointer == nullptr) { + writeByte(0); + return; + } + const auto id = reinterpret_cast(pointer.get()); + auto &alreadyWritten = m_pointer[id]; + writeByte(alreadyWritten ? 2 : 1); + writeVariableLengthUIntBE(id); + if (!alreadyWritten) { + alreadyWritten = true; + write(*pointer); + } +} + template , Traits::HasSize> *> void BinarySerializer::write(const Type &iteratable) {