12#ifndef SST_CORE_SERIALIZATION_IMPL_SERIALIZE_SHARED_PTR_H
13#define SST_CORE_SERIALIZATION_IMPL_SERIALIZE_SHARED_PTR_H
18#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 150000
19#define SST_SERIALIZE_WEAK_PTR_ARRAY 0
21#define SST_SERIALIZE_WEAK_PTR_ARRAY 1
24#ifndef SST_INCLUDING_SERIALIZE_H
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"
29#include "sst/core/output.h"
30#include "sst/core/serialization/serializer.h"
37namespace SST::Core::Serialization {
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"); };
48constexpr inline char ptr_string<std::weak_ptr>[] =
"weak_ptr";
51constexpr inline char ptr_string<std::shared_ptr>[] =
"shared_ptr";
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"); };
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";
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";
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"); };
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)";
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& "
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)";
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, "
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)
96#if SST_SERIALIZE_WEAK_PTR_ARRAY
99 if constexpr ( std::conjunction_v<is_same_template<PTR_TEMPLATE, std::weak_ptr>, std::is_array<PTR_TYPE>> ) {
101 std::weak_ptr<const void> weak_ptr = ptr.lock();
104 return get_shared_ptr_owner_tag(weak_ptr, ser);
110 if ( ser.mode() == serializer::SIZER )
111 return ser.sizer().get_shared_ptr_owner_tag(ptr);
113 return ser.packer().get_shared_ptr_owner_tag(ptr);
123template <
template <
class>
class PTR_TEMPLATE,
class PTR_TYPE,
class PARENT_TYPE>
125pack_shared_ptr_address(
126 const PTR_TEMPLATE<PTR_TYPE>& ptr,
const std::shared_ptr<PARENT_TYPE>& parent,
size_t* size, serializer& ser)
131 if constexpr ( is_same_template_v<PTR_TEMPLATE, std::shared_ptr> )
134 addr = ptr.lock().get();
137 bool nonnull = addr !=
nullptr;
138 ser.primitive(nonnull);
142 const void* parent_addr = parent.get();
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>);
151 ptrdiff_t offset =
static_cast<const char*
>(addr) -
static_cast<const char*
>(parent_addr);
155 if constexpr ( is_unbounded_array_v<PARENT_TYPE> )
156 parent_size = *size *
sizeof(std::remove_extent_t<PARENT_TYPE>);
158 parent_size =
sizeof(PARENT_TYPE);
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>);
168 ser.primitive(offset);
174template <
class PARENT_TYPE>
176pack_shared_ptr_parent(
const std::shared_ptr<PARENT_TYPE>& parent,
size_t* size, serializer& ser, ser_opt_t UNUSED(opt))
179 using OWNER_TYPE = std::remove_cv_t<PARENT_TYPE>;
182 using ELEM_TYPE = std::remove_extent_t<OWNER_TYPE>;
185 OWNER_TYPE* parent_addr =
const_cast<OWNER_TYPE*
>(
reinterpret_cast<const OWNER_TYPE*
>(parent.get()));
188 bool nonnull = parent_addr !=
nullptr;
189 ser.primitive(nonnull);
193 if constexpr ( is_unbounded_array_v<OWNER_TYPE> ) {
197 ser.primitive(*size);
200 if constexpr ( is_trivially_serializable_v<ELEM_TYPE> )
201 ser.raw(parent_addr, *size *
sizeof(ELEM_TYPE));
203 serialize_array(ser, parent_addr, opt, *size, serialize_array_element<ELEM_TYPE>);
209 SST_SER(*parent_addr, opt);
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))
222 using OWNER_TYPE = std::remove_cv_t<PARENT_TYPE>;
225 using ELEM_TYPE = std::remove_extent_t<OWNER_TYPE>;
229 auto&& [owner, is_new_tag] = ser.unpacker().get_shared_ptr_owner(tag);
234 static_assert(std::is_same_v<
decltype(owner), std::shared_ptr<void>&>);
239 bool nonnull =
false;
240 ser.primitive(nonnull);
244 if constexpr ( is_unbounded_array_v<OWNER_TYPE> ) {
248 ser.primitive(*size);
252 if constexpr ( __cplusplus < 202002l )
253 owner = std::make_unique<OWNER_TYPE>(*size);
255 owner = std::make_shared<OWNER_TYPE>(*size);
258 if constexpr ( is_trivially_serializable_v<ELEM_TYPE> )
259 ser.raw(owner.get(), *size *
sizeof(ELEM_TYPE));
261 serialize_array(ser, owner.get(), opt, *size, serialize_array_element<ELEM_TYPE>);
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>]());
270 owner = std::make_shared<OWNER_TYPE>();
273 SST_SER(*
static_cast<OWNER_TYPE*
>(owner.get()));
278 parent = std::static_pointer_cast<PARENT_TYPE>(owner);
284class serialize_shared_ptr_impl
291 explicit serialize_shared_ptr_impl(
size_t* size =
nullptr) :
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)
303 switch ( ser.mode() ) {
304 case serializer::SIZER:
305 case serializer::PACK:
308 auto owner_ne = [](
const auto& a,
const auto& b) {
return a.owner_before(b) || b.owner_before(a); };
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>);
319 auto [tag, is_new_tag] = get_shared_ptr_owner_tag(ptr, ser);
325 if ( tag != 0 ) pack_shared_ptr_address(ptr, parent, size, ser);
328 if ( is_new_tag ) pack_shared_ptr_parent(parent, size, ser, opt);
332 case serializer::UNPACK:
346 bool nonnull =
false;
347 ser.primitive(nonnull);
350 ptrdiff_t offset = 0;
351 if ( nonnull ) ser.primitive(offset);
354 const std::shared_ptr<void>& owner = unpack_shared_ptr_owner(tag, parent, size, ser, opt);
360 using ELEM_TYPE = std::remove_extent_t<PTR_TYPE>;
364 nonnull ?
reinterpret_cast<ELEM_TYPE*
>(
static_cast<char*
>(owner.get()) + offset) :
nullptr;
368 ptr = std::shared_ptr<PTR_TYPE>(owner, addr);
373 case serializer::MAP:
377 class SharedPtrUseCount
379 PTR_TEMPLATE<PTR_TYPE>& ptr;
382 explicit SharedPtrUseCount(PTR_TEMPLATE<PTR_TYPE>& ptr) :
385 operator size_t()
const {
return ptr.use_count(); }
386 SharedPtrUseCount(
const SharedPtrUseCount&) =
default;
387 SharedPtrUseCount& operator=(
size_t) {
return *
this; }
390 ser.mapper().map_hierarchy_start(
391 ser.getMapName(),
new ObjectMapClass(&ptr,
typeid(PTR_TEMPLATE<PTR_TYPE>).name()));
396 ser.mapper().map_object(
"use_count", use_count);
399 auto* ptr_value = [&] {
400 if constexpr ( is_same_template_v<PTR_TEMPLATE, std::weak_ptr> )
401 return ptr.lock().get();
407 if constexpr ( is_unbounded_array_v<PTR_TYPE> )
408 SST_SER_NAME(SST::Core::Serialization::array(ptr_value, *size),
"get");
410 SST_SER_NAME(*
reinterpret_cast<PTR_TYPE*
>(ptr_value),
"get");
412 ser.mapper().map_hierarchy_end();
424template <
class PTR_TYPE>
426 std::enable_if_t<!is_unbounded_array_v<PTR_TYPE> && !std::is_function_v<PTR_TYPE>>>
428 void operator()(std::shared_ptr<PTR_TYPE>& ptr,
serializer& ser, ser_opt_t opt)
430 ser_opt_t elem_opt = SerOption::is_set(opt, SerOption::as_ptr_elem) ? SerOption::as_ptr : SerOption::none;
435 SST_FRIEND_SERIALIZE();
441template <
class PTR_TYPE>
443#if SST_SERIALIZE_WEAK_PTR_ARRAY
444 !is_unbounded_array_v<PTR_TYPE>
446 !std::is_array_v<PTR_TYPE>
448 && !std::is_function_v<PTR_TYPE>>>
450 void operator()(std::weak_ptr<PTR_TYPE>& ptr,
serializer& ser, ser_opt_t opt)
452 ser_opt_t elem_opt = SerOption::is_set(opt, SerOption::as_ptr_elem) ? SerOption::as_ptr : SerOption::none;
460 std::shared_ptr<PTR_TYPE> parent = ptr.lock();
463 SST_FRIEND_SERIALIZE();
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>&>
492 PTR_TEMPLATE<PTR_TYPE>& ptr;
497template <
template <
class>
class PTR_TEMPLATE,
class PTR_TYPE,
class PARENT_ELEM_TYPE,
class SIZE_T,
class OWNER_TYPE>
500 PTR_TEMPLATE<PTR_TYPE>& ptr;
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>>>
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> ) {
521 else if constexpr ( std::is_same_v<SIZE_T, size_t> ) {
527 const auto mode = ser.mode();
529 if ( mode != serializer::UNPACK ) size = get_array_size(ptr.size, pvt::array_size_string<PTR_TEMPLATE>);
531 if ( mode == serializer::UNPACK ) ptr.size =
static_cast<SIZE_T
>(size);
534 SST_FRIEND_SERIALIZE();
542template <
class PTR_TYPE,
class PARENT_TYPE>
544shared_ptr(std::shared_ptr<PTR_TYPE>& ptr, std::shared_ptr<PARENT_TYPE>& parent)
546 return { ptr, parent };
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)
555 return { ptr, ptr, 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)
566 return { ptr, parent, size };
570template <
class PTR_TYPE>
571std::shared_ptr<PTR_TYPE>&
572shared_ptr(std::shared_ptr<PTR_TYPE>& ptr)
580#if SST_SERIALIZE_WEAK_PTR_ARRAY
584template <
class PTR_TYPE,
class PARENT_TYPE>
586weak_ptr(std::weak_ptr<PTR_TYPE>& ptr, std::shared_ptr<PARENT_TYPE>& parent)
588 return { ptr, 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)
599 return { ptr, ptr.lock(), 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)
610 return { ptr, parent, size };
617template <
class PTR_TYPE,
class PARENT_TYPE>
619weak_ptr(std::weak_ptr<PTR_TYPE>& ptr, std::shared_ptr<PARENT_TYPE>& parent)
621 return { ptr, parent };
628template <
class PTR_TYPE>
629std::weak_ptr<PTR_TYPE>&
630weak_ptr(std::weak_ptr<PTR_TYPE>& ptr)
ObjectMap object for non-fundamental, non-container types.
Definition objectMap.h:729
Definition objectMap.h:1455
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
Definition serialize_shared_ptr.h:285
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