SST 16.1.0
Structural Simulation Toolkit
ObjMapToTree.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_OBJECTMAPTOTREE_DEBUGGER_H
13#define SST_CORE_SERIALIZATION_OBJECTMAPTOTREE_DEBUGGER_H
14
15#include "sst/core/serialization/ObjTree.h"
16#include "sst/core/serialization/objectMapTreeBuilder.h"
17
18#include <memory>
19#include <string>
20#include <unordered_set>
21#include <vector>
22
23namespace SST::Core::Serialization {
24
26{
27 using IntVariant = IntegerObj::IntVariant;
28 using FloatVariant = FloatObj::FloatVariant;
29
30 // Known integer type strings
31 static bool isIntegerType(const std::string& type)
32 {
33 static const std::unordered_set<std::string> intTypes = { "signed char", "int8_t", "char", "short", "int16_t",
34 "int", "int32_t", "long", "long long", "int64_t", "unsigned char", "uint8_t", "unsigned short", "uint16_t",
35 "unsigned int", "unsigned", "uint32_t", "unsigned long", "unsigned long long", "uint64_t" };
36 return intTypes.count(type) > 0;
37 }
38
39 static bool isFloatType(const std::string& type)
40 {
41 return type == "float" || type == "double" || type == "long double";
42 }
43
44 static bool isStringType(const std::string& type)
45 {
46 // Demangled std::string can appear in various forms
47 return type.find("std::string") != std::string::npos ||
48 type.find("std::__cxx11::basic_string") != std::string::npos ||
49 type.find("basic_string") != std::string::npos;
50 }
51
52 static bool isContainerType(const std::string& type)
53 {
54 return type.find("std::vector") != std::string::npos || type.find("std::map") != std::string::npos ||
55 type.find("std::unordered_map") != std::string::npos || type.find("std::set") != std::string::npos ||
56 type.find("std::unordered_set") != std::string::npos || type.find("std::list") != std::string::npos ||
57 type.find("std::deque") != std::string::npos || type.find("std::multimap") != std::string::npos ||
58 type.find("std::array") != std::string::npos;
59 }
60
61 static std::unique_ptr<IntegerObj> makeIntegerObj(const std::string& type, void* addr)
62 {
63 if ( !addr ) return nullptr;
64 if ( type == "signed char" || type == "int8_t" || type == "char" )
65 return std::make_unique<IntegerObj>(*static_cast<int8_t*>(addr), addr);
66 if ( type == "short" || type == "int16_t" )
67 return std::make_unique<IntegerObj>(*static_cast<int16_t*>(addr), addr);
68 if ( type == "int" || type == "int32_t" )
69 return std::make_unique<IntegerObj>(*static_cast<int32_t*>(addr), addr);
70 if ( type == "long" || type == "long long" || type == "int64_t" )
71 return std::make_unique<IntegerObj>(*static_cast<int64_t*>(addr), addr);
72 if ( type == "unsigned char" || type == "uint8_t" )
73 return std::make_unique<IntegerObj>(*static_cast<uint8_t*>(addr), addr);
74 if ( type == "unsigned short" || type == "uint16_t" )
75 return std::make_unique<IntegerObj>(*static_cast<uint16_t*>(addr), addr);
76 if ( type == "unsigned int" || type == "unsigned" || type == "uint32_t" )
77 return std::make_unique<IntegerObj>(*static_cast<uint32_t*>(addr), addr);
78 if ( type == "unsigned long" || type == "unsigned long long" || type == "uint64_t" )
79 return std::make_unique<IntegerObj>(*static_cast<uint64_t*>(addr), addr);
80 return nullptr;
81 }
82
83 static std::unique_ptr<FloatObj> makeFloatObj(const std::string& type, void* addr)
84 {
85 if ( !addr ) return nullptr;
86 if ( type == "float" ) return std::make_unique<FloatObj>(*static_cast<float*>(addr), addr);
87 if ( type == "double" ) return std::make_unique<FloatObj>(*static_cast<double*>(addr), addr);
88 if ( type == "long double" ) return std::make_unique<FloatObj>(*static_cast<long double*>(addr), addr);
89 return nullptr;
90 }
91
92public:
93 // Convert a single ObjectMap* into an ObjTreeCont*
94 // Caller takes ownership of the returned pointer
95 static ObjTreeCont* convert(const std::string& name, ObjectMap* objMap, bool recursive = true)
96 {
97 if ( !objMap ) return nullptr;
98
99 const std::string type = objMap->getType();
100 void* addr = objMap->getAddr();
101
102 if ( objMap->isFundamental() ) {
103 if ( type == "bool" && addr ) {
104 // handle bitset and vector<bool> case
105 auto* ref = objMap->buildTreeNode(name);
106 if ( ref ) {
107 return ref;
108 }
109 // standard case
110 auto* o = new BoolObj(*static_cast<bool*>(addr), addr);
111 o->setName(name);
112 o->setType(type);
113 return o;
114 }
115 if ( isIntegerType(type) ) {
116 // handle fundamental ref case
117 auto* ref = objMap->buildTreeNode(name);
118 if ( ref ) {
119 return ref;
120 }
121 // standard case
122 if ( auto o = makeIntegerObj(type, addr) ) {
123 o->setName(name);
124 o->setType(type);
125 if ( objMap->isReadOnly() ) {
126 o->makeReadOnly();
127 }
128 return o.release();
129 }
130 }
131 if ( isFloatType(type) ) {
132 // handle fundamental ref case
133 auto* ref = objMap->buildTreeNode(name);
134 if ( ref ) {
135 return ref;
136 }
137 // standard case
138 if ( auto o = makeFloatObj(type, addr) ) {
139 o->setName(name);
140 o->setType(type);
141 if ( objMap->isReadOnly() ) {
142 o->makeReadOnly();
143 }
144 return o.release();
145 }
146 }
147 if ( isStringType(type) && addr ) {
148 auto* o = new StringObj(*static_cast<std::string*>(addr), addr);
149 o->setName(name);
150 o->setType(type);
151 if ( objMap->isReadOnly() ) {
152 o->makeReadOnly();
153 }
154 return o;
155 }
156 // Unknown fundamental — wrap in GenericObj with the value as string
157 // Note: we pass a nullptr in for objMap as the objMap used here is destroyed by the caller
158 // If it is necessary to set one of these generic values we will need to preserve the
159 // value of objMap. For now, we just pass in a nullptr rather than carry the (potentially)
160 // heavy ObjMap around in this container
161 auto* g = new GenericValObj(objMap->get(), addr, nullptr);
162 g->setName(name);
163 g->setType(type);
164 if ( objMap->isReadOnly() ) {
165 g->makeReadOnly();
166 }
167 return g;
168 }
169
170 if ( objMap->isContainer() || isContainerType(type) ) {
171 const auto& vars = objMap->getVariables();
172 auto* c = new ContainerObj(name, type, vars.size(), nullptr);
173 for ( const auto& [n, m] : vars )
174 if ( auto* child = convert(n, m, recursive) ) c->addChildObj(child);
175 return c;
176 }
177
178 if ( objMap->getCategory() == ObjectMap::ObjectCategory::Component ) {
179 if ( auto* comp = static_cast<BaseComponent*>(addr) ) {
180 auto* co = new ComponentObj(comp, nullptr);
181 co->setName(name);
182 co->setType(type);
183 if ( objMap->isReadOnly() ) {
184 co->makeReadOnly();
185 }
186 return co;
187 }
188 }
189
190 auto* node = new ObjTreeCont(name, type);
191 if ( recursive ) {
192 for ( const auto& [n, m] : objMap->getVariables() )
193 if ( auto* child = convert(n, m, false) ) node->addChildObj(child);
194 }
195 return node;
196 }
197
198 static void addChildrenFromMap(ObjTreeCont* parent, const ObjectMultimap& variables)
199 {
200 if ( !parent ) return;
201 for ( const auto& [name, objMap] : variables ) {
202 ObjTreeCont* child = convert(name, objMap, false);
203 if ( child ) parent->addChildObj(child);
204 }
205 }
206
207 static void addChildrenFromMapRecursive(ObjTreeCont* parent, const ObjectMultimap& variables)
208 {
209 if ( !parent ) return;
210 for ( const auto& [name, objMap] : variables ) {
211 ObjTreeCont* child = convert(name, objMap, true);
212 if ( child ) parent->addChildObj(child);
213 }
214 }
215
216 // Convert an entire ObjectMap's variables into an ObjTreeCont tree
217 static std::unique_ptr<ObjTreeCont> convertTree(const std::string& rootName, ObjectMap* objMap)
218 {
219 auto root = std::make_unique<ObjTreeCont>(rootName, objMap->getType());
220 const auto& variables = objMap->getVariables();
221 for ( const auto& [name, childMap] : variables ) {
222 ObjTreeCont* child = convert(name, childMap, true);
223 if ( child ) {
224 root->addChildObj(child);
225 }
226 }
227 return root;
228 }
229
230 /**
231 * Takes a ComponentObj, serializes its BaseComponent via
232 * ObjectMapDeferred, and populates the ComponentObj's children
233 * with the serialized variables.
234 *
235 * @param compNode The ComponentObj node to expand
236 * @param recursive If true, recursively convert all children
237 * @return true if serialization succeeded
238 */
239 static bool serializeComponent(ComponentObj* compNode, bool recursive = false)
240 {
241 if ( !compNode ) return false;
242
243 BaseComponent* comp = compNode->getVal();
244 if ( !comp ) return false;
245
246 ComponentInfo* compInfo = compNode->getInfo();
247
248
249 // Create a temporary deferred map and trigger serialization
251 serializer.serialize();
252
253 if ( serializer.hasSerialized() ) {
254 const auto& variables = serializer.getVariables();
255
256 // Collect sub-component addresses so we skip them during conversion
257 std::vector<void*> subCompAddrs;
258 if ( compInfo ) {
259 collectSubComponentAddrs(compInfo, subCompAddrs);
260 }
261
262 for ( const auto& [name, objMap] : variables ) {
263 if ( !objMap ) continue;
264
265 // Skip variables that are sub-components
266 if ( std::find(subCompAddrs.begin(), subCompAddrs.end(), objMap->getAddr()) != subCompAddrs.end() )
267 continue;
268
269 ObjTreeCont* child = convert(name, objMap, recursive);
270 if ( child ) compNode->addChildObj(child);
271 }
272 }
273
274 // Serialize sub-components from ComponentInfo
275 if ( compInfo ) {
276 serializeSubComponents(compNode, compInfo, recursive);
277 }
278
279 return true;
280 }
281
282 /**
283 * Serialize all ComponentObj children of a given node.
284 *
285 * @param parent The parent node whose ComponentObj children to expand
286 * @param recursive If true, recursively convert all grandchildren
287 */
288 static void serializeAllComponents(ObjTreeCont* parent, bool recursive = false)
289 {
290 if ( !parent ) return;
291
293 [recursive](ComponentObj* comp) { serializeComponent(comp, recursive); });
294 }
295
296 /**
297 * Full pipeline: convert an ObjectMap tree, then serialize
298 * any ComponentObj nodes found in the result.
299 *
300 * @param rootName Name for the root node
301 * @param objMap Source ObjectMap to convert
302 * @param recursive If true, fully expand all levels
303 * @return Root of the converted and serialized tree
304 */
305 static std::unique_ptr<ObjTreeCont> convertAndSerialize(
306 const std::string& rootName, ObjectMap* objMap, bool recursive = true)
307 {
308 auto root = convertTree(rootName, objMap);
309 if ( !root ) return nullptr;
310
311 // Serialize all component nodes in the tree
312 serializeAllComponents(root.get(), recursive);
313
314 return root;
315 }
316
317private:
318 static void collectSubComponentAddrs(ComponentInfo* compInfo, std::vector<void*>& addrs)
319 {
320 auto& subComps = compInfo->getSubComponents();
321
322 for ( auto it = subComps.begin(); it != subComps.end(); ++it ) {
323
324 BaseComponent* sub = it->second.getComponent();
325 if ( sub ) {
326 addrs.push_back(static_cast<void*>(sub));
327 }
328 }
329 }
330
331 static void serializeSubComponents(ObjTreeCont* parent, ComponentInfo* compInfo, bool recursive)
332 {
333 auto& subComps = compInfo->getSubComponents();
334 for ( auto& [compId, subInfo] : subComps ) {
335 BaseComponent* sub = subInfo.getComponent();
336 if ( !sub ) continue;
337
338 auto* subObj = new ComponentObj(sub, &subInfo);
339 subObj->setName(subInfo.getName());
340 subObj->setType(subInfo.getType());
341
342 // Serialize this sub-component's own variables
343 ComponentSerializer subSerializer(sub);
344 subSerializer.serialize();
345
346 if ( subSerializer.hasSerialized() ) {
347 const auto& subVars = subSerializer.getVariables();
348
349 // Collect nested sub-component addresses
350 std::vector<void*> nestedAddrs;
351 collectSubComponentAddrs(&subInfo, nestedAddrs);
352
353 for ( const auto& [name, objMap] : subVars ) {
354 if ( !objMap ) continue;
355 if ( std::find(nestedAddrs.begin(), nestedAddrs.end(), objMap->getAddr()) != nestedAddrs.end() )
356 continue;
357
358 ObjTreeCont* child = convert(name, objMap, recursive);
359 if ( child ) subObj->addChildObj(child);
360 }
361 }
362
363 // Recurse into this sub-component's own sub-components
364 if ( recursive ) {
365 serializeSubComponents(subObj, &subInfo, recursive);
366 }
367
368 parent->addChildObj(subObj);
369 }
370 }
371};
372
373} // namespace SST::Core::Serialization
374
375#endif
Main component object for the simulation.
Definition baseComponent.h:98
Definition componentInfo.h:45
Definition ObjTreeLeaves.h:941
Definition objectMapDeferred.h:132
Definition ObjTreeLeaves.h:748
Definition ObjTreeLeaves.h:1053
The Object Tree (ObjTree) is intended to be a developer friendly interface to SST’s existing serializ...
Definition ObjTreeLeaves.h:41
void addChildObj(ObjTreeCont *obj)
Adds a child node to the current node.
Definition ObjTreeLeaves.h:103
void applyRecursiveByType(Func &&func)
Apply a function to all children of this node of a specific type.
Definition ObjTreeLeaves.h:169
Definition ObjMapToTree.h:26
static std::unique_ptr< ObjTreeCont > convertAndSerialize(const std::string &rootName, ObjectMap *objMap, bool recursive=true)
Full pipeline: convert an ObjectMap tree, then serialize any ComponentObj nodes found in the result.
Definition ObjMapToTree.h:305
static void serializeAllComponents(ObjTreeCont *parent, bool recursive=false)
Serialize all ComponentObj children of a given node.
Definition ObjMapToTree.h:288
static bool serializeComponent(ComponentObj *compNode, bool recursive=false)
Takes a ComponentObj, serializes its BaseComponent via ObjectMapDeferred, and populates the Component...
Definition ObjMapToTree.h:239
Base class for objects created by the serializer mapping mode used to map the variables for objects.
Definition objectMap.h:189
bool isReadOnly() const
Check to see if this object is read-only.
Definition objectMap.h:259
virtual std::string get() const
Get the value of the variable as a string.
Definition objectMap.h:433
virtual const ObjectMultimap & getVariables() const
Get the list of child variables contained in this ObjectMap.
Definition objectMap.h:320
virtual SST::Core::Serialization::ObjTreeCont * buildTreeNode(const std::string &UNUSED(name))
Helper function to build an ObjTreeCont representation of this ObjectMap, if the subclass has type-sp...
Definition objectMap.h:578
virtual std::string getType() const =0
Get the type of the variable represented by the ObjectMap.
virtual bool isContainer() const
Check to see if this ObjectMap represents a container.
Definition objectMap.h:500
virtual bool isFundamental() const
Check to see if this ObjectMap represents a fundamental or a class treated as a fundamental.
Definition objectMap.h:492
virtual void * getAddr() const =0
Get the address of the variable represented by the ObjectMap.
Definition ObjTreeLeaves.h:871
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition serializer.h:43