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