SST 16.0.0
Structural Simulation Toolkit
serialize_unique_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_UNIQUE_PTR_H
13#define SST_CORE_SERIALIZATION_IMPL_SERIALIZE_UNIQUE_PTR_H
14
15#ifndef SST_INCLUDING_SERIALIZE_H
16#warning \
17 "The header file sst/core/serialization/impl/serialize_unique_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/serialization/serializer.h"
21
22#include <cstddef>
23#include <memory>
24#include <new>
25#include <type_traits>
26#include <utility>
27
28namespace SST::Core::Serialization {
29
30namespace pvt {
31
32// std::unique_ptr wrapper class
33// Default template has a reference to a std::unique_ptr and a deleter which might be defaulted
34template <class PTR_TYPE, class DELETER = std::default_delete<PTR_TYPE>, class SIZE_T = void>
36{
37 std::unique_ptr<PTR_TYPE, DELETER>& ptr;
38 DELETER del {};
39};
40
41// For unbounded array types, a reference to a size parameter is added
42template <class ELEM_TYPE, class DELETER, class SIZE_T>
43struct unique_ptr_wrapper<ELEM_TYPE[], DELETER, SIZE_T>
44{
45 std::unique_ptr<ELEM_TYPE[], DELETER>& ptr;
46 SIZE_T& size;
47 DELETER del {};
48};
49
50} // namespace pvt
51
52// Serialize std::unique_ptr with a default deleter but not an unbounded array type
53template <class PTR_TYPE>
54class serialize_impl<std::unique_ptr<PTR_TYPE>, std::enable_if_t<!is_unbounded_array_v<PTR_TYPE>>>
55{
56 void operator()(std::unique_ptr<PTR_TYPE>& ptr, serializer& ser, ser_opt_t opt)
57 {
58 // Create a wrapper with a default deleter and serialize the wrapper with the generalized code below
61 }
62 SST_FRIEND_SERIALIZE();
63};
64
65// Serialize std::unique_ptr with a wrapper which handles unbounded arrays with a runtime size, and custom deleters
66template <class PTR_TYPE, class DELETER, class SIZE_T>
67class serialize_impl<pvt::unique_ptr_wrapper<PTR_TYPE, DELETER, SIZE_T>>
68{
69 // OWNER_TYPE is PTR_TYPE with cv-qualifiers removed so that it can be serialized
70 using OWNER_TYPE = std::remove_cv_t<PTR_TYPE>;
71
72 // ELEM_TYPE is the array element type, or OWNER_TYPE if OWNER_TYPE is not an array
73 // "pointer" member of std::unique_ptr is used in case DELETER has its own pointer type
74 using ELEM_TYPE = std::remove_cv_t<std::remove_pointer_t<typename std::unique_ptr<PTR_TYPE, DELETER>::pointer>>;
75
76 void operator()(pvt::unique_ptr_wrapper<PTR_TYPE, DELETER, SIZE_T>& ptr, serializer& ser, ser_opt_t opt)
77 {
78 const auto opts = SerOption::is_set(opt, SerOption::as_ptr_elem) ? SerOption::as_ptr : SerOption::none;
79 const auto mode = ser.mode();
80
81 if ( mode == serializer::MAP ) {
82 auto* ptr_value = ptr.ptr.get();
83 if constexpr ( is_unbounded_array_v<PTR_TYPE> )
84 SST_SER_NAME(SST::Core::Serialization::array(ptr_value, ptr.size), ser.getMapName());
85 else
86 SST_SER_NAME(ptr_value, ser.getMapName());
87 return;
88 }
89
90 // Destroy the old std::unique_ptr
91 if ( mode == serializer::UNPACK ) ptr.ptr.~unique_ptr();
92
93 size_t size = 0;
94 if constexpr ( is_unbounded_array_v<PTR_TYPE> ) {
95 // If PTR_TYPE is an unbounded array and there is a size parameter
96
97 // Get the array size, which is 0 if the pointer is null
98 if ( mode != serializer::UNPACK )
99 if ( ptr.ptr )
100 size = get_array_size(ptr.size,
101 "Serialization Error: Array size in SST::Core::Serialization::unique_ptr() cannot fit "
102 "inside size_t. size_t should be used for array sizes.\n");
103
104 // Serialize the array size
105 ser.primitive(size);
106 if ( mode == serializer::UNPACK ) ptr.size = static_cast<SIZE_T>(size);
107 }
108
109 // Serialize the address stored in the std::unique_ptr
110 uintptr_t ptr_stored = reinterpret_cast<uintptr_t>(ptr.ptr.get());
111 ser.primitive(ptr_stored);
112
113 uintptr_t real_ptr = ptr_stored;
114 bool serialize_obj = false;
115
116 switch ( mode ) {
117 case serializer::SIZER:
118 serialize_obj = ptr_stored && !ser.sizer().check_pointer_sizer(ptr_stored);
119 break;
120
121 case serializer::PACK:
122 serialize_obj = ptr_stored && !ser.packer().check_pointer_pack(ptr_stored);
123 break;
124
125 case serializer::UNPACK:
126 if ( ptr_stored ) {
127 // Check if the pointer was seen before
128 real_ptr = ser.unpacker().check_pointer_unpack(ptr_stored);
129
130 // If pointer was not seen before, allocate the object, report its address and serialize the object
131 if ( !real_ptr ) {
132 if constexpr ( is_unbounded_array_v<PTR_TYPE> )
133 real_ptr = reinterpret_cast<uintptr_t>(new ELEM_TYPE[size]());
134 else if constexpr ( std::is_array_v<PTR_TYPE> )
135 real_ptr = reinterpret_cast<uintptr_t>(new ELEM_TYPE[std::extent_v<PTR_TYPE>]());
136 else
137 real_ptr = reinterpret_cast<uintptr_t>(new OWNER_TYPE());
138 ser.unpacker().report_real_pointer(ptr_stored, real_ptr);
139 serialize_obj = true;
140 }
141 }
142 // Create a std::unique_ptr owning the real pointer (or null pointer if ptr_stored == 0)
143 new (&ptr.ptr) std::unique_ptr<PTR_TYPE, DELETER>(
144 reinterpret_cast<ELEM_TYPE*>(real_ptr), std::forward<decltype(ptr.del)>(ptr.del));
145 break;
146
147 default:
148 break;
149 }
150
151 // Serialize the object if the pointer is non-null and this is the first time it's been seen
152 if ( serialize_obj ) {
153 if constexpr ( !is_unbounded_array_v<PTR_TYPE> )
154 SST_SER(*reinterpret_cast<OWNER_TYPE*>(real_ptr));
155 else if constexpr ( is_trivially_serializable_v<ELEM_TYPE> )
156 ser.raw(reinterpret_cast<ELEM_TYPE*>(real_ptr), size * sizeof(ELEM_TYPE));
157 else
158 pvt::serialize_array(
159 ser, reinterpret_cast<ELEM_TYPE*>(real_ptr), opts, size, pvt::serialize_array_element<ELEM_TYPE>);
160 }
161 }
162
163 // For the serialize_impl specialization above
165
166 SST_FRIEND_SERIALIZE();
167};
168
169// Wrapper for a std::unique_ptr to an unbounded array with a runtime size
170template <class ELEM_TYPE, class DELETER, class SIZE_T>
171std::enable_if_t<std::is_integral_v<SIZE_T>, pvt::unique_ptr_wrapper<ELEM_TYPE[], DELETER, SIZE_T>>
172unique_ptr(std::unique_ptr<ELEM_TYPE[], DELETER>& ptr, SIZE_T& size)
173{
174 return { ptr, size };
175}
176
177// Wrapper for a std::unique_ptr with a custom deleter but no unbounded array
178template <class PTR_TYPE, class DELETER, class DEL>
179std::enable_if_t<!is_unbounded_array_v<PTR_TYPE> && std::is_constructible_v<DELETER, DEL&&>,
180 pvt::unique_ptr_wrapper<PTR_TYPE, DELETER>>
181unique_ptr(std::unique_ptr<PTR_TYPE, DELETER>& ptr, DEL&& del)
182{
183 return { ptr, std::forward<DEL>(del) };
184}
185
186// Wrapper for a std::unique_ptr with a custom deleter and an unbounded array with a runtime size
187template <class ELEM_TYPE, class DELETER, class SIZE_T, class DEL>
188std::enable_if_t<std::is_integral_v<SIZE_T> && std::is_constructible_v<DELETER, DEL&&>,
190unique_ptr(std::unique_ptr<ELEM_TYPE[], DELETER>& ptr, SIZE_T& size, DEL&& del)
191{
192 return { ptr, size, std::forward<DEL>(del) };
193}
194
195// NOP for consistency
196template <class PTR_TYPE, class DELETER>
197std::unique_ptr<PTR_TYPE, DELETER>&
198unique_ptr(std::unique_ptr<PTR_TYPE, DELETER>& ptr)
199{
200 return ptr;
201}
202
203} // namespace SST::Core::Serialization
204
205#endif // SST_CORE_SERIALIZATION_IMPL_SERIALIZE_UNIQUE_PTR_H
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_unique_ptr.h:36