SST  15.1.0
StructuralSimulationToolkit
serialize_shared_ptr.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_SHARED_PTR_H
13 #define SST_CORE_SERIALIZATION_IMPL_SERIALIZE_SHARED_PTR_H
14 
15 #ifndef SST_INCLUDING_SERIALIZE_H
16 #warning \
17  "The header file sst/core/serialization/impl/serialize_shared_ptr.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/output.h"
21 #include "sst/core/serialization/serializer.h"
22 
23 #include <cstddef>
24 #include <memory>
25 #include <type_traits>
26 #include <utility>
27 
28 namespace SST::Core::Serialization {
29 
30 namespace pvt {
31 
32 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
33 // Strings for error messages based on the types of shared pointers
34 template <template <class> class PTR_TEMPLATE>
35 constexpr auto ptr_string =
36  [] { static_assert(!is_same_template_v<PTR_TEMPLATE, PTR_TEMPLATE>, "Bad ptr_string template argument"); };
37 
38 template <>
39 constexpr inline char ptr_string<std::weak_ptr>[] = "weak_ptr";
40 
41 template <>
42 constexpr inline char ptr_string<std::shared_ptr>[] = "shared_ptr";
43 
44 template <template <class> class PTR_TEMPLATE>
45 constexpr auto array_size_string =
46  [] { static_assert(!is_same_template_v<PTR_TEMPLATE, PTR_TEMPLATE>, "Bad array_size_string template argument"); };
47 
48 template <>
49 constexpr inline char array_size_string<std::weak_ptr>[] =
50  "Serialization Error: Array size in SST::Core::Serialization::weak_ptr() cannot fit inside size_t. size_t should "
51  "be used for array sizes.\n";
52 
53 template <>
54 constexpr inline char array_size_string<std::shared_ptr>[] =
55  "Serialization Error: Array size in SST::Core::Serialization::shared_ptr() cannot fit inside size_t. size_t should "
56  "be used for array sizes.\n";
57 
58 template <template <class> class PTR_TEMPLATE, class PARENT_TYPE>
59 constexpr auto wrapper_string =
60  [] { static_assert(!is_same_template_v<PTR_TEMPLATE, PTR_TEMPLATE>, "Bad wrapper_string template arguments"); };
61 
62 template <class PARENT_TYPE>
63 constexpr char wrapper_string<std::weak_ptr, PARENT_TYPE>[] =
64  "SST::Core::Serialization::weak_ptr(std::weak_ptr<PTR_TYPE>& ptr, std::shared_ptr<PARENT_TYPE>& parent)";
65 
66 template <class PARENT_ELEM_TYPE>
67 constexpr char wrapper_string<std::weak_ptr, PARENT_ELEM_TYPE[]>[] =
68  "SST::Core::Serialization::weak_ptr(std::weak_ptr<PTR_TYPE>& ptr, std::shared_ptr<PARENT_TYPE>& parent, SIZE_T& "
69  "size)";
70 
71 template <class PARENT_TYPE>
72 constexpr char wrapper_string<std::shared_ptr, PARENT_TYPE>[] =
73  "SST::Core::Serialization::shared_ptr(std::shared_ptr<PTR_TYPE>& ptr, std::shared_ptr<PARENT_TYPE>& parent)";
74 
75 template <class PARENT_ELEM_TYPE>
76 constexpr char wrapper_string<std::shared_ptr, PARENT_ELEM_TYPE[]>[] =
77  "SST::Core::Serialization::shared_ptr(std::shared_ptr<PTR_TYPE>& ptr, std::shared_ptr<PARENT_TYPE>& parent, "
78  "SIZE_T& size)";
79 
80 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
81 // Get the tag for the owner of a std::shared_ptr or std::weak_ptr and whether it has been seen before
82 template <template <class> class PTR_TEMPLATE, class PTR_TYPE>
83 std::pair<size_t, bool>
84 get_shared_ptr_owner_tag(const PTR_TEMPLATE<PTR_TYPE>& ptr, serializer& ser)
85 {
86  // Workaround for libstdc++ bug 120561 which prevents converting std::weak_ptr<array> to std::weak_ptr<const void>
87  if constexpr ( std::conjunction_v<is_same_template<PTR_TEMPLATE, std::weak_ptr>, std::is_array<PTR_TYPE>> ) {
88  // We set weak_ptr on a separate statement so that ptr's shared_ptr refcount is restored before return statement
89  std::weak_ptr<const void> weak_ptr = ptr.lock();
90 
91  // Return this function using the newly cast std::weak_ptr<const void> instead of std::weak_ptr<array>
92  return get_shared_ptr_owner_tag(weak_ptr, ser);
93  }
94  else {
95  if ( ser.mode() == serializer::SIZER )
96  return ser.sizer().get_shared_ptr_owner_tag(ptr);
97  else
98  return ser.packer().get_shared_ptr_owner_tag(ptr);
99  }
100 }
101 
102 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
103 // Pack the address stored in a shared pointer.
104 //
105 // Although abitrary addresses are allowed to be stored in "aliasing" shared pointers, in order to serialize them, we
106 // assume that the stored addresses are in a limited-range offset within a specified std::shared_ptr parent. To support
107 // arbitrary pointers stored in shared pointers, we would need another pointer tracking mechanism.
108 template <template <class> class PTR_TEMPLATE, class PTR_TYPE, class PARENT_TYPE>
109 void
110 pack_shared_ptr_address(
111  const PTR_TEMPLATE<PTR_TYPE>& ptr, const std::shared_ptr<PARENT_TYPE>& parent, size_t* size, serializer& ser)
112 {
113  // If ptr is a std::shared_ptr, stored address is returned by get()
114  // if ptr is a std::weak_ptr, we have to temporarily lock() it to get() the stored address
115  const void* addr;
116  if constexpr ( is_same_template_v<PTR_TEMPLATE, std::shared_ptr> )
117  addr = ptr.get();
118  else
119  addr = ptr.lock().get();
120 
121  // Whether the stored address is not a nullptr
122  bool nonnull = addr != nullptr;
123  ser.primitive(nonnull);
124 
125  // If not null, serialize the offset of the pointer's stored address with its parent's stored address
126  if ( nonnull ) {
127  const void* parent_addr = parent.get();
128 
129  if ( !parent_addr )
130  Output::getDefaultObject().fatal(__LINE__, __FILE__, __func__, 1,
131  "Serialization Error: Serialized std::%s has a non-null stored pointer, but the parent specified by %s "
132  "has a null stored pointer.\nThere is no way to know how this raw pointer should be serialized.\n",
133  ptr_string<PTR_TEMPLATE>, wrapper_string<PTR_TEMPLATE, PARENT_TYPE>);
134 
135  // Offset of the shared pointer's stored address relative to the parent's address
136  ptrdiff_t offset = static_cast<const char*>(addr) - static_cast<const char*>(parent_addr);
137 
138  // Compute parent object size, which depends on a variable size when PARENT_TYPE is an unbounded array type
139  size_t parent_size;
140  if constexpr ( is_unbounded_array_v<PARENT_TYPE> )
141  parent_size = *size * sizeof(std::remove_extent_t<PARENT_TYPE>);
142  else
143  parent_size = sizeof(PARENT_TYPE);
144 
145  // Make sure that the address offset is inside of the parent or one byte past the end
146  if ( offset < 0 || static_cast<size_t>(offset) > parent_size )
147  Output::getDefaultObject().fatal(__LINE__, __FILE__, __func__, 1,
148  "Serialization Error: Serialized std::%s has a stored pointer outside of the bounds of the parent "
149  "specified by %s.\nThere is no way to know how this raw pointer should be serialized.\n",
150  ptr_string<PTR_TEMPLATE>, wrapper_string<PTR_TEMPLATE, PARENT_TYPE>);
151 
152  // Serialize the address offset
153  ser.primitive(offset);
154  }
155 }
156 
157 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
158 // Pack the parent owner of a shared pointer, which is done the first time an ownership tag is seen
159 template <class PARENT_TYPE>
160 void
161 pack_shared_ptr_parent(const std::shared_ptr<PARENT_TYPE>& parent, size_t* size, serializer& ser, ser_opt_t opt)
162 {
163  // OWNER_TYPE is PARENT_TYPE with cv-qualifiers removed so that it can be serialized
164  using OWNER_TYPE = std::remove_cv_t<PARENT_TYPE>;
165 
166  // ELEM_TYPE is the element type if OWNER_TYPE is an array, otherwise it is the same as OWNER_TYPE
167  using ELEM_TYPE = std::remove_extent_t<OWNER_TYPE>;
168 
169  // Address of parent object
170  OWNER_TYPE* parent_addr = const_cast<OWNER_TYPE*>(reinterpret_cast<const OWNER_TYPE*>(parent.get()));
171 
172  // Serialize whether the parent pointer is null
173  bool nonnull = parent_addr != nullptr;
174  ser.primitive(nonnull);
175 
176  // If the parent pointer is not null, serialize the parent object
177  if ( nonnull ) {
178  if constexpr ( is_unbounded_array_v<OWNER_TYPE> ) {
179  // If the parent owner object is an unbounded array
180 
181  // Serialize the array size
182  ser.primitive(*size);
183 
184  // Serialize the array elements
185  if constexpr ( is_trivially_serializable_v<ELEM_TYPE> )
186  ser.raw(parent_addr, *size * sizeof(ELEM_TYPE));
187  else
188  serialize_array(ser, parent_addr, opt, *size, serialize_array_element<ELEM_TYPE>);
189  }
190  else {
191  // If the parent owner object is not an unbounded array
192 
193  // Serialize the parent owner object
194  SST_SER(*parent_addr, opt);
195  }
196  }
197 }
198 
199 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
200 // Unpack a shared pointer owner, finding or creating a std::shared_ptr owner with a particular tag
201 template <class PARENT_TYPE>
202 const std::shared_ptr<void>&
203 unpack_shared_ptr_owner(size_t tag, std::shared_ptr<PARENT_TYPE>& parent, size_t* size, serializer& ser, ser_opt_t opt)
204 {
205  // OWNER_TYPE is PARENT_TYPE with cv-qualifiers removed so that it can be deserialized
206  using OWNER_TYPE = std::remove_cv_t<PARENT_TYPE>;
207 
208  // ELEM_TYPE is the element type if OWNER_TYPE is an array, otherwise it is the same as OWNER_TYPE
209  using ELEM_TYPE = std::remove_extent_t<OWNER_TYPE>;
210 
211  // Look for the std::shared_ptr owner of the tag, creating a new empty one if the tag has not been seen before.
212  // auto&& acts like a universal reference for each member.
213  auto&& [owner, is_new_tag] = ser.unpacker().get_shared_ptr_owner(tag);
214 
215  // Important: owner must be a lvalue reference to a std::shared_ptr<void> so that the code below modifies the
216  // std::shared_ptr owner stored in a table indexed by tag. The control block of the owner created here is used
217  // now and in all future std::shared_ptr or std::weak_ptr deserializations of the same ownership tag.
218  static_assert(std::is_same_v<decltype(owner), std::shared_ptr<void>&>);
219 
220  // If the tag has not been seen before, deserialize the parent object.
221  if ( is_new_tag ) {
222  // Deserialize whether the parent pointer is null
223  bool nonnull = false;
224  ser.primitive(nonnull);
225 
226  // If the parent pointer is nonnull, allocate the new owner object
227  if ( nonnull ) {
228  if constexpr ( is_unbounded_array_v<OWNER_TYPE> ) {
229  // If the parent type is an unbounded array
230 
231  // Deserialize the size
232  ser.primitive(*size);
233 
234  // Allocate a std::shared_ptr for the parent. std::make_shared supports arrays only on C++20
235  // On C++17 a std::unique_ptr allocated for unbounded arrays can be transferred to a std::shared_ptr
236  if constexpr ( __cplusplus < 202002l )
237  owner = std::make_unique<OWNER_TYPE>(*size);
238  else
239  owner = std::make_shared<OWNER_TYPE>(*size);
240 
241  // Deserialize the array elements in the parent object
242  if constexpr ( is_trivially_serializable_v<ELEM_TYPE> )
243  ser.raw(owner.get(), *size * sizeof(ELEM_TYPE));
244  else
245  serialize_array(ser, owner.get(), opt, *size, serialize_array_element<ELEM_TYPE>);
246  }
247  else {
248  // If the parent type is not an unbounded array
249 
250  // Allocate a std::shared_ptr for the parent. std::make_shared supports arrays only on C++20
251  if constexpr ( std::is_array_v<OWNER_TYPE> && __cplusplus < 202002l )
252  owner = std::shared_ptr<OWNER_TYPE>(new ELEM_TYPE[std::extent_v<OWNER_TYPE>]());
253  else
254  owner = std::make_shared<OWNER_TYPE>();
255 
256  // Deserialize the parent owner object
257  SST_SER(*static_cast<OWNER_TYPE*>(owner.get()));
258  }
259  }
260 
261  // Set the parent to the owning std::shared_ptr, analogous to casting from void* to PARENT_TYPE*
262  parent = std::static_pointer_cast<PARENT_TYPE>(owner);
263  }
264  return owner;
265 }
266 
267 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
269 {
270  // Pointer to unbounded array size
271  size_t* const size;
272 
273 public:
274  // Optional size argument is pointer to unbounded array size
275  explicit serialize_shared_ptr_impl(size_t* size = nullptr) :
276  size(size)
277  {}
278 
279  // Serialize a std::shared_ptr or std::weak_ptr whose ownership is managed by a std::shared_ptr parent. The types of
280  // the pointees, PTR_TYPE and PARENT_TYPE, do not need to be the same, since a std::shared_ptr or std::weak_ptr can
281  // point to a sub-object of a managed object. PTR_TEMPLATE<PTR_TYPE> matches either the std::shared_ptr or the
282  // std::weak_ptr being serialized.
283 
284  template <template <class> class PTR_TEMPLATE, class PTR_TYPE, class PARENT_TYPE>
285  void operator()(PTR_TEMPLATE<PTR_TYPE>& ptr, std::shared_ptr<PARENT_TYPE>& parent, serializer& ser, ser_opt_t opt)
286  {
287  switch ( ser.mode() ) {
288  case serializer::SIZER:
289  case serializer::PACK:
290  {
291  // Make sure that ptr and parent have the same owning control block or both have an empty control block
292  auto owner_ne = [](const auto& a, const auto& b) { return a.owner_before(b) || b.owner_before(a); };
293 
294  // If ptr is an expired std::weak_ptr, expect parent to be an empty pointer for the purposes of this test
295  if ( ptr.use_count() ? owner_ne(parent, ptr) : owner_ne(parent, PTR_TEMPLATE<PTR_TYPE>()) )
296  Output::getDefaultObject().fatal(__LINE__, __FILE__, __func__, 1,
297  "Serialization Error: Serialized std::%s does not have the same owning control block as the parent "
298  "specified by %s.\n",
299  ptr_string<PTR_TEMPLATE>, wrapper_string<PTR_TEMPLATE, PARENT_TYPE>);
300 
301  // Get the tag of this shared pointer's control block and whether this is the first time it has been seen
302  // A tag of 0 indicates a missing control block
303  auto [tag, is_new_tag] = get_shared_ptr_owner_tag(ptr, ser);
304 
305  // Serialize the ownership tag of the control block
306  ser.primitive(tag);
307 
308  // If there is a control block, serialize the address stored in the shared pointer
309  if ( tag != 0 ) pack_shared_ptr_address(ptr, parent, size, ser);
310 
311  // If this is the first use of the tag of the owning control block, serialize the parent object
312  if ( is_new_tag ) pack_shared_ptr_parent(parent, size, ser, opt);
313  break;
314  }
315 
316  case serializer::UNPACK:
317  {
318  // Reset the std::shared_ptr or std::weak_ptr so that it is empty
319  ptr.reset();
320 
321  // A tag represents a control block which holds ownership of a std::shared_ptr or std::weak_ptr
322  size_t tag = 0;
323 
324  // Deserialize the tag
325  ser.primitive(tag);
326 
327  // A tag of 0 indicates an empty std::shared_ptr or std::weak_ptr without a control block
328  if ( tag != 0 ) {
329  // Deserialize whether the pointer is null
330  bool nonnull = false;
331  ser.primitive(nonnull);
332 
333  // If it is not null, deserialize the offset
334  ptrdiff_t offset = 0;
335  if ( nonnull ) ser.primitive(offset);
336 
337  // Find the owner of this pointer's control block based on tag, deserializing the parent if it is new
338  const std::shared_ptr<void>& owner = unpack_shared_ptr_owner(tag, parent, size, ser, opt);
339 
340  // At this point, "owner" references a std::shared_ptr<void> which owns the control block for "tag",
341  // whether it was newly allocated, or whether it was retrieved from the table holding it for the tag.
342 
343  // ELEM_TYPE is the array element type if PTR_TYPE is an array type, PTR_TYPE otherwise
344  using ELEM_TYPE = std::remove_extent_t<PTR_TYPE>;
345 
346  // The pointer stored inside of "ptr" is either nullptr, or an offset within the owner std::shared_ptr
347  ELEM_TYPE* addr =
348  nonnull ? reinterpret_cast<ELEM_TYPE*>(static_cast<char*>(owner.get()) + offset) : nullptr;
349 
350  // Set the std::shared_ptr or std::weak_ptr to either nullptr, or to an offset within the owner.
351  // What is very important, is that "ptr" must have the same control block as "owner".
352  ptr = std::shared_ptr<PTR_TYPE>(owner, addr);
353  }
354  break;
355  }
356 
357  case serializer::MAP:
358  {
359  // TODO: Mapping std::shared_ptr or std::weak_ptr
360  break;
361  }
362  }
363  }
364 }; // class serialize_shared_ptr_impl
365 
366 } // namespace pvt
367 
368 // Serialize a std::shared_ptr, assuming that it points to the beginning of the managed object.
369 // For std::shared_ptr to unbounded arrays with runtime size, the wrapper function must be used.
370 // std::shared_ptr to functions is not supported.
371 template <class PTR_TYPE>
372 class serialize_impl<std::shared_ptr<PTR_TYPE>,
373  std::enable_if_t<!is_unbounded_array_v<PTR_TYPE> && !std::is_function_v<PTR_TYPE>>>
374 {
375  void operator()(std::shared_ptr<PTR_TYPE>& ptr, serializer& ser, ser_opt_t opt)
376  {
377  ser_opt_t elem_opt = SerOption::is_set(opt, SerOption::as_ptr_elem) ? SerOption::as_ptr : SerOption::none;
378 
379  // The std::shared_ptr is considered its own parent owning the managed storage
380  pvt::serialize_shared_ptr_impl()(ptr, ptr, ser, elem_opt);
381  }
382  SST_FRIEND_SERIALIZE();
383 };
384 
385 // Serialize a std::weak_ptr, assuming that it points to the beginning of the managed object.
386 // For std::weak_ptr to unbounded arrays with runtime size, the wrapper function must be used.
387 // std::weak_ptr to functions is not supported.
388 template <class PTR_TYPE>
389 class serialize_impl<std::weak_ptr<PTR_TYPE>,
390  std::enable_if_t<!is_unbounded_array_v<PTR_TYPE> && !std::is_function_v<PTR_TYPE>>>
391 {
392  void operator()(std::weak_ptr<PTR_TYPE>& ptr, serializer& ser, ser_opt_t opt)
393  {
394  ser_opt_t elem_opt = SerOption::is_set(opt, SerOption::as_ptr_elem) ? SerOption::as_ptr : SerOption::none;
395 
396  // A temporary std::shared_ptr created from a std::weak_ptr acts as the parent owning the shared object. This
397  // std::shared_ptr will be destroyed at the end of this function, but it will be passed by reference for the
398  // (de)serialization of std::weak_ptr, and in the case of deserialization, a copy of the std::shared_ptr to
399  // the managed object will be saved in a table for use during the rest of the deserialization, where it can
400  // be copied into one or more std::shared_ptr or std::weak_ptr instances which are deserialized. This allows
401  // a std::weak_ptr to be deserialized before its owning std::shared_ptr is deserialized.
402  std::shared_ptr<PTR_TYPE> parent = ptr.lock();
403  pvt::serialize_shared_ptr_impl()(ptr, parent, ser, elem_opt);
404  }
405  SST_FRIEND_SERIALIZE();
406 };
407 
408 namespace pvt {
409 
410 // Wrapper class which references a std::shared_ptr or std::weak_ptr and a std::shared_ptr which manages ownership
411 //
412 // PTR_TEMPLATE: std::shared_ptr or std::weak_ptr, the template of the type being serialized
413 //
414 // PTR_TYPE: The pointee type of the std::shared_ptr or std::weak_ptr pointer. PTR_TEMPLATE<PTR_TYPE> is the type
415 // of the object being serialized.
416 //
417 // PARENT_TYPE: The pointee type of the std::shared_ptr<PARENT_TYPE> owning object. Every std::shared_ptr or
418 // std::weak_ptr is associated with a std::shared_ptr owner which is not necessarily the same pointee type.
419 //
420 // SIZE_T: An integral type used to hold the size of arrays when PARENT_TYPE is an unbounded array type T[].
421 //
422 // OWNER_TYPE: Either std::shared_ptr<PARENT_TYPE>& or std::shared_ptr<PARENT_TYPE>, the type of the owning parent
423 // used by this wrapper. When OWNER_TYPE is an lvalue reference, OWNER_TYPE&& parent collapses into an lvalue
424 // reference which must be bound to an lvalue owner. When OWNER_TYPE is not an lvalue reference, OWNER_TYPE&&
425 // parent is an rvalue reference which must be bound to an rvalue owner such as a temporary returned by
426 // std::weak_ptr::lock() when the std::weak_ptr has an unspecified owner.
427 //
428 // TODO: Add DELETER template parameter and deleter member, to support arbitrary deleters
429 
430 template <template <class> class PTR_TEMPLATE, class PTR_TYPE, class PARENT_TYPE = PTR_TYPE, class SIZE_T = void,
431  class OWNER_TYPE = std::shared_ptr<PARENT_TYPE>&>
433 {
434  PTR_TEMPLATE<PTR_TYPE>& ptr;
435  OWNER_TYPE&& parent;
436 };
437 
438 // Specialization for unbounded arrays which has a reference to a size
439 template <template <class> class PTR_TEMPLATE, class PTR_TYPE, class PARENT_ELEM_TYPE, class SIZE_T, class OWNER_TYPE>
440 struct shared_ptr_wrapper<PTR_TEMPLATE, PTR_TYPE, PARENT_ELEM_TYPE[], SIZE_T, OWNER_TYPE>
441 {
442  PTR_TEMPLATE<PTR_TYPE>& ptr;
443  OWNER_TYPE&& parent;
444  SIZE_T& size;
445 };
446 
447 } // namespace pvt
448 
449 // Serialize a std::shared_ptr or std::weak_ptr with another std::shared_ptr object which manages the shared object
450 // std::shared_ptr or std::weak_ptr to functions is not supported
451 template <template <class> class PTR_TEMPLATE, class PTR_TYPE, class PARENT_TYPE, class SIZE_T, class OWNER_TYPE>
452 class serialize_impl<pvt::shared_ptr_wrapper<PTR_TEMPLATE, PTR_TYPE, PARENT_TYPE, SIZE_T, OWNER_TYPE>,
453  std::enable_if_t<!std::is_function_v<PTR_TYPE>>>
454 {
456  serializer& ser, ser_opt_t opt)
457  {
458  ser_opt_t elem_opt = SerOption::is_set(opt, SerOption::as_ptr_elem) ? SerOption::as_ptr : SerOption::none;
459  if constexpr ( !is_unbounded_array_v<PARENT_TYPE> ) {
460  // If PARENT_TYPE is not an unbounded array
461  pvt::serialize_shared_ptr_impl()(ptr.ptr, ptr.parent, ser, elem_opt);
462  }
463  else if constexpr ( std::is_same_v<SIZE_T, size_t> ) {
464  // If PARENT_TYPE is an unbounded array, pass address of size_t size parameter
465  pvt::serialize_shared_ptr_impl { &ptr.size }(ptr.ptr, ptr.parent, ser, elem_opt);
466  }
467  else {
468  // If PARENT_TYPE is an unbounded array, handle non-size_t size parameter
469  const auto mode = ser.mode();
470  size_t size = 0;
471  if ( mode != serializer::UNPACK ) size = get_array_size(ptr.size, pvt::array_size_string<PTR_TEMPLATE>);
472  pvt::serialize_shared_ptr_impl { &size }(ptr.ptr, ptr.parent, ser, elem_opt);
473  if ( mode == serializer::UNPACK ) ptr.size = static_cast<SIZE_T>(size);
474  }
475  }
476  SST_FRIEND_SERIALIZE();
477 };
478 
479 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
480 // std::shared_ptr wrappers
481 
482 // SST_SER( SST::Core::Serialization::shared_ptr( std::shared_ptr&, std::shared:ptr& ) ) serializes a std::shared_ptr
483 // with a parent std::shared_ptr managing the owned object.
484 template <class PTR_TYPE, class PARENT_TYPE>
485 std::enable_if_t<!is_unbounded_array_v<PARENT_TYPE>, pvt::shared_ptr_wrapper<std::shared_ptr, PTR_TYPE, PARENT_TYPE>>
486 shared_ptr(std::shared_ptr<PTR_TYPE>& ptr, std::shared_ptr<PARENT_TYPE>& parent)
487 {
488  return { ptr, parent };
489 }
490 
491 // SST_SER( SST::Core::Serialization::shared_ptr( std::shared_ptr&, SIZE_T& size ) ) serializes a std::shared_ptr
492 // managing the owned object when the pointer is to an unbounded array of size "size".
493 template <class PTR_TYPE, class SIZE_T>
494 std::enable_if_t<is_unbounded_array_v<PTR_TYPE>, pvt::shared_ptr_wrapper<std::shared_ptr, PTR_TYPE, PTR_TYPE, SIZE_T>>
495 shared_ptr(std::shared_ptr<PTR_TYPE>& ptr, SIZE_T& size)
496 {
497  return { ptr, ptr, size };
498 }
499 
500 // SST_SER( SST::Core::Serialization::shared_ptr( std::shared_ptr&, std::shared:ptr&, SIZE_T& size ) ) serializes a
501 // std::shared_ptr with a parent std::shared_ptr managing the owned object when the pointer is to an unbounded array of
502 // size "size".
503 template <class PTR_TYPE, class PARENT_TYPE, class SIZE_T>
504 std::enable_if_t<is_unbounded_array_v<PARENT_TYPE>,
505  pvt::shared_ptr_wrapper<std::shared_ptr, PTR_TYPE, PARENT_TYPE, SIZE_T>>
506 shared_ptr(std::shared_ptr<PTR_TYPE>& ptr, std::shared_ptr<PARENT_TYPE>& parent, SIZE_T& size)
507 {
508  return { ptr, parent, size };
509 }
510 
511 // Identity operation for consistency -- SST_SER( SST::Core::Serialization::shared_ptr(ptr) ) is same as SST_SER(ptr).
512 template <class PTR_TYPE>
513 std::shared_ptr<PTR_TYPE>&
514 shared_ptr(std::shared_ptr<PTR_TYPE>& ptr)
515 {
516  return ptr;
517 }
518 
519 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
520 // std::weak_ptr wrappers
521 
522 // SST_SER( SST::Core::Serialization::weak_ptr( std::weak_ptr&, std::shared:ptr& ) ) serializes a std::weak_ptr with a
523 // parent std::shared_ptr managing the owned object.
524 template <class PTR_TYPE, class PARENT_TYPE>
525 std::enable_if_t<!is_unbounded_array_v<PARENT_TYPE>, pvt::shared_ptr_wrapper<std::weak_ptr, PTR_TYPE, PARENT_TYPE>>
526 weak_ptr(std::weak_ptr<PTR_TYPE>& ptr, std::shared_ptr<PARENT_TYPE>& parent)
527 {
528  return { ptr, parent };
529 }
530 
531 // SST_SER( SST::Core::Serialization::weak_ptr( std::weak_ptr&, SIZE_T& size& ) ) serializes a std::weak_ptr with an
532 // unspecified std::shared_ptr managing the owned object when the pointer is to an unbounded array of size "size". See
533 // comments above about ptr.lock() being used to get a temporary std::shared_ptr to use as a parent.
534 template <class PTR_TYPE, class SIZE_T>
535 std::enable_if_t<is_unbounded_array_v<PTR_TYPE>,
536  pvt::shared_ptr_wrapper<std::weak_ptr, PTR_TYPE, PTR_TYPE, SIZE_T, std::shared_ptr<PTR_TYPE>>>
537 weak_ptr(std::weak_ptr<PTR_TYPE>& ptr, SIZE_T& size)
538 {
539  return { ptr, ptr.lock(), size };
540 }
541 
542 // SST_SER( SST::Core::Serialization::weak_ptr( std::weak_ptr&, std::shared:ptr&, SIZE_T& size) ) serializes a
543 // std::weak_ptr with a parent std::shared_ptr managing the owned object when the pointer is to an unbounded array of
544 // size "size".
545 template <class PTR_TYPE, class PARENT_TYPE, class SIZE_T>
546 std::enable_if_t<is_unbounded_array_v<PARENT_TYPE>,
547  pvt::shared_ptr_wrapper<std::weak_ptr, PTR_TYPE, PARENT_TYPE, SIZE_T>>
548 weak_ptr(std::weak_ptr<PTR_TYPE>& ptr, std::shared_ptr<PARENT_TYPE>& parent, SIZE_T& size)
549 {
550  return { ptr, parent, size };
551 }
552 
553 // Identity operation for consistency -- SST_SER( SST::Core::Serialization::weak_ptr(ptr) ) is same as SST_SER(ptr).
554 template <class PTR_TYPE>
555 std::weak_ptr<PTR_TYPE>&
556 weak_ptr(std::weak_ptr<PTR_TYPE>& ptr)
557 {
558  return ptr;
559 }
560 
561 } // namespace SST::Core::Serialization
562 
563 #endif // SST_CORE_SERIALIZATION_IMPL_SERIALIZE_SHARED_PTR_H
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition: serializer.h:42
Definition: serialize_shared_ptr.h:432
Base serialize class.
Definition: serialize.h:113
Definition: serialize_shared_ptr.h:268