SST  15.1.0
StructuralSimulationToolkit
serialize_aggregate.h
1 // Copyright 2009-2025 NTESS. Under the terms
2 // of Contract DE-NA0003525 with NTESS, the U.S.
3 // Government retains certain rights in this software.
4 //
5 // Copyright (c) 2009-2025, NTESS
6 // All rights reserved.
7 //
8 // This file is part of the SST software package. For license
9 // information, see the LICENSE file in the top level directory of the
10 // distribution.
11 
12 #ifndef SST_CORE_SERIALIZATION_IMPL_SERIALIZE_AGGREGATE_H
13 #define SST_CORE_SERIALIZATION_IMPL_SERIALIZE_AGGREGATE_H
14 
15 #ifndef SST_INCLUDING_SERIALIZE_H
16 #warning \
17  "The header file sst/core/serialization/impl/serialize_aggregate.h should not be directly included as it is not part of the stable public API. The file is included in sst/core/serialization/serialize.h"
18 #endif
19 
20 #include "sst/core/serialization/impl/serialize_utility.h"
21 #include "sst/core/serialization/serializer.h"
22 
23 #include <array>
24 #include <cstddef>
25 #include <type_traits>
26 
27 namespace SST::Core::Serialization {
28 
29 /////////////////////////////////////////////////////////////////////////////////////////////////////
30 // Aggregate serialization //
31 // //
32 // An aggregate is a C-style array, std::array, or a class/struct/union with all public non-static //
33 // data members and direct bases, no user-provided, inherited or explicit constructors (C++17), no //
34 // user-declared or inherited constructors (C++20), and no virtual functions or virtual bases. //
35 // //
36 // For aggregates which are either not trivially copyable or are not standard layout types, they //
37 // can be serialized by using structured bindings to extract their members and serialize each //
38 // member separately. The serialization implementation needs to be specialized for each member //
39 // count, because until C++26, structured binding packs are not supported. //
40 // //
41 // For aggregate serialization, //
42 // - It must be an aggregate class type //
43 // - It must not be trivially serializable //
44 // - It must not have a serialize_order() method //
45 // - It must not contain anonymous union members (not detectable in C++17 except by error) //
46 // - The number of fields must be supported by the implementation below //
47 /////////////////////////////////////////////////////////////////////////////////////////////////////
48 
49 namespace pvt {
50 
51 template <typename T, size_t NFIELDS>
52 struct serialize_aggregate_impl : std::false_type
53 {};
54 
55 // Structured binding extracts NFIELDS fields in __VA_ARGS__ and serializes each one separately
56 #define SERIALIZE_AGGREGATE_IMPL(NFIELDS, ...) \
57  template <typename T> \
58  struct serialize_aggregate_impl<T, NFIELDS> : std::true_type \
59  { \
60  void operator()(T& t, serializer& ser, ser_opt_t UNUSED(opt)) \
61  { \
62  auto& [__VA_ARGS__] = t; \
63  [&](auto&... e) { (SST_SER(e), ...); }(__VA_ARGS__); \
64  } \
65  }
66 
67 SERIALIZE_AGGREGATE_IMPL(1, a0);
68 SERIALIZE_AGGREGATE_IMPL(2, a0, a1);
69 SERIALIZE_AGGREGATE_IMPL(3, a0, a1, a2);
70 SERIALIZE_AGGREGATE_IMPL(4, a0, a1, a2, a3);
71 SERIALIZE_AGGREGATE_IMPL(5, a0, a1, a2, a3, a4);
72 SERIALIZE_AGGREGATE_IMPL(6, a0, a1, a2, a3, a4, a5);
73 SERIALIZE_AGGREGATE_IMPL(7, a0, a1, a2, a3, a4, a5, a6);
74 SERIALIZE_AGGREGATE_IMPL(8, a0, a1, a2, a3, a4, a5, a6, a7);
75 SERIALIZE_AGGREGATE_IMPL(9, a0, a1, a2, a3, a4, a5, a6, a7, a8);
76 SERIALIZE_AGGREGATE_IMPL(10, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
77 SERIALIZE_AGGREGATE_IMPL(11, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
78 SERIALIZE_AGGREGATE_IMPL(12, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
79 SERIALIZE_AGGREGATE_IMPL(13, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
80 SERIALIZE_AGGREGATE_IMPL(14, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13);
81 SERIALIZE_AGGREGATE_IMPL(15, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14);
82 SERIALIZE_AGGREGATE_IMPL(16, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15);
83 SERIALIZE_AGGREGATE_IMPL(17, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16);
84 SERIALIZE_AGGREGATE_IMPL(18, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17);
85 SERIALIZE_AGGREGATE_IMPL(19, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18);
86 SERIALIZE_AGGREGATE_IMPL(20, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19);
87 
88 // An aggregate class type with no serialize_order() method, an implementation of serialize_aggregate_impl for the
89 // number of fields, and not trivially serializable
90 template <typename T>
91 constexpr bool is_aggregate_serializable_v =
92  std::conjunction_v<std::is_class<T>, std::is_aggregate<T>, std::negation<has_serialize_order<T>>,
93  serialize_aggregate_impl<T, nfields<T>>, std::negation<is_trivially_serializable<T>>>;
94 
95 // std::array is excluded because it is handled in serialize_array.h
96 template <typename T, size_t N>
97 constexpr bool is_aggregate_serializable_v<std::array<T, N>> = false;
98 
99 } // namespace pvt
100 
101 // Serialize aggregate class types which are not trivially serializable
102 template <typename T>
103 class serialize_impl<T, std::enable_if_t<pvt::is_aggregate_serializable_v<T>>> :
104  pvt::serialize_aggregate_impl<T, nfields<T>>
105 {
106  SST_FRIEND_SERIALIZE();
107 };
108 
109 } // namespace SST::Core::Serialization
110 
111 #endif // SST_CORE_SERIALIZATION_IMPL_SERIALIZE_AGGREGATE_H
Base serialize class.
Definition: serialize.h:113