Stroika Library 3.0d22
 
Loading...
Searching...
No Matches
SharedByValue.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
6
7namespace Stroika::Foundation::Memory {
8
9 /*
10 ********************************************************************************
11 *************** SharedByValue_CopyByDefault<T,SHARED_IMLP> *********************
12 ********************************************************************************
13 */
14 template <typename T, typename SHARED_IMLP>
15 inline SHARED_IMLP SharedByValue_CopyByDefault<T, SHARED_IMLP>::operator() (const T& t) const
16 {
17 if constexpr (same_as<SHARED_IMLP, shared_ptr<T>>) {
18 return Memory::MakeSharedPtr<T> (t); // more efficient
19 }
20 return SHARED_IMLP{new T{t}};
21 }
22
23 /*
24 ********************************************************************************
25 *************************** SharedByValue<T, TRAITS> ***************************
26 ********************************************************************************
27 */
28 template <typename T, typename TRAITS>
29 inline SharedByValue<T, TRAITS>::SharedByValue ([[maybe_unused]] nullptr_t) noexcept
30 : fCopier_{element_copier_type{}}
31 , fSharedImpl_{}
32 {
33 }
34 template <typename T, typename TRAITS>
35 inline SharedByValue<T, TRAITS>::SharedByValue (const shared_ptr_type& from, const element_copier_type& copier) noexcept
36 : fCopier_{copier}
37 , fSharedImpl_{from}
38 {
39 }
40 template <typename T, typename TRAITS>
41 inline SharedByValue<T, TRAITS>::SharedByValue (const element_type& from, const element_copier_type& copier) noexcept
42 : fCopier_{copier}
43 , fSharedImpl_{copier (from)}
44 {
45 }
46 template <typename T, typename TRAITS>
47 inline SharedByValue<T, TRAITS>::SharedByValue (shared_ptr_type&& from, const element_copier_type&& copier) noexcept
48 : fCopier_{move (copier)}
49 , fSharedImpl_{move (from)}
50 {
51 }
52 template <typename T, typename TRAITS>
53 inline SharedByValue<T, TRAITS>::SharedByValue (element_type* from, const element_copier_type& copier)
54 : fCopier_{copier}
55 , fSharedImpl_{from}
56 {
57 }
58 template <typename T, typename TRAITS>
59 inline SharedByValue<T, TRAITS>& SharedByValue<T, TRAITS>::operator= (const shared_ptr_type& from) noexcept
60 {
61 // If the pointers are the same, there is no need to copy, as the reference counts must also be the same,
62 // and we can avoid the (common) and costly memory barrier
63 if (fSharedImpl_ != from) [[likely]] {
64 fSharedImpl_ = from;
65 }
66 return *this;
67 }
68 template <typename T, typename TRAITS>
69 inline SharedByValue<T, TRAITS>::operator bool () const noexcept
70 {
71 return fSharedImpl_.get () != nullptr;
72 }
73 template <typename T, typename TRAITS>
74 inline SharedByValue<T, TRAITS>& SharedByValue<T, TRAITS>::operator= (shared_ptr_type&& from) noexcept
75 {
76 // If the pointers are the same, there is no need to copy, as the reference counts must also be the same,
77 // and we can avoid the (common) and costly memory barrier
78 if (fSharedImpl_ != from) [[likely]] {
79 fSharedImpl_ = move (from);
80 }
81 return *this;
82 }
83 template <typename T, typename TRAITS>
84 inline const typename SharedByValue<T, TRAITS>::element_type* SharedByValue<T, TRAITS>::cget () const noexcept
85 {
86 return fSharedImpl_.get ();
87 }
88 template <typename T, typename TRAITS>
89 inline auto SharedByValue<T, TRAITS>::cget_ptr () const -> shared_ptr_type
90 {
91 return fSharedImpl_;
92 }
93 template <typename T, typename TRAITS>
94 inline auto SharedByValue<T, TRAITS>::rwget_ptr () -> shared_ptr_type
95 {
96 return rwget_ptr (fCopier_);
97 }
98 template <typename T, typename TRAITS>
99 template <typename COPIER>
100 auto SharedByValue<T, TRAITS>::rwget_ptr (COPIER&& copier) -> shared_ptr_type
101 {
102 if (fSharedImpl_ != nullptr) [[likely]] {
103 auto result = forward<COPIER> (copier) (fSharedImpl_);
104 Assert (result.use_count () == 1);
105 return result;
106 }
107 return nullptr;
108 }
109 template <typename T, typename TRAITS>
110 inline auto SharedByValue<T, TRAITS>::rwget () -> element_type*
111 {
112 return rwget (fCopier_);
113 }
114 template <typename T, typename TRAITS>
115 template <typename COPIER>
116 inline auto SharedByValue<T, TRAITS>::rwget (COPIER&& copier) -> element_type*
117 {
118 /*
119 * Increment refCount before assureNReferences/breakreferencs so we can save
120 * the original shared_ptr and return it in case its needed (e.g. to update iterators).
121 *
122 * Save this way so no race (after Assure1Reference() other remaining ptr could go away.
123 */
124 if (fSharedImpl_ != nullptr) [[likely]] {
125 AssureNOrFewerReferences (forward<COPIER> (copier));
126 Ensure (fSharedImpl_.use_count () == 1);
127 return fSharedImpl_.get ();
128 }
129 return nullptr;
130 }
131 template <typename T, typename TRAITS>
132 inline const typename SharedByValue<T, TRAITS>::element_type* SharedByValue<T, TRAITS>::operator->() const
133 {
134 return fSharedImpl_.get ();
135 }
136 template <typename T, typename TRAITS>
137 inline typename SharedByValue<T, TRAITS>::element_type* SharedByValue<T, TRAITS>::operator->()
138 {
139 return rwget ();
140 }
141 template <typename T, typename TRAITS>
142 inline const typename SharedByValue<T, TRAITS>::element_type& SharedByValue<T, TRAITS>::operator* () const
143 {
144 const element_type* ptr = cget ();
145 EnsureNotNull (ptr);
146 return *ptr;
147 }
148 template <typename T, typename TRAITS>
149 constexpr bool SharedByValue<T, TRAITS>::operator== (nullptr_t) const
150 {
151 return fSharedImpl_ == nullptr;
152 }
153 template <typename T, typename TRAITS>
154 inline typename SharedByValue<T, TRAITS>::element_copier_type SharedByValue<T, TRAITS>::GetDefaultCopier () const
155 {
156 return fCopier_;
157 }
158 template <typename T, typename TRAITS>
160 {
161 switch (fSharedImpl_.use_count ()) {
162 case 0:
163 Assert (fSharedImpl_.get () == nullptr);
164 return SharedByValue_State::eNull;
165 case 1:
166 Assert (fSharedImpl_.get () != nullptr);
167 return SharedByValue_State::eSolo;
168 default:
169 Assert (fSharedImpl_.get () != nullptr);
170 //NOT NECESSARILY - cuz there is no lock
171 // between the use_count and this unique call, so another object could decrement its count
172 // and this could be that it was shared, but is no solo.
173 // Assert (not fSharedImpl_.unique ());
174 // -- LGP 2015-01-10
175 return SharedByValue_State::eShared;
176 }
177 }
178 template <typename T, typename TRAITS>
180 {
181 return fSharedImpl_.use_count () == 1;
182 }
183 template <typename T, typename TRAITS>
184 inline unsigned int SharedByValue<T, TRAITS>::use_count () const
185 {
186 return fSharedImpl_.use_count ();
187 }
188 template <typename T, typename TRAITS>
189 template <typename COPIER>
190 inline void SharedByValue<T, TRAITS>::AssureNOrFewerReferences (COPIER&& copier, unsigned int n)
191 {
192 Require (n != 0);
193 if (static_cast<unsigned int> (fSharedImpl_.use_count ()) > n) [[unlikely]] {
194 BreakReferences_ (forward<COPIER> (copier));
195 Assert (this->use_count () == 1);
196 }
198 template <typename T, typename TRAITS>
199 inline void SharedByValue<T, TRAITS>::AssureNOrFewerReferences (unsigned int n)
200 {
201 AssureNOrFewerReferences (fCopier_, n);
202 }
203 template <typename T, typename TRAITS>
204 template <typename COPIER>
205 void SharedByValue<T, TRAITS>::BreakReferences_ (COPIER&& copier)
206 {
207 RequireNotNull (fSharedImpl_);
208 /*
209 * For a valid pointer that is reference counted and multiply shared,
210 * make a copy of that pointer via our fCloner function, and assign
211 * that cloned reference to this.
212 *
213 * Note that by doing so, we remove any references to the current
214 * item, and end up with our having the sole reference to the new copy of fPtr.
215 *
216 * Since we will be cloning the given pointer, we assume(assert) that
217 * it is non-nullptr.
218 */
219
220 // This is not NECESSARILY so. Another thread could have just released this pointer, in which case
221 // the creation of a new object was pointless, but harmless, as the assignemnt should decrement to zero the old
222 // value and it should go away.
223 //
224 // Actually, this gets triggered alot when used in heavily multithreaded applications, like
225 // Test10_MutlipleThreadsReadingOneUpdateUsingSynchronizedContainer_, so comment out the weak assert - just too noisy
226 // and really not a problem -- LGP 2021-11-06
227 //WeakAssert (not unique ());
228
229 fSharedImpl_ = forward<COPIER> (copier) (*fSharedImpl_); // make a new shared_ptr (clone) and assign-overwriting.
230
231 // this assignment requires overwriting THIS object, so must be externally synchronized. ASSERT EXTERNALLY SYNCRHONIZED HERE
232 // so treat this as real assertion erorr -- LGP 2021-10-15
233 Ensure (unique ());
234 }
235
236}
#define EnsureNotNull(p)
Definition Assertions.h:340
#define RequireNotNull(p)
Definition Assertions.h:347
SharedByValue is a utility class to implement Copy-On-Write (aka COW) - sort of halfway between uniqu...
nonvirtual unsigned int use_count() const