rippled
Loading...
Searching...
No Matches
IntrusivePointer.h
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2023 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#ifndef RIPPLE_BASICS_INTRUSIVEPOINTER_H_INCLUDED
21#define RIPPLE_BASICS_INTRUSIVEPOINTER_H_INCLUDED
22
23#include <concepts>
24#include <cstdint>
25#include <type_traits>
26#include <utility>
27
28namespace ripple {
29
30//------------------------------------------------------------------------------
31
39
48
55
62
63//------------------------------------------------------------------------------
64//
65
66template <class T>
69
70//------------------------------------------------------------------------------
71
86template <class T>
88{
89public:
90 SharedIntrusive() = default;
91
92 template <CAdoptTag TAdoptTag>
93 SharedIntrusive(T* p, TAdoptTag) noexcept;
94
96
97 template <class TT>
98 // TODO: convertible_to isn't quite right. That include a static castable.
99 // Find the right concept.
102
104
105 template <class TT>
108
111
112 bool
114
115 bool
117
118 template <class TT>
122
125
126 template <class TT>
130
134 template <CAdoptTag TAdoptTag = SharedIntrusiveAdoptIncrementStrongTag>
135 void
136 adopt(T* p);
137
139
143 template <class TT>
146 SharedIntrusive<TT> const& rhs);
147
151 template <class TT>
153
157 template <class TT>
160 SharedIntrusive<TT> const& rhs);
161
165 template <class TT>
167
168 T&
169 operator*() const noexcept;
170
171 T*
172 operator->() const noexcept;
173
174 explicit
175 operator bool() const noexcept;
176
180 void
182
184 T*
185 get() const;
186
188 std::size_t
189 use_count() const;
190
191 template <class TT, class... Args>
192 friend SharedIntrusive<TT>
193 make_SharedIntrusive(Args&&... args);
194
195 template <class TT>
196 friend class SharedIntrusive;
197
198 template <class TT>
199 friend class SharedWeakUnion;
200
201 template <class TT>
202 friend class WeakIntrusive;
203
204private:
206 T*
208
213 void
215
219 void
221
227 T*
229
231 T* ptr_{nullptr};
232};
233
234//------------------------------------------------------------------------------
235
242template <class T>
244{
245public:
246 WeakIntrusive() = default;
247
249
251
253
254 // There is no move constructor from a strong intrusive ptr because
255 // moving would be move expensive than copying in this case (the strong
256 // ref would need to be decremented)
257 WeakIntrusive(SharedIntrusive<T> const&& rhs) = delete;
258
259 // Since there are no current use cases for copy assignment in
260 // WeakIntrusive, we delete this operator to simplify the implementation. If
261 // a need arises in the future, we can reintroduce it with proper
262 // consideration."
264 operator=(WeakIntrusive const&) = delete;
265
266 template <class TT>
270
272 void
273 adopt(T* ptr);
274
276
282 lock() const;
283
285 bool
286 expired() const;
287
292 void
294
295private:
296 T* ptr_ = nullptr;
297
303 void
305};
306
307//------------------------------------------------------------------------------
308
320template <class T>
322{
323 // Tagged pointer. Low bit determines if this is a strong or a weak
324 // pointer. The low bit must be masked to zero when converting back to a
325 // pointer. If the low bit is '1', this is a weak pointer.
326 static_assert(
327 alignof(T) >= 2,
328 "Bad alignment: Combo pointer requires low bit to be zero");
329
330public:
331 SharedWeakUnion() = default;
332
334
335 template <class TT>
338
340
341 template <class TT>
344
347
348 template <class TT>
352
353 template <class TT>
357
359
365 getStrong() const;
366
370 explicit
371 operator bool() const noexcept;
372
376 void
378
382 T*
383 get() const;
384
388 std::size_t
389 use_count() const;
390
392 bool
393 expired() const;
394
399 lock() const;
400
402 bool
403 isStrong() const;
404
406 bool
407 isWeak() const;
408
415 bool
417
423 bool
425
426private:
427 // Tagged pointer. Low bit determines if this is a strong or a weak
428 // pointer. The low bit must be masked to zero when converting back to a
429 // pointer. If the low bit is '1', this is a weak pointer.
430 std::uintptr_t tp_{0};
431 static constexpr std::uintptr_t tagMask = 1;
432 static constexpr std::uintptr_t ptrMask = ~tagMask;
433
434private:
437 T*
439
440 enum class RefStrength { strong, weak };
443 void
445
449
453 void
455};
456
457//------------------------------------------------------------------------------
458
465template <class TT, class... Args>
467make_SharedIntrusive(Args&&... args)
468{
469 auto p = new TT(std::forward<Args>(args)...);
470
471 static_assert(
472 noexcept(SharedIntrusive<TT>(
475 "SharedIntrusive constructor should not throw or this can leak "
476 "memory");
477
479}
480
481//------------------------------------------------------------------------------
482
483namespace intr_ptr {
484template <class T>
486
487template <class T>
489
490template <class T>
492
493template <class T, class... A>
495make_shared(A&&... args)
496{
497 return make_SharedIntrusive<T>(std::forward<A>(args)...);
498}
499
500template <class T, class TT>
501SharedPtr<T>
503{
505}
506
507template <class T, class TT>
508SharedPtr<T>
510{
512}
513} // namespace intr_ptr
514} // namespace ripple
515#endif
A shared intrusive pointer class that supports weak pointers.
bool operator!=(std::nullptr_t) const
T * ptr_
pointer to the type with an intrusive count
T & operator*() const noexcept
SharedIntrusive & operator=(SharedIntrusive const &rhs)
void adopt(T *p)
Adopt the raw pointer.
SharedIntrusive(T *p, TAdoptTag) noexcept
SharedIntrusive(SharedIntrusive< TT > &&rhs)
std::size_t use_count() const
Return the strong count.
SharedIntrusive & operator=(SharedIntrusive< TT > &&rhs)
T * unsafeGetRawPtr() const
Return the raw pointer held by this object.
friend SharedIntrusive< TT > make_SharedIntrusive(Args &&... args)
Create a shared intrusive pointer.
SharedIntrusive & operator=(SharedIntrusive &&rhs)
SharedIntrusive(SharedIntrusive &&rhs)
SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive< TT > &&rhs)
Create a new SharedIntrusive by dynamically casting the pointer controlled by the rhs param.
SharedIntrusive & operator=(SharedIntrusive< TT > const &rhs)
T * get() const
Get the raw pointer.
SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive< TT > &&rhs)
Create a new SharedIntrusive by statically casting the pointer controlled by the rhs param.
SharedIntrusive(SharedIntrusive const &rhs)
void reset()
Set the pointer to null, decrement the strong count, and run the appropriate release action.
SharedIntrusive(SharedIntrusive< TT > const &rhs)
void unsafeSetRawPtr(T *p)
Set the raw pointer directly.
SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive< TT > const &rhs)
Create a new SharedIntrusive by dynamically casting the pointer controlled by the rhs param.
SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive< TT > const &rhs)
Create a new SharedIntrusive by statically casting the pointer controlled by the rhs param.
void unsafeReleaseAndStore(T *next)
Exchange the current raw pointer held by this object with the given pointer.
T * unsafeExchange(T *p)
Exchange the raw pointer directly.
bool operator==(std::nullptr_t) const
A combination of a strong and a weak intrusive pointer stored in the space of a single pointer.
SharedIntrusive< T > getStrong() const
Return a strong pointer if this is already a strong pointer (i.e.
SharedIntrusive< T > lock() const
If this is a strong pointer, return the strong pointer.
T * unsafeGetRawPtr() const
Return the raw pointer held by this object.
bool expired() const
Return true if there is a non-zero strong count.
SharedWeakUnion & operator=(SharedIntrusive< TT > const &rhs)
bool isStrong() const
Return true is this represents a strong pointer.
SharedWeakUnion(SharedWeakUnion &&rhs)
SharedWeakUnion & operator=(SharedIntrusive< TT > &&rhs)
SharedWeakUnion(SharedIntrusive< TT > &&rhs)
bool convertToWeak()
If this is a strong pointer, attempt to convert it to a weak pointer.
T * get() const
If this is a strong pointer, return the raw pointer.
void reset()
Set the pointer to null, decrement the appropriate ref count, and run the appropriate release action.
std::size_t use_count() const
If this is a strong pointer, return the strong count.
SharedWeakUnion & operator=(SharedWeakUnion const &rhs)
SharedWeakUnion(SharedIntrusive< TT > const &rhs)
static constexpr std::uintptr_t ptrMask
bool convertToStrong()
If this is a weak pointer, attempt to convert it to a strong pointer.
void unsafeReleaseNoStore()
Decrement the appropriate ref count, and run the appropriate release action.
void unsafeSetRawPtr(T *p, RefStrength rs)
Set the raw pointer and tag bit directly.
bool isWeak() const
Return true is this represents a weak pointer.
void unsafeSetRawPtr(std::nullptr_t)
Set the raw pointer and tag bit to all zeros (strong null pointer).
static constexpr std::uintptr_t tagMask
SharedWeakUnion(SharedWeakUnion const &rhs)
A weak intrusive pointer class for the SharedIntrusive pointer class.
WeakIntrusive(SharedIntrusive< T > const &&rhs)=delete
bool expired() const
Return true if the strong count is zero.
WeakIntrusive & operator=(SharedIntrusive< TT > const &rhs)
void adopt(T *ptr)
Adopt the raw pointer and increment the weak count.
WeakIntrusive(SharedIntrusive< T > const &rhs)
void unsafeReleaseNoStore()
Decrement the weak count.
WeakIntrusive & operator=(WeakIntrusive const &)=delete
SharedIntrusive< T > lock() const
Get a strong pointer from the weak pointer, if possible.
WeakIntrusive(WeakIntrusive &&rhs)
void reset()
Set the pointer to null and decrement the weak count.
WeakIntrusive(WeakIntrusive const &rhs)
T is_same_v
SharedPtr< T > make_shared(A &&... args)
SharedPtr< T > static_pointer_cast(TT const &v)
SharedPtr< T > dynamic_pointer_cast(TT const &v)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
SharedIntrusive< TT > make_SharedIntrusive(Args &&... args)
Create a shared intrusive pointer.
STL namespace.
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.