11#include <unordered_map>
15namespace nc::serialize::binary
18concept TriviallyCopyable =
requires {
requires std::is_trivially_copyable_v<T>; };
21concept Aggregate =
requires {
requires std::is_aggregate_v<T>; };
27inline constexpr size_t g_failedMemberCount = 0xFFFFFFFFFFFFFFFF;
30struct UniversalType{
template<
class T>
operator T()
const; };
34 requires requires { std::is_aggregate_v<T>; }
35consteval auto MemberCount() ->
size_t
37 using U = UniversalType;
38 if constexpr (
requires { T{U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}}; })
39 return g_failedMemberCount;
40 else if constexpr (
requires { T{U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}}; })
42 else if constexpr (
requires { T{U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}}; })
44 else if constexpr (
requires { T{U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}}; })
46 else if constexpr (
requires { T{U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}}; })
48 else if constexpr (
requires { T{U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}}; })
50 else if constexpr (
requires { T{U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}}; })
52 else if constexpr (
requires { T{U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}}; })
54 else if constexpr (
requires { T{U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}}; })
56 else if constexpr (
requires { T{U{}, U{}, U{}, U{}, U{}, U{}, U{}, U{}}; })
58 else if constexpr (
requires { T{U{}, U{}, U{}, U{}, U{}, U{}, U{}}; })
60 else if constexpr (
requires { T{U{}, U{}, U{}, U{}, U{}, U{}}; })
62 else if constexpr (
requires { T{U{}, U{}, U{}, U{}, U{}}; })
64 else if constexpr (
requires { T{U{}, U{}, U{}, U{}}; })
66 else if constexpr (
requires { T{U{}, U{}, U{}}; })
68 else if constexpr (
requires { T{U{}, U{}}; })
70 else if constexpr (
requires { T{U{}}; })
78concept UnpackableAggregate = Aggregate<T>
79 && !TriviallyCopyable<T>
83void Serialize(std::ostream& stream,
const T& in);
85template<TriviallyCopyable T>
86void Serialize(std::ostream& stream,
const T& in);
88template<UnpackableAggregate T>
89void Serialize(std::ostream& stream,
const T& in);
92void Serialize(std::ostream& stream,
const std::vector<T>& in);
94template<
class T,
size_t I>
95void Serialize(std::ostream& stream,
const std::array<T, I>& in);
97template<
class T,
class U>
98void Serialize(std::ostream& stream,
const std::pair<T, U>& in);
100template<
class K,
class V>
101void Serialize(std::ostream& stream,
const std::unordered_map<K, V>& in);
104void Serialize(std::ostream& stream,
const std::optional<T>& in);
109template<TriviallyCopyable T>
112template<UnpackableAggregate T>
116void Deserialize(std::istream& stream, std::vector<T>& out);
118template<
class T,
size_t I>
119void Deserialize(std::istream& stream, std::array<T, I>& out);
121template<
class T,
class U>
122void Deserialize(std::istream& stream, std::pair<T, U>& out);
124template<
class K,
class V>
125void Deserialize(std::istream& stream, std::unordered_map<K, V>& out);
128void Deserialize(std::istream& stream, std::optional<T>& out);
130template<
class... Args>
131void SerializeMultiple(std::ostream& stream, Args&&... args)
136template<
class... Args>
137void DeserializeMultiple(std::istream& stream, Args&&... args)
143void SerializeTrivialContainer(std::ostream& stream,
const C& container)
146 stream.write(
reinterpret_cast<const char*
>(container.data()),
sizeof(
typename C::value_type) * container.size());
150void DeserializeTrivialContainer(std::istream& stream, C& container)
152 auto size =
size_t{};
154 container.resize(size);
155 stream.read(
reinterpret_cast<char*
>(container.data()),
sizeof(
typename C::value_type) * size);
159void SerializeNonTrivialContainer(std::ostream& stream,
const C& container)
161 auto size = container.size();
162 stream.write(
reinterpret_cast<char*
>(&size),
sizeof(size));
163 for (
const auto& obj : container)
Serialize(stream, obj);
167void DeserializeNonTrivialContainer(std::istream& stream, C& container)
169 auto count =
size_t{};
171 container.reserve(count);
172 std::generate_n(std::back_inserter(container), count, [&stream]()
174 auto out =
typename C::value_type{};
180template<TriviallyCopyable T>
181void Serialize(std::ostream& stream,
const T& in)
183 stream.write(
reinterpret_cast<const char*
>(&in),
sizeof(T));
186template<TriviallyCopyable T>
189 stream.read(
reinterpret_cast<char*
>(&out),
sizeof(T));
193inline void Serialize(std::ostream& stream,
const std::string& in)
195 SerializeTrivialContainer(stream, in);
199inline void Deserialize(std::istream& stream, std::string& out)
201 DeserializeTrivialContainer(stream, out);
205void Serialize(std::ostream& stream,
const std::vector<T>& in)
207 if constexpr (std::is_trivially_copyable_v<T>)
208 SerializeTrivialContainer(stream, in);
210 SerializeNonTrivialContainer(stream, in);
214void Deserialize(std::istream& stream, std::vector<T>& out)
216 if constexpr (std::is_trivially_copyable_v<T>)
217 DeserializeTrivialContainer(stream, out);
219 DeserializeNonTrivialContainer(stream, out);
222template<
class T,
size_t I>
223void Serialize(std::ostream& stream,
const std::array<T, I>& in)
225 if constexpr(std::is_trivially_copyable_v<T>)
226 SerializeTrivialContainer(stream, in);
228 SerializeNonTrivialContainer(stream, in);
231template<
class T,
size_t I>
232void Deserialize(std::istream& stream, std::array<T, I>& out)
234 auto size =
size_t{};
236 NC_ASSERT(size == out.size(),
"Expected array size does not match stream contents");
238 if constexpr(std::is_trivially_copyable_v<T>)
240 stream.read(
reinterpret_cast<char*
>(out.data()),
sizeof(T) * size);
244 std::ranges::for_each(out, [&stream](
auto&& obj)
251template<
class T,
class U>
252void Serialize(std::ostream& stream,
const std::pair<T, U>& in)
254 SerializeMultiple(stream, in.first, in.second);
257template<
class T,
class U>
258void Deserialize(std::istream& stream, std::pair<T, U>& out)
260 DeserializeMultiple(stream, out.first, out.second);
263template<
class K,
class V>
264void Serialize(std::ostream& stream,
const std::unordered_map<K, V>& in)
266 SerializeNonTrivialContainer(stream, in);
269template<
class K,
class V>
270void Deserialize(std::istream& stream, std::unordered_map<K, V>& out)
272 auto count =
size_t{};
275 std::generate_n(std::inserter(out, std::end(out)), count, [&stream]()
277 auto pair = std::pair<K, V>{};
284void Serialize(std::ostream& stream,
const std::optional<T>& in)
287 ? SerializeMultiple(stream,
true, in.value())
292void Deserialize(std::istream& stream, std::optional<T>& out)
294 auto hasValue =
false;
307template<UnpackableAggregate T>
308void Serialize(std::ostream& stream,
const T& in)
310 static constexpr auto memberCount = MemberCount<T>();
313 if constexpr (memberCount == 16)
315 const auto& [m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16] = in;
316 SerializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16);
318 else if constexpr (memberCount == 15)
320 const auto& [m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15] = in;
321 SerializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15);
323 else if constexpr (memberCount == 14)
325 const auto& [m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14] = in;
326 SerializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14);
328 else if constexpr (memberCount == 13)
330 const auto& [m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13] = in;
331 SerializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13);
333 else if constexpr (memberCount == 12)
335 const auto& [m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12] = in;
336 SerializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12);
338 else if constexpr (memberCount == 11)
340 const auto& [m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11] = in;
341 SerializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11);
343 else if constexpr (memberCount == 10)
345 const auto& [m1, m2, m3, m4, m5, m6, m7, m8, m9, m10] = in;
346 SerializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10);
348 else if constexpr (memberCount == 9)
350 const auto& [m1, m2, m3, m4, m5, m6, m7, m8, m9] = in;
351 SerializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8, m9);
353 else if constexpr (memberCount == 8)
355 const auto& [m1, m2, m3, m4, m5, m6, m7, m8] = in;
356 SerializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8);
358 else if constexpr (memberCount == 7)
360 const auto& [m1, m2, m3, m4, m5, m6, m7] = in;
361 SerializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7);
363 else if constexpr (memberCount == 6)
365 const auto& [m1, m2, m3, m4, m5, m6] = in;
366 SerializeMultiple(stream, m1, m2, m3, m4, m5, m6);
368 else if constexpr (memberCount == 5)
370 const auto& [m1, m2, m3, m4, m5] = in;
371 SerializeMultiple(stream, m1, m2, m3, m4, m5);
373 else if constexpr (memberCount == 4)
375 const auto& [m1, m2, m3, m4] = in;
376 SerializeMultiple(stream, m1, m2, m3, m4);
378 else if constexpr (memberCount == 3)
380 const auto& [m1, m2, m3] = in;
381 SerializeMultiple(stream, m1, m2, m3);
383 else if constexpr (memberCount == 2)
385 const auto& [m1, m2] = in;
386 SerializeMultiple(stream, m1, m2);
388 else if constexpr (memberCount == 1)
390 const auto& [m1] = in;
391 SerializeMultiple(stream, m1);
395template<UnpackableAggregate T>
398 static constexpr auto memberCount = MemberCount<T>();
401 if constexpr (memberCount == 16)
403 auto& [m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16] = out;
404 DeserializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16);
406 else if constexpr (memberCount == 15)
408 auto& [m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15] = out;
409 DeserializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15);
411 else if constexpr (memberCount == 14)
413 auto& [m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14] = out;
414 DeserializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14);
416 else if constexpr (memberCount == 13)
418 auto& [m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13] = out;
419 DeserializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13);
421 else if constexpr (memberCount == 12)
423 auto& [m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12] = out;
424 DeserializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12);
426 else if constexpr (memberCount == 11)
428 auto& [m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11] = out;
429 DeserializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11);
431 else if constexpr (memberCount == 10)
433 auto& [m1, m2, m3, m4, m5, m6, m7, m8, m9, m10] = out;
434 DeserializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10);
436 else if constexpr (memberCount == 9)
438 auto& [m1, m2, m3, m4, m5, m6, m7, m8, m9] = out;
439 DeserializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8, m9);
441 else if constexpr (memberCount == 8)
443 auto& [m1, m2, m3, m4, m5, m6, m7, m8] = out;
444 DeserializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7, m8);
446 else if constexpr (memberCount == 7)
448 auto& [m1, m2, m3, m4, m5, m6, m7] = out;
449 DeserializeMultiple(stream, m1, m2, m3, m4, m5, m6, m7);
451 else if constexpr (memberCount == 6)
453 auto& [m1, m2, m3, m4, m5, m6] = out;
454 DeserializeMultiple(stream, m1, m2, m3, m4, m5, m6);
456 else if constexpr (memberCount == 5)
458 auto& [m1, m2, m3, m4, m5] = out;
459 DeserializeMultiple(stream, m1, m2, m3, m4, m5);
461 else if constexpr (memberCount == 4)
463 auto& [m1, m2, m3, m4] = out;
464 DeserializeMultiple(stream, m1, m2, m3, m4);
466 else if constexpr (memberCount == 3)
468 auto& [m1, m2, m3] = out;
469 DeserializeMultiple(stream, m1, m2, m3);
471 else if constexpr (memberCount == 2)
473 auto& [m1, m2] = out;
474 DeserializeMultiple(stream, m1, m2);
476 else if constexpr (memberCount == 1)
479 DeserializeMultiple(stream, m1);
constexpr nc::serialize::cpo::DeserializeFn Deserialize
Deserialize an object from a stream.
Definition: BinarySerialization.h:47
constexpr nc::serialize::cpo::SerializeFn Serialize
Serialize an object to a stream.
Definition: BinarySerialization.h:41
constexpr size_t g_aggregateMaxMemberCount
The maximum number of members an aggregate may have for default serialization.
Definition: BinarySerialization.h:50