SST  15.1.0
StructuralSimulationToolkit
ser_shared_ptr_tracker.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_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 
29 
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 
50 public:
51  ser_shared_ptr_packer() = default;
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 
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 
74 public:
75  ser_shared_ptr_unpacker() = default;
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
Definition: ser_shared_ptr_tracker.h:30
Definition: baseComponent.cc:1107
Definition: ser_shared_ptr_tracker.h:60