6#include "Stroika/Foundation/Execution/Common.h"
8#include "Stroika/Foundation/Execution/Throw.h"
11namespace Stroika::Foundation::Memory {
12 DISABLE_COMPILER_MSC_WARNING_START (4996);
13 DISABLE_COMPILER_GCC_WARNING_START (
"GCC diagnostic ignored \"-Wdeprecated-declarations\"");
14 DISABLE_COMPILER_CLANG_WARNING_START (
"clang diagnostic ignored \"-Wdeprecated-declarations\"");
19 inline conditional_t<Execution::kSpinLock_IsFasterThan_mutex, Execution::SpinLock, mutex> sSharedPtrCopyLock_;
27 inline Private_::ReferenceCounterContainerType_::ReferenceCounterContainerType_ ()
29 , fDeleteCounter_{true}
32 inline Private_::ReferenceCounterContainerType_::ReferenceCounterContainerType_ (
bool deleteCounter)
34 , fDeleteCounter_{deleteCounter}
48 ReferenceCounterContainerType_* fCountHolder_;
51 Envelope_ (T* ptr, ReferenceCounterContainerType_* countHolder)
53 , fCountHolder_ (countHolder)
55 Require ((fPtr_ ==
nullptr) == (fCountHolder_ ==
nullptr));
57 inline Envelope_ (Envelope_&& from) noexcept
58 : fPtr_ (from.GetPtr ())
59 , fCountHolder_ (from.fCountHolder_)
62 from.fCountHolder_ =
nullptr;
64 template <
typename T2>
65 inline Envelope_ (Envelope_<T2>&& from) noexcept
66 : fPtr_ (from.GetPtr ())
67 , fCountHolder_ (from.fCountHolder_)
70 from.fCountHolder_ =
nullptr;
72 inline Envelope_ (
const Envelope_& from) noexcept
73 : fPtr_ (from.GetPtr ())
74 , fCountHolder_ (from.fCountHolder_)
77 template <
typename T2>
78 inline Envelope_ (
const Envelope_<T2>& from) noexcept
79 : fPtr_ (from.GetPtr ())
80 , fCountHolder_ (from.fCountHolder_)
83 template <
typename T2>
84 inline Envelope_ (
const Envelope_<T2>& from, T* newP) noexcept
86 , fCountHolder_ (from.fCountHolder_)
91 Require (newP == from.GetPtr ());
93 inline Envelope_& operator= (
const Envelope_& rhs)
96 fCountHolder_ = rhs.fCountHolder_;
99 template <
typename T2>
100 inline Envelope_& operator= (
const Envelope_<T2>& rhs)
103 fCountHolder_ = rhs.fCountHolder_;
106 inline Envelope_& operator= (Envelope_&& rhs)
noexcept
109 fCountHolder_ = rhs.fCountHolder_;
111 rhs.fCountHolder_ =
nullptr;
114 template <
typename T2>
115 inline Envelope_& operator= (Envelope_<T2>&& rhs)
118 fCountHolder_ = rhs.fCountHolder_;
120 rhs.fCountHolder_ =
nullptr;
123 inline void swap (Envelope_& rhs)
125 swap (fPtr_, rhs.fPtr_);
126 swap (fCountHolder_, rhs.fCountHolder_);
128 inline T* GetPtr () const noexcept
132 inline void SetPtr (T* p)
noexcept
136 inline SharedPtrBase::ReferenceCountType CurrentRefCount () const noexcept
138 return fCountHolder_ ==
nullptr ? 0 : fCountHolder_->fCount.load ();
140 inline void Increment () noexcept
143 ++fCountHolder_->fCount;
145 inline bool Decrement () noexcept
147 Require (CurrentRefCount () > 0);
148 if (--fCountHolder_->fCount == 0) {
153 inline void DoDeleteCounter () noexcept
156 if (fCountHolder_->fDeleteCounter_) {
157 ManuallyBlockAllocated<ReferenceCounterContainerType_>::Delete (fCountHolder_);
159 fCountHolder_ =
nullptr;
161#if qStroika_FeatureSupported_Valgrind
163 inline void ValgrindAnnotateGotLockZeroCaseClearing ()
166 ANNOTATE_HAPPENS_AFTER (&fCountHolder_->fCount);
167 ANNOTATE_HAPPENS_BEFORE_FORGET_ALL (&fCountHolder_->fCount);
169 inline void ValgrindAnnotateNotGotZeroCase ()
172 ANNOTATE_HAPPENS_BEFORE (&fCountHolder_->fCount);
176 template <
typename T2>
177 friend class Envelope_;
186 template <
typename T>
187 inline SharedPtr<T>::SharedPtr () noexcept
188 : fEnvelope_ (
nullptr,
nullptr)
191 template <
typename T>
192 inline SharedPtr<T>::SharedPtr (nullptr_t) noexcept
193 : fEnvelope_ (
nullptr,
nullptr)
196 template <
typename T>
197 template <
typename T2, enable_if_t<is_convertible_v<T2*, T*>>*>
198 inline SharedPtr<T>::SharedPtr (T2* from)
199 : fEnvelope_ (mkEnvelope_ (from))
201 Assert (fEnvelope_.GetPtr () == from);
202 if (from !=
nullptr) {
205 fEnvelope_.Increment ();
208 template <
typename T>
209 inline SharedPtr<T>::SharedPtr (
const Envelope_& from) noexcept
212 if (fEnvelope_.GetPtr () !=
nullptr) {
213 fEnvelope_.Increment ();
216 template <
typename T>
217 inline SharedPtr<T>::SharedPtr (
const SharedPtr& from) noexcept
218 : fEnvelope_ (from.fEnvelope_)
220 if (fEnvelope_.GetPtr () !=
nullptr) {
221 fEnvelope_.Increment ();
224 template <
typename T>
225 inline SharedPtr<T>::SharedPtr (SharedPtr&& from) noexcept
226 : fEnvelope_ (move (from.fEnvelope_))
228 Assert (from.fEnvelope_.GetPtr () ==
nullptr);
231 template <
typename T>
232 template <
typename T2, enable_if_t<is_convertible_v<T2*, T*>>*>
233 SharedPtr<T>::SharedPtr (
const SharedPtr<T2>& from) noexcept
234 : fEnvelope_ (from.fEnvelope_)
236 if (fEnvelope_.GetPtr () !=
nullptr) {
237 fEnvelope_.Increment ();
240 template <
typename T>
241 template <
typename T2, enable_if_t<is_convertible_v<T2*, T*>>*>
242 SharedPtr<T>::SharedPtr (SharedPtr<T2>&& from) noexcept
243 : fEnvelope_ (move (from.fEnvelope_))
245 Assert (from.fEnvelope_.GetPtr () ==
nullptr);
248 template <
typename T>
249 template <
typename T2>
250 inline typename SharedPtr<T>::Envelope_
251 SharedPtr<T>::mkEnvelope_ (T2* from, enable_if_t<is_convertible_v<T2*, Private_::ReferenceCounterContainerType_*>>*)
253 if (from ==
nullptr) {
254 return Envelope_{
nullptr,
nullptr};
257 return Envelope_{from, from};
260 template <
typename T>
261 template <
typename T2>
262 typename SharedPtr<T>::Envelope_ SharedPtr<T>::mkEnvelope_ (T2* from,
263 enable_if_t<!is_convertible_v<T2*, Private_::ReferenceCounterContainerType_*>>*)
265 return Envelope_{from, from ==
nullptr ? nullptr : ManuallyBlockAllocated<Private_::ReferenceCounterContainerType_>::New ()};
267 template <
typename T>
268 SharedPtr<T>& SharedPtr<T>::operator= (
const SharedPtr& rhs)
noexcept
270 if (rhs.fEnvelope_.GetPtr () != fEnvelope_.GetPtr ()) {
271 if (fEnvelope_.GetPtr () !=
nullptr) {
272 if (fEnvelope_.Decrement ()) {
273#if qStroika_FeatureSupported_Valgrind
274 fEnvelope_.ValgrindAnnotateGotLockZeroCaseClearing ();
276 fEnvelope_.DoDeleteCounter ();
277 delete fEnvelope_.GetPtr ();
278 fEnvelope_.SetPtr (
nullptr);
280#if qStroika_FeatureSupported_Valgrind
282 fEnvelope_.ValgrindAnnotateNotGotZeroCase ();
286 fEnvelope_ = rhs.fEnvelope_;
287 if (fEnvelope_.GetPtr () !=
nullptr) {
288 Assert (fEnvelope_.CurrentRefCount () > 0);
289 fEnvelope_.Increment ();
294 template <
typename T>
295 SharedPtr<T>& SharedPtr<T>::operator= (SharedPtr&& rhs)
noexcept
297 if (rhs.fEnvelope_.GetPtr () != fEnvelope_.GetPtr ()) {
298 if (fEnvelope_.GetPtr () !=
nullptr) {
299 if (fEnvelope_.Decrement ()) {
300#if qStroika_FeatureSupported_Valgrind
301 fEnvelope_.ValgrindAnnotateGotLockZeroCaseClearing ();
303 fEnvelope_.DoDeleteCounter ();
304 delete fEnvelope_.GetPtr ();
305 fEnvelope_.SetPtr (
nullptr);
307#if qStroika_FeatureSupported_Valgrind
309 fEnvelope_.ValgrindAnnotateNotGotZeroCase ();
313 fEnvelope_ = move (rhs.fEnvelope_);
314 Assert (rhs.fEnvelope_.GetPtr () ==
nullptr);
318 template <
typename T>
319 inline SharedPtr<T>::~SharedPtr ()
321 if (fEnvelope_.GetPtr () !=
nullptr) {
322 if (fEnvelope_.Decrement ()) {
323#if qStroika_FeatureSupported_Valgrind
324 fEnvelope_.ValgrindAnnotateGotLockZeroCaseClearing ();
326 fEnvelope_.DoDeleteCounter ();
327 delete fEnvelope_.GetPtr ();
329#if qStroika_FeatureSupported_Valgrind
331 fEnvelope_.ValgrindAnnotateNotGotZeroCase ();
336 template <
typename T>
337 inline bool SharedPtr<T>::IsNull () const noexcept
339 return fEnvelope_.GetPtr () ==
nullptr;
341 template <
typename T>
342 inline T& SharedPtr<T>::GetRep () const noexcept
345 Assert (fEnvelope_.CurrentRefCount () > 0);
346 return *fEnvelope_.GetPtr ();
348 template <
typename T>
349 inline T* SharedPtr<T>::operator->() const noexcept
353 template <
typename T>
354 inline T& SharedPtr<T>::operator* () const noexcept
358 template <
typename T>
359 inline SharedPtr<T>::operator T* ()
const noexcept
361 return fEnvelope_.GetPtr ();
363 template <
typename T>
364 inline T* SharedPtr<T>::get () const noexcept
366 return fEnvelope_.GetPtr ();
368 template <
typename T>
369 inline void SharedPtr<T>::release () noexcept
371 if (fEnvelope_.GetPtr () !=
nullptr) {
372 if (fEnvelope_.Decrement ()) {
373#if qStroika_FeatureSupported_Valgrind
374 fEnvelope_.ValgrindAnnotateGotLockZeroCaseClearing ();
376 fEnvelope_.DoDeleteCounter ();
377 delete fEnvelope_.GetPtr ();
378 fEnvelope_.SetPtr (
nullptr);
380#if qStroika_FeatureSupported_Valgrind
382 fEnvelope_.ValgrindAnnotateNotGotZeroCase ();
387 template <
typename T>
388 inline void SharedPtr<T>::clear () noexcept
392 template <
typename T>
393 inline void SharedPtr<T>::reset (T* p)
395 if (fEnvelope_.GetPtr () != p) {
396 *
this = SharedPtr<T> (p);
399 template <
typename T>
400 template <
typename T2>
401 inline SharedPtr<T2> SharedPtr<T>::Dynamic_Cast () const noexcept
403 return SharedPtr<T2> (
typename SharedPtr<T2>::Envelope_ (fEnvelope_,
dynamic_cast<T2*
> (get ())));
405 template <
typename T>
406 inline void SharedPtr<T>::swap (SharedPtr& rhs)
408 swap (fEnvelope_, rhs.fEnvelope_);
410 template <
typename T>
411 inline typename SharedPtr<T>::ReferenceCountType SharedPtr<T>::CurrentRefCount () const noexcept
413 return fEnvelope_.CurrentRefCount ();
415 template <
typename T>
416 inline typename SharedPtr<T>::ReferenceCountType SharedPtr<T>::use_count () const noexcept
418 return fEnvelope_.CurrentRefCount ();
420 template <
typename T>
421 inline bool SharedPtr<T>::IsUnique () const noexcept
423 return fEnvelope_.CurrentRefCount () == 1;
425 template <
typename T>
426 inline bool SharedPtr<T>::unique () const noexcept
431 template <
typename T>
432 constexpr bool SharedPtr<T>::operator== (
const SharedPtr& rhs)
const
434 return fEnvelope_.GetPtr () == rhs.fEnvelope_.GetPtr ();
436 template <
typename T>
437 constexpr bool SharedPtr<T>::operator== (nullptr_t)
const
439 return fEnvelope_.GetPtr () ==
nullptr;
441 template <
typename T>
442 constexpr strong_ordering SharedPtr<T>::operator<=> (
const SharedPtr& rhs)
const
444 return fEnvelope_.GetPtr () <=> rhs.fEnvelope_.GetPtr ();
446 template <
typename T>
447 inline SharedPtr<T>::operator bool () const noexcept
449 return get () !=
nullptr;
457 template <
typename T>
458 constexpr inline enable_shared_from_this<T>::enable_shared_from_this ()
459 : ReferenceCounterContainerType_ (false)
462 template <
typename T>
463 constexpr inline enable_shared_from_this<T>::enable_shared_from_this (
const enable_shared_from_this& )
464 : ReferenceCounterContainerType_ (false)
467 template <
typename T>
468 inline SharedPtr<T> enable_shared_from_this<T>::shared_from_this ()
483 T* ptr =
static_cast<T*
> (
this);
484 return (SharedPtr<T> (
typename SharedPtr<T>::Envelope_ (ptr,
this)));
489 template <
typename TO_TYPE_T,
typename FROM_TYPE_T>
490 inline Stroika::Foundation::Memory::SharedPtr<TO_TYPE_T> dynamic_pointer_cast (
const Stroika::Foundation::Memory::SharedPtr<FROM_TYPE_T>& sp)
noexcept
492 return sp.template Dynamic_Cast<TO_TYPE_T> ();
494 template <
typename T>
495 inline Stroika::Foundation::Memory::SharedPtr<T> atomic_load_explicit (
const Stroika::Foundation::Memory::SharedPtr<T>* copyFrom, memory_order)
499 [[maybe_unused]]
auto&& critSec = lock_guard{Memory::Private_::sSharedPtrCopyLock_};
500 Stroika::Foundation::Memory::SharedPtr<T> result = *copyFrom;
503 template <
typename T>
504 inline Stroika::Foundation::Memory::SharedPtr<T> atomic_load (
const Stroika::Foundation::Memory::SharedPtr<T>* p)
507 return atomic_load_explicit (p, memory_order_seq_cst);
509 template <
typename T>
510 inline void atomic_store_explicit (Stroika::Foundation::Memory::SharedPtr<T>* storeTo, Stroika::Foundation::Memory::SharedPtr<T> o, memory_order)
513 [[maybe_unused]] lock_guard critSec{Memory::Private_::sSharedPtrCopyLock_};
516 template <
typename T>
517 inline void atomic_store (Stroika::Foundation::Memory::SharedPtr<T>* storeTo, Stroika::Foundation::Memory::SharedPtr<T> o)
519 atomic_store_explicit (storeTo, o, memory_order_seq_cst);
521 DISABLE_COMPILER_MSC_WARNING_END (4996);
522 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wdeprecated-declarations\"");
523 DISABLE_COMPILER_CLANG_WARNING_END (
"clang diagnostic ignored \"-Wdeprecated-declarations\"");
#define RequireNotNull(p)