1 #ifndef INTRUSIVE_PTR_H
2 #define INTRUSIVE_PTR_H
7 #include "opthelpers.h"
17 unsigned int add_ref() noexcept
{ return IncrementRef(mRef
); }
18 unsigned int release() noexcept
20 auto ref
= DecrementRef(mRef
);
22 delete static_cast<T
*>(this);
27 * Release only if doing so would not bring the object to 0 references and
28 * delete it. Returns false if the object could not be released.
30 * NOTE: The caller is responsible for handling a failed release, as it
31 * means the object has no other references and needs to be be deleted
34 bool releaseIfNoDelete() noexcept
36 auto val
= mRef
.load(std::memory_order_acquire
);
37 while(val
> 1 && !mRef
.compare_exchange_strong(val
, val
-1, std::memory_order_acq_rel
))
39 /* val was updated with the current value on failure, so just try
54 intrusive_ptr() noexcept
= default;
55 intrusive_ptr(const intrusive_ptr
&rhs
) noexcept
: mPtr
{rhs
.mPtr
}
56 { if(mPtr
) mPtr
->add_ref(); }
57 intrusive_ptr(intrusive_ptr
&& rhs
) noexcept
: mPtr
{rhs
.mPtr
}
58 { rhs
.mPtr
= nullptr; }
59 intrusive_ptr(std::nullptr_t
) noexcept
{ }
60 explicit intrusive_ptr(T
*ptr
) noexcept
: mPtr
{ptr
} { }
61 ~intrusive_ptr() { if(mPtr
) mPtr
->release(); }
63 intrusive_ptr
& operator=(const intrusive_ptr
&rhs
) noexcept
65 static_assert(noexcept(std::declval
<T
*>()->release()), "release must be noexcept");
67 if(rhs
.mPtr
) rhs
.mPtr
->add_ref();
68 if(mPtr
) mPtr
->release();
72 intrusive_ptr
& operator=(intrusive_ptr
&& rhs
) noexcept
74 if(likely(&rhs
!= this))
76 if(mPtr
) mPtr
->release();
77 mPtr
= std::exchange(rhs
.mPtr
, nullptr);
82 explicit operator bool() const noexcept
{ return mPtr
!= nullptr; }
84 T
& operator*() const noexcept
{ return *mPtr
; }
85 T
* operator->() const noexcept
{ return mPtr
; }
86 T
* get() const noexcept
{ return mPtr
; }
88 void reset(T
*ptr
=nullptr) noexcept
95 T
* release() noexcept
{ return std::exchange(mPtr
, nullptr); }
97 void swap(intrusive_ptr
&rhs
) noexcept
{ std::swap(mPtr
, rhs
.mPtr
); }
98 void swap(intrusive_ptr
&& rhs
) noexcept
{ std::swap(mPtr
, rhs
.mPtr
); }
101 #define AL_DECL_OP(op) \
102 template<typename T> \
103 inline bool operator op(const intrusive_ptr<T> &lhs, const T *rhs) noexcept \
104 { return lhs.get() op rhs; } \
105 template<typename T> \
106 inline bool operator op(const T *lhs, const intrusive_ptr<T> &rhs) noexcept \
107 { return lhs op rhs.get(); }
120 #endif /* INTRUSIVE_PTR_H */