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