SST  15.1.0
StructuralSimulationToolkit
serialize_array.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_ARRAY_H
13 #define SST_CORE_SERIALIZATION_IMPL_SERIALIZE_ARRAY_H
14 
15 #ifndef SST_INCLUDING_SERIALIZE_H
16 #warning \
17  "The header file sst/core/serialization/impl/serialize_array.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/serializer.h"
21 
22 #include <array>
23 #include <cstddef>
24 #include <type_traits>
25 
26 namespace SST::Core::Serialization {
27 
28 // Serialize arrays
29 
30 namespace pvt {
31 
32 // Wrapper classes. They have no declared constructors so that they can be aggregate-initialized.
33 template <typename ELEM_T, typename SIZE_T>
35 {
36  ELEM_T*& ptr;
37  SIZE_T& size;
38 };
39 
40 template <typename ELEM_T>
42 {
43  ELEM_T*& ptr;
44 };
45 
46 // Functions for serializing arrays element by element
47 void serialize_array(serializer& ser, void* data, ser_opt_t opt, size_t size,
48  void serialize_array_element(serializer& ser, void* data, ser_opt_t opt, size_t index));
49 
50 void serialize_array_map(serializer& ser, void* data, ser_opt_t opt, size_t size, ObjectMap* map,
51  void serialize_array_map_element(serializer& ser, void* data, ser_opt_t opt, size_t index, const char* name));
52 
53 // Serialize an array element
54 // Separated out to reduce code size
55 template <typename ELEM_T>
56 void
57 serialize_array_element(serializer& ser, void* data, ser_opt_t opt, size_t index)
58 {
59  SST_SER(static_cast<ELEM_T*>(data)[index], opt);
60 }
61 
62 // Serialize an array map element
63 // Separated out to reduce code size
64 template <typename ELEM_T>
65 void
66 serialize_array_map_element(serializer& ser, void* data, ser_opt_t opt, size_t index, const char* name)
67 {
68  SST_SER_NAME(static_cast<ELEM_T*>(data)[index], name, opt);
69 }
70 
71 // Serialize fixed arrays
72 // ELEM_T: Array element type
73 // SIZE: Fixed array size
74 // OBJ_TYPE: Complete type of object being serialized
75 template <typename OBJ_TYPE, typename ELEM_T, size_t SIZE>
77 {
78  void operator()(OBJ_TYPE& ary, serializer& ser, ser_opt_t opt)
79  {
80  ser_opt_t elem_opt = SerOption::is_set(opt, SerOption::as_ptr_elem) ? SerOption::as_ptr : SerOption::none;
81  const auto& aPtr = get_ptr(ary); // reference to ary if it's a pointer; &ary otherwise
82  switch ( ser.mode() ) {
83  case serializer::MAP:
84  serialize_array_map(ser, &(*aPtr)[0], elem_opt, SIZE, new ObjectMapArray<ELEM_T>(&(*aPtr)[0], SIZE),
85  serialize_array_map_element<ELEM_T>);
86  break;
87 
88  case serializer::UNPACK:
89  if constexpr ( std::is_pointer_v<OBJ_TYPE> ) {
90  // for pointers to fixed arrays, we allocate the storage
91  ary = reinterpret_cast<OBJ_TYPE>(new std::remove_pointer_t<OBJ_TYPE>);
92  }
93  [[fallthrough]];
94 
95  default:
96  // TODO: How to handle array-of-array
97  // is_trivially_serializable_excluded_v<ELEM_T> can be added to exclude arrays-of-arrays from the fast path
98  if constexpr ( is_trivially_serializable_v<ELEM_T> )
99  ser.raw(&(*aPtr)[0], sizeof(ELEM_T) * SIZE);
100  else
101  serialize_array(ser, &(*aPtr)[0], elem_opt, SIZE, serialize_array_element<ELEM_T>);
102  break;
103  }
104  }
105 };
106 
107 } // namespace pvt
108 
109 // Serialize fixed arrays and pointers to them
110 template <typename ELEM_T, size_t SIZE>
111 class serialize_impl<ELEM_T[SIZE]> : pvt::serialize_impl_fixed_array<ELEM_T[SIZE], ELEM_T, SIZE>
112 {
113  SST_FRIEND_SERIALIZE();
114 };
115 
116 template <typename ELEM_T, size_t SIZE>
117 class serialize_impl<std::array<ELEM_T, SIZE>> : pvt::serialize_impl_fixed_array<std::array<ELEM_T, SIZE>, ELEM_T, SIZE>
118 {
119  SST_FRIEND_SERIALIZE();
120 };
121 
122 template <typename ELEM_T, size_t SIZE>
123 class serialize_impl<ELEM_T (*)[SIZE]> : pvt::serialize_impl_fixed_array<ELEM_T (*)[SIZE], ELEM_T, SIZE>
124 {
125  SST_FRIEND_SERIALIZE();
126 };
127 
128 template <typename ELEM_T, size_t SIZE>
129 class serialize_impl<std::array<ELEM_T, SIZE>*> :
130  pvt::serialize_impl_fixed_array<std::array<ELEM_T, SIZE>*, ELEM_T, SIZE>
131 {
132  SST_FRIEND_SERIALIZE();
133 };
134 
135 // Serialize dynamic arrays
136 template <typename ELEM_T, typename SIZE_T>
137 class serialize_impl<pvt::array_wrapper<ELEM_T, SIZE_T>>
138 {
139  void operator()(pvt::array_wrapper<ELEM_T, SIZE_T>& ary, serializer& ser, ser_opt_t opt)
140  {
141  ser_opt_t elem_opt = SerOption::is_set(opt, SerOption::as_ptr_elem) ? SerOption::as_ptr : SerOption::none;
142  const auto mode = ser.mode();
143  size_t size = 0;
144 
145  if ( mode != serializer::UNPACK )
146  size = get_array_size(ary.size, "Serialization Error: Array size in SST::Core::Serialization::array() "
147  "cannot fit inside size_t. size_t should be used for array sizes.\n");
148 
149  if ( mode == serializer::MAP ) {
150  if constexpr ( !std::is_void_v<ELEM_T> ) {
151  pvt::serialize_array_map(ser, ary.ptr, elem_opt, size, new ObjectMapArray<ELEM_T>(ary.ptr, size),
152  pvt::serialize_array_map_element<ELEM_T>);
153  }
154  return;
155  }
156 
157  // TODO: How to handle array-of-array
158  // is_trivially_serializable_excluded_v<ELEM_T> can be added to exclude arrays-of-arrays from the fast path
159  if constexpr ( std::is_void_v<ELEM_T> || is_trivially_serializable_v<ELEM_T> )
160  ser.binary(ary.ptr, size);
161  else {
162  ser.primitive(size);
163  if ( mode == serializer::UNPACK ) ary.ptr = new ELEM_T[size];
164  pvt::serialize_array(ser, ary.ptr, elem_opt, size, pvt::serialize_array_element<ELEM_T>);
165  }
166  if ( mode == serializer::UNPACK ) ary.size = static_cast<SIZE_T>(size);
167  }
168 
169  SST_FRIEND_SERIALIZE();
170 };
171 
172 /**
173  Version of serialize that works for copying raw pointers (only
174  copying the value of the pointer. Note that this is only useful
175  if the value is going to be sent back to the originator, since it
176  won't be valid on the other rank.
177  */
178 template <typename ELEM_T>
179 struct serialize_impl<pvt::raw_ptr_wrapper<ELEM_T>>
180 {
181  void operator()(pvt::raw_ptr_wrapper<ELEM_T>& a, serializer& ser, ser_opt_t UNUSED(opt)) { ser.primitive(a.ptr); }
182  SST_FRIEND_SERIALIZE();
183 };
184 
185 // Wrapper functions
186 
187 template <typename ELEM_T, typename SIZE_T>
189 array(ELEM_T*& ptr, SIZE_T& size)
190 {
191  return { ptr, size };
192 }
193 
194 template <typename SIZE_T>
195 pvt::array_wrapper<void, SIZE_T>
196 buffer(void*& ptr, SIZE_T& size)
197 {
198  return { ptr, size };
199 }
200 
201 template <typename ELEM_T>
202 pvt::raw_ptr_wrapper<ELEM_T>
203 raw_ptr(ELEM_T*& ptr)
204 {
205  return { ptr };
206 }
207 
208 } // namespace SST::Core::Serialization
209 
210 #endif // SST_CORE_SERIALIZATION_IMPL_SERIALIZE_ARRAY_H
Definition: serialize_array.h:34
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition: serializer.h:42
Base serialize class.
Definition: serialize.h:113
Base class for objects created by the serializer mapping mode used to map the variables for objects...
Definition: objectMap.h:158
Class used to map arrays.
Definition: objectMap.h:1480
Definition: serialize_array.h:41