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