SST 16.0.0
Structural Simulation Toolkit
ser_shared_ptr_tracker.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_SER_SHARED_PTR_TRACKER_H
13#define SST_CORE_SERIALIZATION_IMPL_SER_SHARED_PTR_TRACKER_H
14
15#ifndef SST_INCLUDING_SERIALIZER_H
16#warning \
17 "The header file sst/core/serialization/impl/ser_shared_ptr_tracker.h should not be directly included as it is not part of the stable public API. The file is included in sst/core/serialization/serializer.h"
18#endif
19
20#include "sst/core/output.h"
21
22#include <cstddef>
23#include <deque>
24#include <map>
25#include <memory>
26#include <utility>
27
28namespace SST::Core::Serialization::pvt {
29
30class ser_shared_ptr_packer
31{
32 // Map of ownership from std::shared_ptr or std::weak_ptr to a numeric tag representing the owner
33 //
34 // The std::owner_less<void> functor compares two std::shared_ptr or std::weak_ptr instances with .owner_before()
35 // to form an ordering which std::map uses to detect whether two std::shared_ptr or std::weak_ptr pointers have
36 // the same owner.
37 //
38 // The keys are of type std::weak_ptr<const void> because any std::shared_ptr or std::weak_ptr can be implicitly
39 // converted to a std::weak_ptr<const void> and its ownership can be compared with any other std::shared_ptr or
40 // std::weak_ptr.
41 //
42 // The map is initialized with an empty std::weak_ptr mapped to tag 0. This empty entry compares equal to all
43 // std::shared_ptr or std::weak_ptr with an empty control block, which is different from having a use_count() == 0,
44 // because a std::weak_ptr with a use_count() == 0 can still have an orphaned control block shared with others.
45 std::map<std::weak_ptr<const void>, size_t, std::owner_less<void>> shared_ptr_map = { { {}, 0 } };
46
47 // Running owner tag which starts at 1 and increments each time a new std::shared_ptr owner is found
48 size_t owner_tag = 1;
49
50public:
51 ser_shared_ptr_packer() = default;
52 ser_shared_ptr_packer(const ser_shared_ptr_packer&) = delete;
53 ser_shared_ptr_packer& operator=(const ser_shared_ptr_packer&) = delete;
54 ~ser_shared_ptr_packer() = default;
55
56 // Get the tag associated with a shared pointer's owner, and whether it is new
57 std::pair<size_t, bool> get_shared_ptr_owner_tag(const std::weak_ptr<const void>& ptr);
58}; // class ser_shared_ptr_packer
59
60class ser_shared_ptr_unpacker
61{
62 // Array of std::shared_ptr owners indexed by tag.
63 //
64 // When a std::shared_ptr or std::weak_ptr is deserialized, numeric tags represent different owners.
65 //
66 // The first time a tag is seen, a std::shared_ptr<PARENT_TYPE> is allocated, and PARENT_TYPE is deserialized.
67 //
68 // This array keeps an copy of the std::shared_ptr<PARENT_TYPE> owner converted to std::shared_ptr<void> around
69 // for every deserialization of std::shared_ptr or std::weak_ptr with the same ownership tag.
70 //
71 // std::deque is used because it never moves std::shared_ptr around after it is inserted, unlike std::vector.
72 std::deque<std::shared_ptr<void>> shared_ptr_owners;
73
74public:
75 ser_shared_ptr_unpacker() = default;
76 ser_shared_ptr_unpacker(const ser_shared_ptr_unpacker&) = delete;
77 ser_shared_ptr_unpacker& operator=(const ser_shared_ptr_unpacker&) = delete;
78 ~ser_shared_ptr_unpacker() = default;
79
80 // Get the std::shared_ptr associated with a tag, and whether it is new
81 std::pair<std::shared_ptr<void>&, bool> get_shared_ptr_owner(size_t tag);
82}; // class ser_shared_ptr_unpacker
83
84} // namespace SST::Core::Serialization::pvt
85
86#endif // SST_CORE_SERIALIZATION_IMPL_SER_SHARED_PTR_TRACKER_H