SST 15.0
Structural Simulation Toolkit
serializable_base.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_SERIALIZABLE_BASE_H
13#define SST_CORE_SERIALIZATION_SERIALIZABLE_BASE_H
14
15#include "sst/core/serialization/serializer.h"
16#include "sst/core/warnmacros.h"
17
18#include <cstring>
19#include <limits>
20#include <stdint.h>
21#include <string>
22#include <typeinfo>
23#include <unordered_map>
24
25namespace SST::Core::Serialization {
26
27namespace pvt {
28
29// Functions to implement the hash for cls_id at compile time. The
30// hash function being implemented is:
31
32inline uint32_t
33type_hash(const char* key)
34{
35 int len = ::strlen(key);
36 uint32_t hash = 0;
37 for ( int i = 0; i < len; ++i ) {
38 hash += key[i];
39 hash += (hash << 10);
40 hash ^= (hash >> 6);
41 }
42 hash += (hash << 3);
43 hash ^= (hash >> 11);
44 hash += (hash << 15);
45
46 return hash;
47}
48
49// Using constexpr is very limited, so the implementation is a bit
50// convoluted. May be able to streamline later.
51
52// computes hash ^= (hash >> 6)
53constexpr uint32_t
54B(const uint32_t b)
55{
56 return b ^ (b >> 6);
57}
58
59// computes hash += (hash << 10)
60constexpr uint32_t
61A(const uint32_t a)
62{
63 return B((a << 10) + a);
64}
65
66// recursive piece that computes the for loop
67template <size_t idx>
68constexpr uint32_t
69ct_hash_rec(const char* str)
70{
71 return A(str[idx] + ct_hash_rec<idx - 1>(str));
72}
73
74// End of the recursion (i.e. when you've walked back off the front of
75// the string
76template <>
77constexpr uint32_t
78ct_hash_rec<size_t(-1)>(const char* UNUSED(str))
79{
80 return 0;
81}
82
83// computes hash += (hash << 15)
84constexpr uint32_t
85E(const uint32_t e)
86{
87 return (e << 15) + e;
88}
89
90// computes hash ^= (hash >> 11)
91constexpr uint32_t
92D(const uint32_t d)
93{
94 return E((d >> 11) ^ d);
95}
96
97// computes hash += (hash << 3)
98constexpr uint32_t
99C(const uint32_t c)
100{
101 return D((c << 3) + c);
102}
103
104// Main function that computes the final manipulations after calling
105// the recursive function to compute the for loop.
106template <size_t idx>
107constexpr uint32_t
108ct_hash(const char* str)
109{
110 return C(ct_hash_rec<idx>(str));
111}
112
113// Macro that should be used to call the compile time hash function
114#define COMPILE_TIME_HASH(x) (::SST::Core::Serialization::pvt::ct_hash<sizeof(x) - 2>(x))
115
116} // namespace pvt
117
119{
120public:
121 static constexpr uint32_t NullClsId = std::numeric_limits<uint32_t>::max();
122
123 virtual const char* cls_name() const = 0;
124
125 virtual void serialize_order(serializer& ser) = 0;
126
127 virtual uint32_t cls_id() const = 0;
128 virtual std::string serialization_name() const = 0;
129
130 virtual ~serializable_base() {}
131
132protected:
133 enum cxn_flag_t { ConstructorFlag };
134 [[noreturn]]
135 static void serializable_abort(uint32_t line, const char* file, const char* func, const char* obj);
136};
137
138
139template <class T>
141{};
142
143#define ImplementVirtualSerializable(obj) \
144 \
145public: \
146 static void throw_exc() \
147 { \
148 ::SST::Core::Serialization::serializable_base::serializable_abort(__LINE__, __FILE__, __FUNCTION__, #obj); \
149 } \
150 virtual const char* cls_name() const override \
151 { \
152 return #obj; \
153 } \
154 virtual uint32_t cls_id() const override \
155 { \
156 throw_exc(); \
157 return 0; \
158 } \
159 virtual std::string serialization_name() const override \
160 { \
161 throw_exc(); \
162 return ""; \
163 }
164
165#define NotSerializable(obj) \
166 \
167public: \
168 static void throw_exc() \
169 { \
170 ::SST::Core::Serialization::serializable_base::serializable_abort(__LINE__, __FILE__, __FUNCTION__, #obj); \
171 } \
172 virtual void serialize_order(SST::Core::Serialization::serializer& UNUSED(sst)) override \
173 { \
174 throw_exc(); \
175 } \
176 virtual uint32_t cls_id() const override \
177 { \
178 throw_exc(); \
179 return ::SST::Core::Serialization::serializable_base::NullClsId; \
180 } \
181 static obj* construct_deserialize_stub() \
182 { \
183 throw_exc(); \
184 return 0; \
185 } \
186 virtual std::string serialization_name() const override \
187 { \
188 throw_exc(); \
189 return ""; \
190 } \
191 virtual const char* cls_name() const override \
192 { \
193 return #obj; \
194 }
195
196// virtual const char* cls_name() const override { return obj_str; }
197#define ImplementSerializableDefaultConstructor(obj, obj_str) \
198 \
199public: \
200 virtual const char* cls_name() const override \
201 { \
202 return SST::Core::Serialization::serializable_builder_impl<obj>::static_name(); \
203 } \
204 virtual uint32_t cls_id() const override \
205 { \
206 return SST::Core::Serialization::serializable_builder_impl<obj>::static_cls_id(); \
207 } \
208 static obj* construct_deserialize_stub() \
209 { \
210 return new obj; \
211 } \
212 virtual std::string serialization_name() const override \
213 { \
214 return obj_str; \
215 } \
216 \
217private: \
218 friend class SST::Core::Serialization::serializable_builder_impl<obj>; \
219 static bool you_forgot_to_add_ImplementSerializable_to_this_class() \
220 { \
221 return false; \
222 }
223
224#define SER_FORWARD_AS_ONE(...) __VA_ARGS__
225
226#define ImplementSerializable(...) \
227 \
228public: \
229 ImplementSerializableDefaultConstructor(SER_FORWARD_AS_ONE(__VA_ARGS__), #__VA_ARGS__)
230
232{
233public:
234 virtual serializable_base* build() const = 0;
235
236 virtual ~serializable_builder() {}
237
238 virtual const char* name() const = 0;
239
240 virtual uint32_t cls_id() const = 0;
241
242 virtual bool sanity(serializable_base* ser) = 0;
243};
244
245template <class T>
247{
248protected:
249 static const char* name_;
250 static const uint32_t cls_id_;
251
252public:
253 serializable_base* build() const override { return T::construct_deserialize_stub(); }
254
255 const char* name() const override { return name_; }
256
257 uint32_t cls_id() const override { return cls_id_; }
258
259 static uint32_t static_cls_id() { return cls_id_; }
260
261 static const char* static_name() { return name_; }
262
263 bool sanity(serializable_base* ser) override { return (typeid(T) == typeid(*ser)); }
264};
265
267{
268protected:
269 using builder_map = std::unordered_map<long, serializable_builder*>;
270 static builder_map* builders_;
271
272public:
273 static serializable_base* get_serializable(uint32_t cls_id);
274
275 /**
276 @return The cls id for the given builder
277 */
278 static uint32_t
279 // add_builder(serializable_builder* builder, uint32_t cls_id);
280 add_builder(serializable_builder* builder, const char* name);
281
282 static bool sanity(serializable_base* ser, uint32_t cls_id) { return (*builders_)[cls_id]->sanity(ser); }
283
284 static void delete_statics();
285};
286
287template <class T>
288const char* serializable_builder_impl<T>::name_ = typeid(T).name();
289template <class T>
290const uint32_t serializable_builder_impl<T>::cls_id_ =
292
293// Hold off on trivially_serializable for now, as it's not really safe
294// in the case of inheritance
295//
296// class trivially_serializable {
297// };
298
299} // namespace SST::Core::Serialization
300
301#define SerializableName(obj) #obj
302
303#define DeclareSerializable(obj)
304
305// #include "sst/core/serialization/serialize_serializable_base.h"
306
307#endif
Definition serializable_base.h:119
Definition serializable_base.h:247
Definition serializable_base.h:232
Definition serializable_base.h:267
static uint32_t add_builder(serializable_builder *builder, const char *name)
Definition serializable_base.cc:37
Definition serializable_base.h:141
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition serializer.h:45