WPILibC++ 2027.0.0-alpha-4
Loading...
Searching...
No Matches
intrusive_shared_ptr.hpp
Go to the documentation of this file.
1// Copyright (c) Sleipnir contributors
2
3#pragma once
4
5#include <concepts>
6#include <cstddef>
7#include <memory>
8#include <utility>
9
10namespace slp {
11
12/// A custom intrusive shared pointer implementation without thread
13/// synchronization overhead.
14///
15/// Types used with this class should have three things:
16///
17/// 1. A zero-initialized public counter variable that serves as the shared
18/// pointer's reference count.
19/// 2. A free function `void inc_ref_count(T*)` that increments the reference
20/// count.
21/// 3. A free function `void dec_ref_count(T*)` that decrements the reference
22/// count and deallocates the pointed to object if the reference count
23/// reaches zero.
24///
25/// @tparam T The type of the object to be reference counted.
26template <typename T>
28 public:
29 template <typename>
30 friend class IntrusiveSharedPtr;
31
32 /// Constructs an empty intrusive shared pointer.
33 constexpr IntrusiveSharedPtr() noexcept = default;
34
35 /// Constructs an empty intrusive shared pointer.
36 // NOLINTNEXTLINE (google-explicit-constructor)
37 constexpr IntrusiveSharedPtr(std::nullptr_t) noexcept {}
38
39 /// Constructs an intrusive shared pointer from the given pointer and takes
40 /// ownership.
41 ///
42 /// @param ptr The pointer of which to take ownership.
43 explicit constexpr IntrusiveSharedPtr(T* ptr) noexcept : m_ptr{ptr} {
44 if (m_ptr != nullptr) {
45 inc_ref_count(m_ptr);
46 }
47 }
48
49 constexpr ~IntrusiveSharedPtr() {
50 if (m_ptr != nullptr) {
51 dec_ref_count(m_ptr);
52 }
53 }
54
55 /// Copy constructs from the given intrusive shared pointer.
56 ///
57 /// @param rhs The other intrusive shared pointer.
58 constexpr IntrusiveSharedPtr(const IntrusiveSharedPtr<T>& rhs) noexcept
59 : m_ptr{rhs.m_ptr} {
60 if (m_ptr != nullptr) {
61 inc_ref_count(m_ptr);
62 }
63 }
64
65 /// Copy constructs from the given intrusive shared pointer.
66 ///
67 /// @param rhs The other intrusive shared pointer.
68 template <typename U>
69 requires(!std::same_as<T, U> && std::convertible_to<U*, T*>)
70 // NOLINTNEXTLINE (google-explicit-constructor)
71 constexpr IntrusiveSharedPtr(const IntrusiveSharedPtr<U>& rhs) noexcept
72 : m_ptr{rhs.m_ptr} {
73 if (m_ptr != nullptr) {
74 inc_ref_count(m_ptr);
75 }
76 }
77
78 /// Makes a copy of the given intrusive shared pointer.
79 ///
80 /// @param rhs The other intrusive shared pointer.
81 /// @return This intrusive shared pointer.
82 // NOLINTNEXTLINE (google-explicit-constructor)
84 const IntrusiveSharedPtr<T>& rhs) noexcept {
85 if (m_ptr == rhs.m_ptr) {
86 return *this;
87 }
88
89 if (m_ptr != nullptr) {
90 dec_ref_count(m_ptr);
91 }
92
93 m_ptr = rhs.m_ptr;
94
95 if (m_ptr != nullptr) {
96 inc_ref_count(m_ptr);
97 }
98
99 return *this;
100 }
101
102 /// Makes a copy of the given intrusive shared pointer.
103 ///
104 /// @param rhs The other intrusive shared pointer.
105 /// @return This intrusive shared pointer.
106 template <typename U>
107 requires(!std::same_as<T, U> && std::convertible_to<U*, T*>)
108 // NOLINTNEXTLINE (google-explicit-constructor)
109 constexpr IntrusiveSharedPtr<T>& operator=(
110 const IntrusiveSharedPtr<U>& rhs) noexcept {
111 if (m_ptr == rhs.m_ptr) {
112 return *this;
113 }
114
115 if (m_ptr != nullptr) {
116 dec_ref_count(m_ptr);
117 }
118
119 m_ptr = rhs.m_ptr;
120
121 if (m_ptr != nullptr) {
122 inc_ref_count(m_ptr);
123 }
124
125 return *this;
126 }
127
128 /// Move constructs from the given intrusive shared pointer.
129 ///
130 /// @param rhs The other intrusive shared pointer.
132 : m_ptr{std::exchange(rhs.m_ptr, nullptr)} {}
133
134 /// Move constructs from the given intrusive shared pointer.
135 ///
136 /// @param rhs The other intrusive shared pointer.
137 template <typename U>
138 requires(!std::same_as<T, U> && std::convertible_to<U*, T*>)
139 // NOLINTNEXTLINE (google-explicit-constructor)
141 : m_ptr{std::exchange(rhs.m_ptr, nullptr)} {}
142
143 /// Move assigns from the given intrusive shared pointer.
144 ///
145 /// @param rhs The other intrusive shared pointer.
146 /// @return This intrusive shared pointer.
148 IntrusiveSharedPtr<T>&& rhs) noexcept {
149 if (m_ptr == rhs.m_ptr) {
150 return *this;
151 }
152
153 std::swap(m_ptr, rhs.m_ptr);
154
155 return *this;
156 }
157
158 /// Move assigns from the given intrusive shared pointer.
159 ///
160 /// @param rhs The other intrusive shared pointer.
161 /// @return This intrusive shared pointer.
162 template <typename U>
163 requires(!std::same_as<T, U> && std::convertible_to<U*, T*>)
164 constexpr IntrusiveSharedPtr<T>& operator=(
165 IntrusiveSharedPtr<U>&& rhs) noexcept {
166 if (m_ptr == rhs.m_ptr) {
167 return *this;
168 }
169
170 std::swap(m_ptr, rhs.m_ptr);
171
172 return *this;
173 }
174
175 /// Returns the internal pointer.
176 ///
177 /// @return The internal pointer.
178 constexpr T* get() const noexcept { return m_ptr; }
179
180 /// Returns the object pointed to by the internal pointer.
181 ///
182 /// @return The object pointed to by the internal pointer.
183 constexpr T& operator*() const noexcept { return *m_ptr; }
184
185 /// Returns the internal pointer.
186 ///
187 /// @return The internal pointer.
188 constexpr T* operator->() const noexcept { return m_ptr; }
189
190 /// Returns true if the internal pointer isn't nullptr.
191 ///
192 /// @return True if the internal pointer isn't nullptr.
193 explicit constexpr operator bool() const noexcept { return m_ptr != nullptr; }
194
195 /// Returns true if the given intrusive shared pointers point to the same
196 /// object.
197 ///
198 /// @param lhs The left-hand side.
199 /// @param rhs The right-hand side.
200 friend constexpr bool operator==(const IntrusiveSharedPtr<T>& lhs,
201 const IntrusiveSharedPtr<T>& rhs) noexcept {
202 return lhs.m_ptr == rhs.m_ptr;
203 }
204
205 /// Returns true if the given intrusive shared pointers point to different
206 /// objects.
207 ///
208 /// @param lhs The left-hand side.
209 /// @param rhs The right-hand side.
210 friend constexpr bool operator!=(const IntrusiveSharedPtr<T>& lhs,
211 const IntrusiveSharedPtr<T>& rhs) noexcept {
212 return lhs.m_ptr != rhs.m_ptr;
213 }
214
215 /// Returns true if the left-hand intrusive shared pointer points to nullptr.
216 ///
217 /// @param lhs The left-hand side.
218 friend constexpr bool operator==(const IntrusiveSharedPtr<T>& lhs,
219 std::nullptr_t) noexcept {
220 return lhs.m_ptr == nullptr;
221 }
222
223 /// Returns true if the right-hand intrusive shared pointer points to nullptr.
224 ///
225 /// @param rhs The right-hand side.
226 friend constexpr bool operator==(std::nullptr_t,
227 const IntrusiveSharedPtr<T>& rhs) noexcept {
228 return nullptr == rhs.m_ptr;
229 }
230
231 /// Returns true if the left-hand intrusive shared pointer doesn't point to
232 /// nullptr.
233 ///
234 /// @param lhs The left-hand side.
235 friend constexpr bool operator!=(const IntrusiveSharedPtr<T>& lhs,
236 std::nullptr_t) noexcept {
237 return lhs.m_ptr != nullptr;
238 }
239
240 /// Returns true if the right-hand intrusive shared pointer doesn't point to
241 /// nullptr.
242 ///
243 /// @param rhs The right-hand side.
244 friend constexpr bool operator!=(std::nullptr_t,
245 const IntrusiveSharedPtr<T>& rhs) noexcept {
246 return nullptr != rhs.m_ptr;
247 }
248
249 private:
250 T* m_ptr = nullptr;
251};
252
253/// Constructs an object of type T and wraps it in an intrusive shared pointer
254/// using args as the parameter list for the constructor of T.
255///
256/// @tparam T Type of object for intrusive shared pointer.
257/// @tparam Args Types of constructor arguments.
258/// @param args Constructor arguments for T.
259template <typename T, typename... Args>
261 return IntrusiveSharedPtr<T>{new T(std::forward<Args>(args)...)};
262}
263
264/// Constructs an object of type T and wraps it in an intrusive shared pointer
265/// using alloc as the storage allocator of T and args as the parameter list for
266/// the constructor of T.
267///
268/// @tparam T Type of object for intrusive shared pointer.
269/// @tparam Alloc Type of allocator for T.
270/// @tparam Args Types of constructor arguments.
271/// @param alloc The allocator for T.
272/// @param args Constructor arguments for T.
273template <typename T, typename Alloc, typename... Args>
275 auto ptr = std::allocator_traits<Alloc>::allocate(alloc, sizeof(T));
276 std::allocator_traits<Alloc>::construct(alloc, ptr,
277 std::forward<Args>(args)...);
279}
280
281} // namespace slp
decltype(nullptr) nullptr_t
Definition base.h:322
A custom intrusive shared pointer implementation without thread synchronization overhead.
Definition intrusive_shared_ptr.hpp:27
constexpr IntrusiveSharedPtr(IntrusiveSharedPtr< U > &&rhs) noexcept
Move constructs from the given intrusive shared pointer.
Definition intrusive_shared_ptr.hpp:140
constexpr IntrusiveSharedPtr< T > & operator=(IntrusiveSharedPtr< T > &&rhs) noexcept
Move assigns from the given intrusive shared pointer.
Definition intrusive_shared_ptr.hpp:147
friend constexpr bool operator==(std::nullptr_t, const IntrusiveSharedPtr< T > &rhs) noexcept
Returns true if the right-hand intrusive shared pointer points to nullptr.
Definition intrusive_shared_ptr.hpp:226
constexpr T * get() const noexcept
Returns the internal pointer.
Definition intrusive_shared_ptr.hpp:178
constexpr IntrusiveSharedPtr(const IntrusiveSharedPtr< T > &rhs) noexcept
Copy constructs from the given intrusive shared pointer.
Definition intrusive_shared_ptr.hpp:58
constexpr T * operator->() const noexcept
Returns the internal pointer.
Definition intrusive_shared_ptr.hpp:188
friend class IntrusiveSharedPtr
Definition intrusive_shared_ptr.hpp:30
constexpr ~IntrusiveSharedPtr()
Definition intrusive_shared_ptr.hpp:49
friend constexpr bool operator!=(const IntrusiveSharedPtr< T > &lhs, std::nullptr_t) noexcept
Returns true if the left-hand intrusive shared pointer doesn't point to nullptr.
Definition intrusive_shared_ptr.hpp:235
friend constexpr bool operator==(const IntrusiveSharedPtr< T > &lhs, std::nullptr_t) noexcept
Returns true if the left-hand intrusive shared pointer points to nullptr.
Definition intrusive_shared_ptr.hpp:218
friend constexpr bool operator==(const IntrusiveSharedPtr< T > &lhs, const IntrusiveSharedPtr< T > &rhs) noexcept
Returns true if the given intrusive shared pointers point to the same object.
Definition intrusive_shared_ptr.hpp:200
constexpr IntrusiveSharedPtr() noexcept=default
Constructs an empty intrusive shared pointer.
constexpr IntrusiveSharedPtr(T *ptr) noexcept
Constructs an intrusive shared pointer from the given pointer and takes ownership.
Definition intrusive_shared_ptr.hpp:43
friend constexpr bool operator!=(std::nullptr_t, const IntrusiveSharedPtr< T > &rhs) noexcept
Returns true if the right-hand intrusive shared pointer doesn't point to nullptr.
Definition intrusive_shared_ptr.hpp:244
constexpr IntrusiveSharedPtr(IntrusiveSharedPtr< T > &&rhs) noexcept
Move constructs from the given intrusive shared pointer.
Definition intrusive_shared_ptr.hpp:131
constexpr T & operator*() const noexcept
Returns the object pointed to by the internal pointer.
Definition intrusive_shared_ptr.hpp:183
constexpr IntrusiveSharedPtr(const IntrusiveSharedPtr< U > &rhs) noexcept
Copy constructs from the given intrusive shared pointer.
Definition intrusive_shared_ptr.hpp:71
friend constexpr bool operator!=(const IntrusiveSharedPtr< T > &lhs, const IntrusiveSharedPtr< T > &rhs) noexcept
Returns true if the given intrusive shared pointers point to different objects.
Definition intrusive_shared_ptr.hpp:210
constexpr IntrusiveSharedPtr< T > & operator=(const IntrusiveSharedPtr< T > &rhs) noexcept
Makes a copy of the given intrusive shared pointer.
Definition intrusive_shared_ptr.hpp:83
auto ptr(T p) -> const void *
Converts p to const void* for pointer formatting.
Definition format.h:3975
Definition expression_graph.hpp:11
IntrusiveSharedPtr< T > make_intrusive_shared(Args &&... args)
Constructs an object of type T and wraps it in an intrusive shared pointer using args as the paramete...
Definition intrusive_shared_ptr.hpp:260
IntrusiveSharedPtr< T > allocate_intrusive_shared(Alloc alloc, Args &&... args)
Constructs an object of type T and wraps it in an intrusive shared pointer using alloc as the storage...
Definition intrusive_shared_ptr.hpp:274
Definition StringMap.hpp:773
void swap(wpi::util::StringMap< T > &lhs, wpi::util::StringMap< T > &rhs)
Definition StringMap.hpp:775