1 #ifndef REFLECTIVE_RAPIDJSON_BINARY_REFLECTOR_H
2 #define REFLECTIVE_RAPIDJSON_BINARY_REFLECTOR_H
10 #include "../traits.h"
12 #include <c++utilities/conversion/conversionexception.h>
13 #include <c++utilities/io/binaryreader.h>
14 #include <c++utilities/io/binarywriter.h>
32 static constexpr
const char *
name =
"AdaptedBinarySerializable";
33 static constexpr
const char *
qualifiedName =
"ReflectiveRapidJSON::AdaptedBinarySerializable";
41 namespace BinaryReflector {
44 template <
typename Type>
45 using IsBuiltInType = Traits::Any<Traits::IsAnyOf<Type, char, std::uint8_t, bool, std::string, std::int16_t, std::uint16_t, std::int32_t,
46 std::uint32_t, std::int64_t, std::uint64_t, float,
double>,
47 Traits::IsIteratable<Type>, Traits::IsSpecializingAnyOf<Type, std::pair, std::unique_ptr, std::shared_ptr>, std::is_enum<Type>,
IsVariant<Type>>;
48 template <
typename Type>
using IsCustomType = Traits::Not<IsBuiltInType<Type>>;
57 friend class ::BinaryReflectorTests;
62 using CppUtilities::BinaryReader::read;
63 template <
typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::pair>> * =
nullptr>
void read(Type &pair);
64 template <
typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::unique_ptr>> * =
nullptr>
void read(Type &pointer);
65 template <
typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::shared_ptr>> * =
nullptr>
void read(Type &pointer);
66 template <
typename Type, Traits::EnableIf<IsArray<Type>, Traits::IsResizable<Type>> * =
nullptr>
void read(Type &iteratable);
67 template <
typename Type, Traits::EnableIfAny<IsMapOrHash<Type>, IsMultiMapOrHash<Type>> * =
nullptr>
void read(Type &iteratable);
68 template <
typename Type,
69 Traits::EnableIf<IsIteratableExceptString<Type>,
70 Traits::None<IsMapOrHash<Type>,
IsMultiMapOrHash<Type>, Traits::All<IsArray<Type>, Traits::IsResizable<Type>>>> * =
nullptr>
71 void read(Type &iteratable);
72 template <
typename Type, Traits::EnableIf<std::is_enum<Type>> * =
nullptr>
void read(Type &enumValue);
73 template <
typename Type, Traits::EnableIf<IsVariant<Type>> * =
nullptr>
void read(Type &variant);
74 template <
typename Type, Traits::EnableIf<IsCustomType<Type>> * =
nullptr>
void read(Type &customType);
77 std::unordered_map<std::uint64_t, std::any> m_pointer;
81 friend class ::BinaryReflectorTests;
86 using CppUtilities::BinaryWriter::write;
87 template <
typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::pair>> * =
nullptr>
void write(
const Type &pair);
88 template <
typename Type, Traits::EnableIf<Traits::IsSpecializingAnyOf<Type, std::unique_ptr>> * =
nullptr>
void write(
const Type &pointer);
89 template <
typename Type, Traits::EnableIf<Traits::IsSpecializingAnyOf<Type, std::shared_ptr>> * =
nullptr>
void write(
const Type &pointer);
90 template <
typename Type, Traits::EnableIf<IsIteratableExceptString<Type>, Traits::HasSize<Type>> * =
nullptr>
void write(
const Type &iteratable);
91 template <
typename Type, Traits::EnableIf<std::is_enum<Type>> * =
nullptr>
void write(
const Type &enumValue);
92 template <
typename Type, Traits::EnableIf<IsVariant<Type>> * =
nullptr>
void write(
const Type &variant);
93 template <
typename Type, Traits::EnableIf<IsCustomType<Type>> * =
nullptr>
void write(
const Type &customType);
96 std::unordered_map<std::uint64_t, bool> m_pointer;
100 : CppUtilities::BinaryReader(stream)
104 template <
typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::pair>> *>
void BinaryDeserializer::read(Type &pair)
110 template <
typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::unique_ptr>> *>
void BinaryDeserializer::read(Type &pointer)
116 pointer = std::make_unique<typename Type::element_type>();
120 template <
typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::shared_ptr>> *>
void BinaryDeserializer::read(Type &pointer)
122 auto mode = readByte();
129 const auto id = (mode & 0x4) ? readUInt64BE() : readVariableLengthUIntBE();
130 if ((mode & 0x3) == 1) {
132 m_pointer[id] = pointer = std::make_shared<typename Type::element_type>();
138 pointer = std::any_cast<Type>(m_pointer[
id]);
139 }
catch (
const std::bad_any_cast &) {
140 throw CppUtilities::ConversionException(
"Referenced pointer type does not match");
144 template <
typename Type, Traits::EnableIf<IsArray<Type>, Traits::IsResizable<Type>> *>
void BinaryDeserializer::read(Type &iteratable)
146 const auto size = readVariableLengthUIntBE();
147 iteratable.resize(size);
148 for (
auto &element : iteratable) {
153 template <
typename Type, Traits::EnableIfAny<IsMapOrHash<Type>, IsMultiMapOrHash<Type>> *>
void BinaryDeserializer::read(Type &iteratable)
155 const auto size = readVariableLengthUIntBE();
156 for (
size_t i = 0; i != size; ++i) {
157 std::pair<typename std::remove_const<typename Type::value_type::first_type>::type,
typename Type::value_type::second_type> value;
159 iteratable.emplace(std::move(value));
163 template <
typename Type,
164 Traits::EnableIf<IsIteratableExceptString<Type>,
165 Traits::None<IsMapOrHash<Type>, IsMultiMapOrHash<Type>, Traits::All<IsArray<Type>, Traits::IsResizable<Type>>>> *>
168 const auto size = readVariableLengthUIntBE();
169 for (
size_t i = 0; i != size; ++i) {
170 typename Type::value_type value;
172 iteratable.emplace(std::move(value));
178 typename std::underlying_type<Type>::type value;
180 enumValue =
static_cast<Type
>(value);
185 template <
typename Variant, std::
size_t compiletimeIndex = 0>
186 void readVariantValueByRuntimeIndex(std::size_t runtimeIndex, Variant &variant, BinaryDeserializer &deserializer)
188 if constexpr (compiletimeIndex < std::variant_size_v<Variant>) {
189 if (compiletimeIndex == runtimeIndex) {
190 if constexpr (std::is_same_v<std::variant_alternative_t<compiletimeIndex, Variant>, std::monostate>) {
191 variant = std::monostate{};
193 deserializer.read(variant.template emplace<compiletimeIndex>());
196 readVariantValueByRuntimeIndex<Variant, compiletimeIndex + 1>(runtimeIndex, variant, deserializer);
199 throw CppUtilities::ConversionException(
"Variant index is out of expected range");
207 Detail::readVariantValueByRuntimeIndex(readByte(), variant, *
this);
216 : CppUtilities::BinaryWriter(stream)
220 template <
typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::pair>> *>
void BinarySerializer::write(
const Type &pair)
226 template <
typename Type, Traits::EnableIf<Traits::IsSpecializingAnyOf<Type, std::unique_ptr>> *>
void BinarySerializer::write(
const Type &pointer)
228 const bool hasValue = pointer !=
nullptr;
235 template <
typename Type, Traits::EnableIf<Traits::IsSpecializingAnyOf<Type, std::shared_ptr>> *>
void BinarySerializer::write(
const Type &pointer)
237 if (pointer ==
nullptr) {
241 const auto id =
reinterpret_cast<std::uintptr_t
>(pointer.get());
242 const auto bigId =
id >= 0x80000000000000;
243 auto &alreadyWritten = m_pointer[id];
244 std::uint8_t mode = alreadyWritten ? 2 : 1;
252 writeVariableLengthUIntBE(
id);
254 if (!alreadyWritten) {
255 alreadyWritten =
true;
260 template <
typename Type, Traits::EnableIf<IsIteratableExceptString<Type>, Traits::HasSize<Type>> *>
263 writeVariableLengthUIntBE(iteratable.size());
264 for (
const auto &element : iteratable) {
269 template <
typename Type, Traits::EnableIf<std::is_enum<Type>> *>
void BinarySerializer::write(
const Type &enumValue)
271 write(
static_cast<typename std::underlying_type<Type>::type
>(enumValue));
274 template <
typename Type, Traits::EnableIf<IsVariant<Type>> *>
void BinarySerializer::write(
const Type &variant)
276 static_assert(std::variant_size_v<Type> < std::numeric_limits<std::uint8_t>::max(),
"index will not exceed limit");
277 writeByte(
static_cast<std::uint8_t
>(variant.index()));
279 [
this](
const auto &valueOfActualType) {
280 if constexpr (!std::is_same_v<std::decay_t<decltype(valueOfActualType)>, std::monostate>) {
281 write(valueOfActualType);
283 CPP_UTILITIES_UNUSED(
this)
289 template <
typename Type, Traits::EnableIf<IsCustomType<Type>> *>
void BinarySerializer::write(
const Type &customType)
297 #endif // REFLECTIVE_RAPIDJSON_BINARY_REFLECTOR_H