WPILibC++ 2027.0.0-alpha-2
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/**
13 * A custom intrusive shared pointer implementation without thread
14 * synchronization overhead.
15 *
16 * Types used with this class should have three things:
17 *
18 * 1. A zero-initialized public counter variable that serves as the shared
19 * pointer's reference count.
20 * 2. A free function `void inc_ref_count(T*)` that increments the reference
21 * count.
22 * 3. A free function `void dec_ref_count(T*)` that decrements the reference
23 * count and deallocates the pointed to object if the reference count reaches
24 * zero.
25 *
26 * @tparam T The type of the object to be reference counted.
27 */
28template <typename T>
30 public:
31 template <typename>
32 friend class IntrusiveSharedPtr;
33
34 /**
35 * Constructs an empty intrusive shared pointer.
36 */
37 constexpr IntrusiveSharedPtr() noexcept = default;
38
39 /**
40 * Constructs an empty intrusive shared pointer.
41 */
42 constexpr IntrusiveSharedPtr(std::nullptr_t) noexcept {} // NOLINT
43
44 /**
45 * Constructs an intrusive shared pointer from the given pointer and takes
46 * ownership.
47 *
48 * @param ptr The pointer of which to take ownership.
49 */
50 explicit constexpr IntrusiveSharedPtr(T* ptr) noexcept : m_ptr{ptr} {
51 if (m_ptr != nullptr) {
52 inc_ref_count(m_ptr);
53 }
54 }
55
56 constexpr ~IntrusiveSharedPtr() {
57 if (m_ptr != nullptr) {
58 dec_ref_count(m_ptr);
59 }
60 }
61
62 /**
63 * Copy constructs from the given intrusive shared pointer.
64 *
65 * @param rhs The other intrusive shared pointer.
66 */
67 constexpr IntrusiveSharedPtr(const IntrusiveSharedPtr<T>& rhs) noexcept
68 : m_ptr{rhs.m_ptr} {
69 if (m_ptr != nullptr) {
70 inc_ref_count(m_ptr);
71 }
72 }
73
74 /**
75 * Copy constructs from the given intrusive shared pointer.
76 *
77 * @param rhs The other intrusive shared pointer.
78 */
79 template <typename U>
80 requires(!std::same_as<T, U> && std::convertible_to<U*, T*>)
81 constexpr IntrusiveSharedPtr( // NOLINT
82 const IntrusiveSharedPtr<U>& rhs) noexcept
83 : m_ptr{rhs.m_ptr} {
84 if (m_ptr != nullptr) {
85 inc_ref_count(m_ptr);
86 }
87 }
88
89 /**
90 * Makes a copy of the given intrusive shared pointer.
91 *
92 * @param rhs The other intrusive shared pointer.
93 * @return This intrusive shared pointer.
94 */
95 constexpr IntrusiveSharedPtr<T>& operator=( // NOLINT
96 const IntrusiveSharedPtr<T>& rhs) noexcept {
97 if (m_ptr == rhs.m_ptr) {
98 return *this;
99 }
100
101 if (m_ptr != nullptr) {
102 dec_ref_count(m_ptr);
103 }
104
105 m_ptr = rhs.m_ptr;
106
107 if (m_ptr != nullptr) {
108 inc_ref_count(m_ptr);
109 }
110
111 return *this;
112 }
113
114 /**
115 * Makes a copy of the given intrusive shared pointer.
116 *
117 * @param rhs The other intrusive shared pointer.
118 * @return This intrusive shared pointer.
119 */
120 template <typename U>
121 requires(!std::same_as<T, U> && std::convertible_to<U*, T*>)
122 constexpr IntrusiveSharedPtr<T>& operator=( // NOLINT
123 const IntrusiveSharedPtr<U>& rhs) noexcept {
124 if (m_ptr == rhs.m_ptr) {
125 return *this;
126 }
127
128 if (m_ptr != nullptr) {
129 dec_ref_count(m_ptr);
130 }
131
132 m_ptr = rhs.m_ptr;
133
134 if (m_ptr != nullptr) {
135 inc_ref_count(m_ptr);
136 }
137
138 return *this;
139 }
140
141 /**
142 * Move constructs from the given intrusive shared pointer.
143 *
144 * @param rhs The other intrusive shared pointer.
145 */
147 : m_ptr{std::exchange(rhs.m_ptr, nullptr)} {}
148
149 /**
150 * Move constructs from the given intrusive shared pointer.
151 *
152 * @param rhs The other intrusive shared pointer.
153 */
154 template <typename U>
155 requires(!std::same_as<T, U> && std::convertible_to<U*, T*>)
156 constexpr IntrusiveSharedPtr( // NOLINT
157 IntrusiveSharedPtr<U>&& rhs) noexcept
158 : m_ptr{std::exchange(rhs.m_ptr, nullptr)} {}
159
160 /**
161 * Move assigns from the given intrusive shared pointer.
162 *
163 * @param rhs The other intrusive shared pointer.
164 * @return This intrusive shared pointer.
165 */
167 IntrusiveSharedPtr<T>&& rhs) noexcept {
168 if (m_ptr == rhs.m_ptr) {
169 return *this;
170 }
171
172 std::swap(m_ptr, rhs.m_ptr);
173
174 return *this;
175 }
176
177 /**
178 * Move assigns from the given intrusive shared pointer.
179 *
180 * @param rhs The other intrusive shared pointer.
181 * @return This intrusive shared pointer.
182 */
183 template <typename U>
184 requires(!std::same_as<T, U> && std::convertible_to<U*, T*>)
185 constexpr IntrusiveSharedPtr<T>& operator=(
186 IntrusiveSharedPtr<U>&& rhs) noexcept {
187 if (m_ptr == rhs.m_ptr) {
188 return *this;
189 }
190
191 std::swap(m_ptr, rhs.m_ptr);
192
193 return *this;
194 }
195
196 /**
197 * Returns the internal pointer.
198 *
199 * @return The internal pointer.
200 */
201 constexpr T* get() const noexcept { return m_ptr; }
202
203 /**
204 * Returns the object pointed to by the internal pointer.
205 *
206 * @return The object pointed to by the internal pointer.
207 */
208 constexpr T& operator*() const noexcept { return *m_ptr; }
209
210 /**
211 * Returns the internal pointer.
212 *
213 * @return The internal pointer.
214 */
215 constexpr T* operator->() const noexcept { return m_ptr; }
216
217 /**
218 * Returns true if the internal pointer isn't nullptr.
219 *
220 * @return True if the internal pointer isn't nullptr.
221 */
222 explicit constexpr operator bool() const noexcept { return m_ptr != nullptr; }
223
224 /**
225 * Returns true if the given intrusive shared pointers point to the same
226 * object.
227 *
228 * @param lhs The left-hand side.
229 * @param rhs The right-hand side.
230 */
231 friend constexpr bool operator==(const IntrusiveSharedPtr<T>& lhs,
232 const IntrusiveSharedPtr<T>& rhs) noexcept {
233 return lhs.m_ptr == rhs.m_ptr;
234 }
235
236 /**
237 * Returns true if the given intrusive shared pointers point to different
238 * objects.
239 *
240 * @param lhs The left-hand side.
241 * @param rhs The right-hand side.
242 */
243 friend constexpr bool operator!=(const IntrusiveSharedPtr<T>& lhs,
244 const IntrusiveSharedPtr<T>& rhs) noexcept {
245 return lhs.m_ptr != rhs.m_ptr;
246 }
247
248 /**
249 * Returns true if the left-hand intrusive shared pointer points to nullptr.
250 *
251 * @param lhs The left-hand side.
252 */
253 friend constexpr bool operator==(const IntrusiveSharedPtr<T>& lhs,
254 std::nullptr_t) noexcept {
255 return lhs.m_ptr == nullptr;
256 }
257
258 /**
259 * Returns true if the right-hand intrusive shared pointer points to nullptr.
260 *
261 * @param rhs The right-hand side.
262 */
263 friend constexpr bool operator==(std::nullptr_t,
264 const IntrusiveSharedPtr<T>& rhs) noexcept {
265 return nullptr == rhs.m_ptr;
266 }
267
268 /**
269 * Returns true if the left-hand intrusive shared pointer doesn't point to
270 * nullptr.
271 *
272 * @param lhs The left-hand side.
273 */
274 friend constexpr bool operator!=(const IntrusiveSharedPtr<T>& lhs,
275 std::nullptr_t) noexcept {
276 return lhs.m_ptr != nullptr;
277 }
278
279 /**
280 * Returns true if the right-hand intrusive shared pointer doesn't point to
281 * nullptr.
282 *
283 * @param rhs The right-hand side.
284 */
285 friend constexpr bool operator!=(std::nullptr_t,
286 const IntrusiveSharedPtr<T>& rhs) noexcept {
287 return nullptr != rhs.m_ptr;
288 }
289
290 private:
291 T* m_ptr = nullptr;
292};
293
294/**
295 * Constructs an object of type T and wraps it in an intrusive shared pointer
296 * using args as the parameter list for the constructor of T.
297 *
298 * @tparam T Type of object for intrusive shared pointer.
299 * @tparam Args Types of constructor arguments.
300 * @param args Constructor arguments for T.
301 */
302template <typename T, typename... Args>
304 return IntrusiveSharedPtr<T>{new T(std::forward<Args>(args)...)};
305}
306
307/**
308 * Constructs an object of type T and wraps it in an intrusive shared pointer
309 * using alloc as the storage allocator of T and args as the parameter list for
310 * the constructor of T.
311 *
312 * @tparam T Type of object for intrusive shared pointer.
313 * @tparam Alloc Type of allocator for T.
314 * @tparam Args Types of constructor arguments.
315 * @param alloc The allocator for T.
316 * @param args Constructor arguments for T.
317 */
318template <typename T, typename Alloc, typename... Args>
320 auto ptr = std::allocator_traits<Alloc>::allocate(alloc, sizeof(T));
321 std::allocator_traits<Alloc>::construct(alloc, ptr,
322 std::forward<Args>(args)...);
324}
325
326} // namespace slp
A custom intrusive shared pointer implementation without thread synchronization overhead.
Definition intrusive_shared_ptr.hpp:29
constexpr IntrusiveSharedPtr(IntrusiveSharedPtr< U > &&rhs) noexcept
Move constructs from the given intrusive shared pointer.
Definition intrusive_shared_ptr.hpp:156
constexpr IntrusiveSharedPtr< T > & operator=(IntrusiveSharedPtr< T > &&rhs) noexcept
Move assigns from the given intrusive shared pointer.
Definition intrusive_shared_ptr.hpp:166
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:263
constexpr T * get() const noexcept
Returns the internal pointer.
Definition intrusive_shared_ptr.hpp:201
constexpr IntrusiveSharedPtr(const IntrusiveSharedPtr< T > &rhs) noexcept
Copy constructs from the given intrusive shared pointer.
Definition intrusive_shared_ptr.hpp:67
constexpr T * operator->() const noexcept
Returns the internal pointer.
Definition intrusive_shared_ptr.hpp:215
constexpr ~IntrusiveSharedPtr()
Definition intrusive_shared_ptr.hpp:56
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:274
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:253
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:231
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:50
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:285
constexpr IntrusiveSharedPtr(IntrusiveSharedPtr< T > &&rhs) noexcept
Move constructs from the given intrusive shared pointer.
Definition intrusive_shared_ptr.hpp:146
constexpr T & operator*() const noexcept
Returns the object pointed to by the internal pointer.
Definition intrusive_shared_ptr.hpp:208
constexpr IntrusiveSharedPtr(const IntrusiveSharedPtr< U > &rhs) noexcept
Copy constructs from the given intrusive shared pointer.
Definition intrusive_shared_ptr.hpp:81
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:243
constexpr IntrusiveSharedPtr< T > & operator=(const IntrusiveSharedPtr< T > &rhs) noexcept
Makes a copy of the given intrusive shared pointer.
Definition intrusive_shared_ptr.hpp:95
auto ptr(T p) -> const void *
Converts p to const void* for pointer formatting.
Definition format.h:3925
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:303
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:319
Definition PointerIntPair.h:280
WPI_BASIC_JSON_TPL_DECLARATION void swap(wpi::WPI_BASIC_JSON_TPL &j1, wpi::WPI_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp) is_nothrow_move_constructible< wpi::WPI_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression, cppcoreguidelines-noexcept-swap, performance-noexcept-swap) is_nothrow_move_assignable< wpi::WPI_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition json.h:5258
decltype(nullptr) nullptr_t
Definition base.h:327