xrpld
Loading...
Searching...
No Matches
IntrusivePointer.h
1#pragma once
2
3#include <concepts>
4#include <cstddef>
5#include <cstdint>
6#include <type_traits>
7#include <utility>
8
9namespace xrpl {
10
11//------------------------------------------------------------------------------
12
21
31
39
47
48//------------------------------------------------------------------------------
49//
50
51template <class T>
54
55//------------------------------------------------------------------------------
56
72template <class T>
74{
75public:
76 SharedIntrusive() = default;
77
78 template <CAdoptTag TAdoptTag>
79 SharedIntrusive(T* p, TAdoptTag) noexcept;
80
82
83 template <class TT>
84 // TODO: convertible_to isn't quite right. That include a static castable.
85 // Find the right concept.
86 requires std::convertible_to<TT*, T*>
88
90
91 template <class TT>
92 requires std::convertible_to<TT*, T*>
94 SharedIntrusive<TT>&& rhs); // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
95
98
99 bool
101
102 template <class TT>
103 requires std::convertible_to<TT*, T*>
106
109
110 template <class TT>
111 requires std::convertible_to<TT*, T*>
114 SharedIntrusive<TT>&& rhs); // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
115
120 template <CAdoptTag TAdoptTag = SharedIntrusiveAdoptIncrementStrongTag>
121 void
122 adopt(T* p);
123
125
130 template <class TT>
132
137 template <class TT>
139
144 template <class TT>
146
151 template <class TT>
153
154 T&
155 operator*() const noexcept;
156
157 T*
158 operator->() const noexcept;
159
160 explicit
161 operator bool() const noexcept;
162
167 void
169
173 [[nodiscard]] T*
174 get() const;
175
179 [[nodiscard]] std::size_t
180 useCount() const;
181
182 template <class TT, class... Args>
183 friend SharedIntrusive<TT>
184 makeSharedIntrusive(Args&&... args);
185
186 template <class TT>
187 friend class SharedIntrusive;
188
189 template <class TT>
190 friend class SharedWeakUnion;
191
192 template <class TT>
193 friend class WeakIntrusive;
194
195private:
199 [[nodiscard]] T*
201
207 void
209
214 void
216
223 T*
225
229 T* ptr_{nullptr};
230};
231
232//------------------------------------------------------------------------------
233
241template <class T>
243{
244public:
245 WeakIntrusive() = default;
246
248
250
252
253 // There is no move constructor from a strong intrusive ptr because
254 // moving would be move expensive than copying in this case (the strong
255 // ref would need to be decremented)
256 WeakIntrusive(SharedIntrusive<T> const&& rhs) = delete;
257
258 // Since there are no current use cases for copy assignment in
259 // WeakIntrusive, we delete this operator to simplify the implementation. If
260 // a need arises in the future, we can reintroduce it with proper
261 // consideration."
263 operator=(WeakIntrusive const&) = delete;
264
265 template <class TT>
266 requires std::convertible_to<TT*, T*>
269
273 void
274 adopt(T* ptr);
275
277
284 lock() const;
285
289 [[nodiscard]] bool
290 expired() const;
291
297 void
299
300private:
301 T* ptr_ = nullptr;
302
309 void
311};
312
313//------------------------------------------------------------------------------
314
326
327template <class T>
329{
330 // Tagged pointer. Low bit determines if this is a strong or a weak
331 // pointer. The low bit must be masked to zero when converting back to a
332 // pointer. If the low bit is '1', this is a weak pointer.
333 static_assert(alignof(T) >= 2, "Bad alignment: Combo pointer requires low bit to be zero");
334
335public:
336 SharedWeakUnion() = default;
337
339
340 template <class TT>
341 requires std::convertible_to<TT*, T*>
343
345
346 template <class TT>
347 requires std::convertible_to<TT*, T*>
349 SharedIntrusive<TT>&& rhs); // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
350
353
354 template <class TT>
355 requires std::convertible_to<TT*, T*>
358
359 template <class TT>
360 requires std::convertible_to<TT*, T*>
363 SharedIntrusive<TT>&& rhs); // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
364
366
372 [[nodiscard]] SharedIntrusive<T>
373 getStrong() const;
374
379 explicit
380 operator bool() const noexcept;
381
386 void
388
393 [[nodiscard]] T*
394 get() const;
395
400 [[nodiscard]] std::size_t
401 useCount() const;
402
406 [[nodiscard]] bool
407 expired() const;
408
413 [[nodiscard]] SharedIntrusive<T>
414 lock() const;
415
419 [[nodiscard]] bool
420 isStrong() const;
421
425 [[nodiscard]] bool
426 isWeak() const;
427
435 bool
437
444 bool
446
447private:
448 // Tagged pointer. Low bit determines if this is a strong or a weak
449 // pointer. The low bit must be masked to zero when converting back to a
450 // pointer. If the low bit is '1', this is a weak pointer.
451 std::uintptr_t tp_{0};
452 static constexpr std::uintptr_t kTagMask = 1;
454
455private:
459 [[nodiscard]] T*
461
462 enum class RefStrength { Strong, Weak };
466 void
468
473
478 void
480};
481
482//------------------------------------------------------------------------------
483
491template <class TT, class... Args>
493makeSharedIntrusive(Args&&... args)
494{
495 auto p = new TT(std::forward<Args>(args)...);
496
497 static_assert(
498 noexcept(SharedIntrusive<TT>(
500 "SharedIntrusive constructor should not throw or this can leak "
501 "memory");
502
504}
505
506//------------------------------------------------------------------------------
507
508namespace intr_ptr {
509template <class T>
511
512template <class T>
514
515template <class T>
517
518template <class T, class... A>
520makeShared(A&&... args)
521{
523}
524
525template <class T, class TT>
528{
530}
531
532template <class T, class TT>
535{
537}
538} // namespace intr_ptr
539} // namespace xrpl
A shared intrusive pointer class that supports weak pointers.
SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive< TT > const &rhs)
Create a new SharedIntrusive by dynamically casting the pointer controlled by the rhs param.
SHAMapTreeNode * unsafeGetRawPtr() const
SharedIntrusive & operator=(SharedIntrusive< TT > const &rhs)
bool operator==(std::nullptr_t) const
SharedIntrusive(SharedIntrusive< TT > const &rhs)
SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive< TT > const &rhs)
Create a new SharedIntrusive by statically casting the pointer controlled by the rhs param.
void unsafeSetRawPtr(SHAMapTreeNode *p)
SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive< TT > &&rhs)
Create a new SharedIntrusive by dynamically casting the pointer controlled by the rhs param.
SHAMapTreeNode * unsafeExchange(SHAMapTreeNode *p)
SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive< TT > &&rhs)
Create a new SharedIntrusive by statically casting the pointer controlled by the rhs param.
void adopt(T *p)
Adopt the raw pointer.
SharedIntrusive & operator=(SharedIntrusive &&rhs)
void unsafeReleaseAndStore(SHAMapTreeNode *next)
SharedIntrusive(SharedIntrusive< TT > &&rhs)
SharedIntrusive(SharedIntrusive const &rhs)
SharedIntrusive(T *p, TAdoptTag) noexcept
friend SharedIntrusive< TT > makeSharedIntrusive(Args &&... args)
SharedIntrusive & operator=(SharedIntrusive< TT > &&rhs)
SharedIntrusive & operator=(SharedIntrusive const &rhs)
T & operator*() const noexcept
SharedIntrusive(SharedIntrusive &&rhs)
A combination of a strong and a weak intrusive pointer stored in the space of a single pointer.
void unsafeSetRawPtr(std::nullptr_t)
Set the raw pointer and tag bit to all zeros (strong null pointer).
SharedWeakUnion(SharedIntrusive< TT > const &rhs)
SharedWeakUnion(SharedWeakUnion const &rhs)
static constexpr std::uintptr_t kPtrMask
bool expired() const
Return true if there is a non-zero strong count.
SharedWeakUnion(SharedWeakUnion &&rhs)
SharedWeakUnion(SharedIntrusive< TT > &&rhs)
void reset()
Set the pointer to null, decrement the appropriate ref count, and run the appropriate release action.
static constexpr std::uintptr_t kTagMask
void unsafeSetRawPtr(T *p, RefStrength rs)
Set the raw pointer and tag bit directly.
T * unsafeGetRawPtr() const
Return the raw pointer held by this object.
T * get() const
If this is a strong pointer, return the raw pointer.
SharedWeakUnion & operator=(SharedIntrusive< TT > const &rhs)
bool convertToStrong()
If this is a weak pointer, attempt to convert it to a strong pointer.
SharedIntrusive< T > lock() const
If this is a strong pointer, return the strong pointer.
SharedWeakUnion & operator=(SharedIntrusive< TT > &&rhs)
SharedWeakUnion & operator=(SharedWeakUnion const &rhs)
void unsafeReleaseNoStore()
Decrement the appropriate ref count, and run the appropriate release action.
bool convertToWeak()
If this is a strong pointer, attempt to convert it to a weak pointer.
bool isStrong() const
Return true is this represents a strong pointer.
std::size_t useCount() const
If this is a strong pointer, return the strong count.
bool isWeak() const
Return true is this represents a weak pointer.
SharedIntrusive< T > getStrong() const
Return a strong pointer if this is already a strong pointer (i.e.
A weak intrusive pointer class for the SharedIntrusive pointer class.
WeakIntrusive(SharedIntrusive< T > const &&rhs)=delete
void unsafeReleaseNoStore()
Decrement the weak count.
WeakIntrusive(WeakIntrusive const &rhs)
void adopt(T *ptr)
Adopt the raw pointer and increment the weak count.
WeakIntrusive(SharedIntrusive< T > const &rhs)
SharedIntrusive< T > lock() const
Get a strong pointer from the weak pointer, if possible.
WeakIntrusive & operator=(SharedIntrusive< TT > const &rhs)
WeakIntrusive & operator=(WeakIntrusive const &)=delete
bool expired() const
Return true if the strong count is zero.
WeakIntrusive(WeakIntrusive &&rhs)
WeakIntrusive()=default
void reset()
Set the pointer to null and decrement the weak count.
T declval(T... args)
T forward(T... args)
T is_same_v
STL namespace.
SharedWeakUnion< T > SharedWeakUnionPtr
SharedPtr< T > dynamicPointerCast(TT const &v)
SharedPtr< T > staticPointerCast(TT const &v)
SharedIntrusive< T > SharedPtr
WeakIntrusive< T > WeakPtr
SharedPtr< T > makeShared(A &&... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
SharedIntrusive< TT > makeSharedIntrusive(Args &&... args)
Create a shared intrusive pointer.
Tag to create an intrusive pointer from another intrusive pointer by using a dynamic cast.
When creating or adopting a raw pointer, controls whether the strong count is incremented or not.
When creating or adopting a raw pointer, controls whether the strong count is incremented or not.
Tag to create an intrusive pointer from another intrusive pointer by using a static cast.