Reflection for RapidJSON  0.0.7
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/conversion/types.h>
14 #include <c++utilities/io/binaryreader.h>
15 #include <c++utilities/io/binarywriter.h>
16 
17 #include <any>
18 #include <limits>
19 #include <memory>
20 #include <string>
21 #include <tuple>
22 
23 namespace ReflectiveRapidJSON {
24 
28 template <typename T> struct AdaptedBinarySerializable : public Traits::Bool<false> {
29  static constexpr const char *name = "AdaptedBinarySerializable";
30  static constexpr const char *qualifiedName = "ReflectiveRapidJSON::AdaptedBinarySerializable";
31 };
32 
33 template <typename Type> struct BinarySerializable;
34 
38 namespace BinaryReflector {
39 
40 // define traits to distinguish between "built-in" types like int, std::string, std::vector, ... and custom structs/classes
41 template <typename Type>
42 using IsBuiltInType = Traits::Any<Traits::IsAnyOf<Type, char, byte, bool, std::string, int16, uint16, int32, uint32, int64, uint64, float32, float64>,
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 IoUtilities::BinaryReader {
53 public:
54  BinaryDeserializer(std::istream *stream);
55 
56  using IoUtilities::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<uint64, std::any> m_pointer;
70 };
71 
72 class BinarySerializer : public IoUtilities::BinaryWriter {
73 public:
74  BinarySerializer(std::ostream *stream);
75 
76  using IoUtilities::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<uint64, bool> m_pointer;
85 };
86 
87 inline BinaryDeserializer::BinaryDeserializer(std::istream *stream)
88  : IoUtilities::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 ConversionUtilities::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  : IoUtilities::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  byte 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
void writeCustomType(BinarySerializer &serializer, const Type &customType)
Traits::Not< IsBuiltInType< Type > > IsCustomType
Definition: reflector.h:44
void readCustomType(BinaryDeserializer &deserializer, Type &customType)
Traits::Any< Traits::IsSpecializationOf< Type, std::multimap >, Traits::IsSpecializationOf< Type, std::unordered_multimap >, TreatAsMultiMapOrHash< Type > > IsMultiMapOrHash
Definition: traits.h:47
std::unordered_map< uint64, bool > m_pointer
Definition: reflector.h:84
static constexpr const char * qualifiedName
Definition: reflector.h:30
static constexpr const char * name
Definition: reflector.h:29
Traits::Any< Traits::IsAnyOf< Type, char, byte, bool, std::string, int16, uint16, int32, uint32, int64, uint64, float32, float64 >, Traits::IsIteratable< Type >, Traits::IsSpecializingAnyOf< Type, std::pair, std::unique_ptr, std::shared_ptr >, std::is_enum< Type > > IsBuiltInType
Definition: reflector.h:43
The AdaptedBinarySerializable class allows considering 3rd party classes as serializable.
Definition: reflector.h:28
std::unordered_map< uint64, std::any > m_pointer
Definition: reflector.h:69
The BinarySerializable class provides the CRTP-base for (de)serializable objects.
Definition: reflector.h:33