Reflection for RapidJSON  0.0.10
Reflection for serializing/deserializing with RapidJSON
reflector.h
Go to the documentation of this file.
1 #ifndef REFLECTIVE_RAPIDJSON_BINARY_REFLECTOR_H
2 #define REFLECTIVE_RAPIDJSON_BINARY_REFLECTOR_H
3 
10 #include "../traits.h"
11 
12 #include <c++utilities/conversion/conversionexception.h>
13 #include <c++utilities/io/binaryreader.h>
14 #include <c++utilities/io/binarywriter.h>
15 
16 #include <any>
17 #include <limits>
18 #include <memory>
19 #include <string>
20 #include <tuple>
21 
22 namespace ReflectiveRapidJSON {
23 
27 template <typename T> struct AdaptedBinarySerializable : public Traits::Bool<false> {
28  static constexpr const char *name = "AdaptedBinarySerializable";
29  static constexpr const char *qualifiedName = "ReflectiveRapidJSON::AdaptedBinarySerializable";
30 };
31 
32 template <typename Type> struct BinarySerializable;
33 
37 namespace BinaryReflector {
38 
39 // define traits to distinguish between "built-in" types like int, std::string, std::vector, ... and custom structs/classes
40 template <typename Type>
41 using IsBuiltInType = Traits::Any<Traits::IsAnyOf<Type, char, std::uint8_t, bool, std::string, std::int16_t, std::uint16_t, std::int32_t,
42  std::uint32_t, std::int64_t, std::uint64_t, float, double>,
43  Traits::IsIteratable<Type>, Traits::IsSpecializingAnyOf<Type, std::pair, std::unique_ptr, std::shared_ptr>, std::is_enum<Type>>;
44 template <typename Type> using IsCustomType = Traits::Not<IsBuiltInType<Type>>;
45 
46 class BinaryDeserializer;
47 class BinarySerializer;
48 
49 template <typename Type, Traits::EnableIf<IsCustomType<Type>> * = nullptr> void readCustomType(BinaryDeserializer &deserializer, Type &customType);
50 template <typename Type, Traits::EnableIf<IsCustomType<Type>> * = nullptr> void writeCustomType(BinarySerializer &serializer, const Type &customType);
51 
52 class BinaryDeserializer : public CppUtilities::BinaryReader {
53 public:
54  BinaryDeserializer(std::istream *stream);
55 
56  using CppUtilities::BinaryReader::read;
57  template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::pair>> * = nullptr> void read(Type &pair);
58  template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::unique_ptr>> * = nullptr> void read(Type &pair);
59  template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::shared_ptr>> * = nullptr> void read(Type &pair);
60  template <typename Type, Traits::EnableIf<IsArray<Type>, Traits::IsResizable<Type>> * = nullptr> void read(Type &iteratable);
61  template <typename Type, Traits::EnableIfAny<IsMapOrHash<Type>, IsMultiMapOrHash<Type>> * = nullptr> void read(Type &iteratable);
62  template <typename Type,
63  Traits::EnableIf<IsIteratableExceptString<Type>,
64  Traits::None<IsMapOrHash<Type>, IsMultiMapOrHash<Type>, Traits::All<IsArray<Type>, Traits::IsResizable<Type>>>> * = nullptr>
65  void read(Type &iteratable);
66  template <typename Type, Traits::EnableIf<std::is_enum<Type>> * = nullptr> void read(Type &customType);
67  template <typename Type, Traits::EnableIf<IsCustomType<Type>> * = nullptr> void read(Type &customType);
68 
69  std::unordered_map<std::uint64_t, std::any> m_pointer;
70 };
71 
72 class BinarySerializer : public CppUtilities::BinaryWriter {
73 public:
74  BinarySerializer(std::ostream *stream);
75 
76  using CppUtilities::BinaryWriter::write;
77  template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::pair>> * = nullptr> void write(const Type &pair);
78  template <typename Type, Traits::EnableIf<Traits::IsSpecializingAnyOf<Type, std::unique_ptr>> * = nullptr> void write(const Type &pointer);
79  template <typename Type, Traits::EnableIf<Traits::IsSpecializingAnyOf<Type, std::shared_ptr>> * = nullptr> void write(const Type &pointer);
80  template <typename Type, Traits::EnableIf<IsIteratableExceptString<Type>, Traits::HasSize<Type>> * = nullptr> void write(const Type &iteratable);
81  template <typename Type, Traits::EnableIf<std::is_enum<Type>> * = nullptr> void write(const Type &customType);
82  template <typename Type, Traits::EnableIf<IsCustomType<Type>> * = nullptr> void write(const Type &customType);
83 
84  std::unordered_map<std::uint64_t, bool> m_pointer;
85 };
86 
87 inline BinaryDeserializer::BinaryDeserializer(std::istream *stream)
88  : CppUtilities::BinaryReader(stream)
89 {
90 }
91 
92 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::pair>> *> void BinaryDeserializer::read(Type &pair)
93 {
94  read(pair.first);
95  read(pair.second);
96 }
97 
98 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::unique_ptr>> *> void BinaryDeserializer::read(Type &pointer)
99 {
100  if (!readBool()) {
101  pointer.reset();
102  return;
103  }
104  pointer = std::make_unique<typename Type::element_type>();
105  read(*pointer);
106 }
107 
108 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::shared_ptr>> *> void BinaryDeserializer::read(Type &pointer)
109 {
110  auto mode = readByte();
111  if (!mode) {
112  // pointer not set
113  pointer.reset();
114  return;
115  }
116 
117  const auto id = (mode & 0x4) ? readUInt64BE() : readVariableLengthUIntBE(); // the 3rd bit being flagged indicates a big ID
118  if ((mode & 0x3) == 1) {
119  // first occurence: make a new pointer
120  m_pointer[id] = pointer = std::make_shared<typename Type::element_type>();
121  read(*pointer);
122  return;
123  }
124  // further occurences: copy previous pointer
125  try {
126  pointer = std::any_cast<Type>(m_pointer[id]);
127  } catch (const std::bad_any_cast &) {
128  throw CppUtilities::ConversionException("Referenced pointer type does not match");
129  }
130 }
131 
132 template <typename Type, Traits::EnableIf<IsArray<Type>, Traits::IsResizable<Type>> *> void BinaryDeserializer::read(Type &iteratable)
133 {
134  const auto size = readVariableLengthUIntBE();
135  iteratable.resize(size);
136  for (auto &element : iteratable) {
137  read(element);
138  }
139 }
140 
141 template <typename Type, Traits::EnableIfAny<IsMapOrHash<Type>, IsMultiMapOrHash<Type>> *> void BinaryDeserializer::read(Type &iteratable)
142 {
143  const auto size = readVariableLengthUIntBE();
144  for (size_t i = 0; i != size; ++i) {
145  std::pair<typename std::remove_const<typename Type::value_type::first_type>::type, typename Type::value_type::second_type> value;
146  read(value);
147  iteratable.emplace(std::move(value));
148  }
149 }
150 
151 template <typename Type,
152  Traits::EnableIf<IsIteratableExceptString<Type>,
153  Traits::None<IsMapOrHash<Type>, IsMultiMapOrHash<Type>, Traits::All<IsArray<Type>, Traits::IsResizable<Type>>>> *>
154 void BinaryDeserializer::read(Type &iteratable)
155 {
156  const auto size = readVariableLengthUIntBE();
157  for (size_t i = 0; i != size; ++i) {
158  typename Type::value_type value;
159  read(value);
160  iteratable.emplace(std::move(value));
161  }
162 }
163 
164 template <typename Type, Traits::EnableIf<std::is_enum<Type>> *> void BinaryDeserializer::read(Type &enumValue)
165 {
166  typename std::underlying_type<Type>::type value;
167  read(value);
168  enumValue = static_cast<Type>(value);
169 }
170 
171 template <typename Type, Traits::EnableIf<IsCustomType<Type>> *> void BinaryDeserializer::read(Type &customType)
172 {
173  readCustomType(*this, customType);
174 }
175 
176 inline BinarySerializer::BinarySerializer(std::ostream *stream)
177  : CppUtilities::BinaryWriter(stream)
178 {
179 }
180 
181 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::pair>> *> void BinarySerializer::write(const Type &pair)
182 {
183  write(pair.first);
184  write(pair.second);
185 }
186 
187 template <typename Type, Traits::EnableIf<Traits::IsSpecializingAnyOf<Type, std::unique_ptr>> *> void BinarySerializer::write(const Type &pointer)
188 {
189  const bool hasValue = pointer != nullptr;
190  writeBool(hasValue);
191  if (hasValue) {
192  write(*pointer);
193  }
194 }
195 
196 template <typename Type, Traits::EnableIf<Traits::IsSpecializingAnyOf<Type, std::shared_ptr>> *> void BinarySerializer::write(const Type &pointer)
197 {
198  if (pointer == nullptr) {
199  writeByte(0);
200  return;
201  }
202  const auto id = reinterpret_cast<std::uintptr_t>(pointer.get());
203  const auto bigId = id >= 0x80000000000000;
204  auto &alreadyWritten = m_pointer[id];
205  std::uint8_t mode = alreadyWritten ? 2 : 1;
206  if (bigId) {
207  mode = mode | 0x4; // "flag" 3rd bit to indicate big ID
208  }
209  writeByte(mode);
210  if (bigId) {
211  writeUInt64BE(id);
212  } else {
213  writeVariableLengthUIntBE(id);
214  }
215  if (!alreadyWritten) {
216  alreadyWritten = true;
217  write(*pointer);
218  }
219 }
220 
221 template <typename Type, Traits::EnableIf<IsIteratableExceptString<Type>, Traits::HasSize<Type>> *>
222 void BinarySerializer::write(const Type &iteratable)
223 {
224  writeVariableLengthUIntBE(iteratable.size());
225  for (const auto &element : iteratable) {
226  write(element);
227  }
228 }
229 
230 template <typename Type, Traits::EnableIf<std::is_enum<Type>> *> void BinarySerializer::write(const Type &enumValue)
231 {
232  write(static_cast<typename std::underlying_type<Type>::type>(enumValue));
233 }
234 
235 template <typename Type, Traits::EnableIf<IsCustomType<Type>> *> void BinarySerializer::write(const Type &customType)
236 {
237  writeCustomType(*this, customType);
238 }
239 
240 } // namespace BinaryReflector
241 } // namespace ReflectiveRapidJSON
242 
243 #endif // REFLECTIVE_RAPIDJSON_BINARY_REFLECTOR_H
ReflectiveRapidJSON::BinaryReflector::BinaryDeserializer::m_pointer
std::unordered_map< std::uint64_t, std::any > m_pointer
Definition: reflector.h:69
ReflectiveRapidJSON::BinaryReflector::BinarySerializer
Definition: reflector.h:72
ReflectiveRapidJSON::BinaryReflector::BinarySerializer::BinarySerializer
BinarySerializer(std::ostream *stream)
Definition: reflector.h:176
ReflectiveRapidJSON::AdaptedBinarySerializable::qualifiedName
static constexpr const char * qualifiedName
Definition: reflector.h:29
ReflectiveRapidJSON::BinaryReflector::BinarySerializer::write
void write(const Type &pair)
Definition: reflector.h:181
ReflectiveRapidJSON::BinaryReflector::BinaryDeserializer::read
void read(Type &pair)
Definition: reflector.h:92
ReflectiveRapidJSON
Definition: traits.h:12
ReflectiveRapidJSON::IsMultiMapOrHash
Traits::Any< Traits::IsSpecializationOf< Type, std::multimap >, Traits::IsSpecializationOf< Type, std::unordered_multimap >, TreatAsMultiMapOrHash< Type > > IsMultiMapOrHash
Definition: traits.h:49
ReflectiveRapidJSON::BinarySerializable
The BinarySerializable class provides the CRTP-base for (de)serializable objects.
Definition: reflector.h:32
ReflectiveRapidJSON::AdaptedBinarySerializable::name
static constexpr const char * name
Definition: reflector.h:28
ReflectiveRapidJSON::AdaptedBinarySerializable
The AdaptedBinarySerializable class allows considering 3rd party classes as serializable.
Definition: reflector.h:27
ReflectiveRapidJSON::BinaryReflector::IsCustomType
Traits::Not< IsBuiltInType< Type > > IsCustomType
Definition: reflector.h:44
ReflectiveRapidJSON::BinaryReflector::BinaryDeserializer
Definition: reflector.h:52
ReflectiveRapidJSON::BinaryReflector::BinarySerializer::m_pointer
std::unordered_map< std::uint64_t, bool > m_pointer
Definition: reflector.h:84
ReflectiveRapidJSON::JsonType::Bool
ReflectiveRapidJSON::BinaryReflector::writeCustomType
void writeCustomType(BinarySerializer &serializer, const Type &customType)
Definition: reflector-boosthana.h:33
ReflectiveRapidJSON::BinaryReflector::BinaryDeserializer::BinaryDeserializer
BinaryDeserializer(std::istream *stream)
Definition: reflector.h:87
ReflectiveRapidJSON::BinaryReflector::readCustomType
void readCustomType(BinaryDeserializer &deserializer, Type &customType)
Definition: reflector-boosthana.h:27
ReflectiveRapidJSON::BinaryReflector::IsBuiltInType
Traits::Any< Traits::IsAnyOf< Type, char, std::uint8_t, bool, std::string, std::int16_t, std::uint16_t, std::int32_t, std::uint32_t, std::int64_t, std::uint64_t, float, double >, Traits::IsIteratable< Type >, Traits::IsSpecializingAnyOf< Type, std::pair, std::unique_ptr, std::shared_ptr >, std::is_enum< Type > > IsBuiltInType
Definition: reflector.h:43