Lagrange
Loading...
Searching...
No Matches
shared_ptr.h
1// Source: https://github.com/X-czh/smart_ptr
2// SPDX-License-Identifier: MIT
3//
4// This file has been modified by Adobe.
5//
6// All modifications are Copyright 2022 Adobe.
7
8#pragma once
9
10#include <lagrange/internal/smart_ptr/control_block.h>
11#include <lagrange/internal/weak_ptr.h>
12#include <lagrange/utils/assert.h>
13
14#include <cstddef>
15#include <iostream>
16#include <memory>
17#include <type_traits>
18#include <utility>
19
20namespace lagrange::internal {
21
22// Forward declarations
23
24template <typename T>
25class shared_ptr;
26template <typename T>
27class weak_ptr;
28
29// shared_ptr_access general template
30// Defines operator*, operator-> and operator[]
31// for T not array or cv void
32
33template <typename T, bool = std::is_array<T>::value, bool = std::is_void<T>::value>
35{
36public:
37 using element_type = T;
38
40 element_type& operator*() const noexcept
41 {
42 la_debug_assert(_get() != nullptr);
43 return *_get();
44 }
45
47 element_type* operator->() const noexcept
48 {
49 la_debug_assert(_get() != nullptr);
50 return _get();
51 }
52
53private:
54 element_type* _get() const noexcept { return static_cast<const shared_ptr<T>*>(this)->get(); }
55};
56
57// specialization of shared_ptr_access for T array type
58// Defines operator[] for shared_ptr<T[]> and shared_ptr<T[N]>
59
60template <typename T>
61class shared_ptr_access<T, true, false>
62{
63public:
64 using element_type = typename std::remove_extent<T>::type;
65
67 element_type* operator[](std::ptrdiff_t i) const noexcept
68 {
69 la_debug_assert(_get() != nullptr);
70 static_assert(!std::extent<T>::value || i < std::extent<T>::value);
71 return _get()[i];
72 }
73
74private:
75 element_type* _get() const noexcept { return static_cast<const shared_ptr<T>*>(this)->get(); }
76};
77
78// specialization of shared_ptr_access for T cv void type
79// Defines operator-> for shared_ptr<cv void>
80
81template <typename T>
82class shared_ptr_access<T, false, true>
83{
84public:
85 using element_type = T;
86
88 element_type* operator->() const noexcept
89 {
90 la_debug_assert(_get() != nullptr);
91 return _get();
92 }
93
94private:
95 element_type* _get() const noexcept { return static_cast<const shared_ptr<T>*>(this)->get(); }
96};
97
98// 20.7.2.2 Class template shared_ptr
99
100/* supports shared_ptr<T[]> and shared_ptr<T[N]>: added in C++17 */
101
108
109template <typename T>
110class shared_ptr : public shared_ptr_access<T>
111{
112public:
113 template <typename U>
114 friend class shared_ptr;
115
116 template <typename U>
117 friend class weak_ptr;
118
119 using element_type = typename shared_ptr_access<T>::element_type;
120 using weak_type = weak_ptr<T>; /* added in C++17 */
121
122 // 20.7.2.2.1, constructors
123
126 constexpr shared_ptr() noexcept
127 : _ptr{}
128 , _control_block{}
129 {}
130
133 constexpr shared_ptr(std::nullptr_t) noexcept
134 : _ptr{}
135 , _control_block{}
136 {}
137
140 template <typename U>
141 explicit shared_ptr(U* p)
142 : _ptr{p}
143 , _control_block{new control_block<U>{p}}
144 {}
145
149 template <typename U, typename D, typename A>
150 shared_ptr(U* p, D d, A a) = delete;
151
155 template <typename D, typename A>
156 shared_ptr(std::nullptr_t p, D d, A a) = delete;
157
161 template <typename U>
162 shared_ptr(const shared_ptr<U>& sp, T* p) noexcept
163 : _ptr{p}
164 , _control_block{sp._control_block}
165 {
166 if (_control_block) _control_block->inc_ref();
167 }
168
171 shared_ptr(const shared_ptr& sp) noexcept
172 : _ptr{sp._ptr}
173 , _control_block{sp._control_block}
174 {
175 if (_control_block) _control_block->inc_ref();
176 }
177
180 template <typename U>
181 shared_ptr(const shared_ptr<U>& sp) noexcept
182 : _ptr{sp._ptr}
183 , _control_block{sp._control_block}
184 {
185 if (_control_block) _control_block->inc_ref();
186 }
187
191 shared_ptr(shared_ptr&& sp) noexcept
192 : _ptr{std::move(sp._ptr)}
193 , _control_block{std::move(sp._control_block)}
194 {
195 sp._ptr = nullptr;
196 sp._control_block = nullptr;
197 }
198
202 template <typename U>
203 shared_ptr(shared_ptr<U>&& sp) noexcept
204 : _ptr{sp._ptr}
205 , _control_block{sp._control_block}
206 {
207 sp._ptr = nullptr;
208 sp._control_block = nullptr;
209 }
210
213 template <typename U>
214 explicit shared_ptr(const weak_ptr<U>& wp)
215 : _ptr{wp._ptr}
216 , _control_block{wp._control_block}
217 {
218 if (wp.expired()) {
219 throw std::bad_weak_ptr{};
220 } else {
221 _control_block->inc_ref();
222 }
223 }
224
225 // 20.7.2.2.2, destructor
226
228 {
229 if (_control_block) _control_block->dec_ref();
230 }
231
232 // 20.7.2.2.3, assignment
233
235 shared_ptr& operator=(const shared_ptr& sp) noexcept
236 {
237 shared_ptr{sp}.swap(*this);
238 return *this;
239 }
240
242 template <typename U>
243 shared_ptr& operator=(const shared_ptr<U>& sp) noexcept
244 {
245 shared_ptr{sp}.swap(*this);
246 return *this;
247 }
248
250 shared_ptr& operator=(shared_ptr&& sp) noexcept
251 {
252 shared_ptr{std::move(sp)}.swap(*this);
253 return *this;
254 }
255
257 template <typename U>
258 shared_ptr& operator=(shared_ptr<U>&& sp) noexcept
259 {
260 shared_ptr{std::move(sp)}.swap(*this);
261 return *this;
262 }
263
264 // 20.7.2.2.4, modifiers
265
267 void swap(shared_ptr& sp) noexcept
268 {
269 using std::swap;
270 swap(_ptr, sp._ptr);
271 swap(_control_block, sp._control_block);
272 }
273
275 void reset() noexcept { shared_ptr{}.swap(*this); }
276
278 template <typename U>
279 void reset(U* p)
280 {
281 shared_ptr{p}.swap(*this);
282 }
283
286 template <typename U, typename D>
287 void reset(U* p, D d)
288 {
289 shared_ptr{p, d}.swap(*this);
290 }
291
294 template <typename U, typename D, typename A>
295 void reset(U* p, D d, A a) = delete;
296
297 // 20.7.2.2.5, observers
298
300 element_type* get() const noexcept { return _ptr; }
301
302 /* implemented in shared_ptr_access<T> */
303
304 // /// Dereferences pointer to the managed object
305 // element_type&
306 // operator*() const noexcept
307 // { return *_ptr; }
308
309 // /// Dereferences pointer to the managed object
310 // element_type*
311 // operator->() const noexcept
312 // { return _ptr; }
313
315 long use_count() const noexcept { return (_control_block) ? _control_block->use_count() : 0; }
316
317 /* deprecated in C++17, removed in C++20 */
319 bool unique() const noexcept { return (_control_block) ? _control_block->unique() : false; }
320
322 explicit operator bool() const noexcept { return (_ptr) ? true : false; }
323
324private:
325 element_type* _ptr;
326 control_block_base* _control_block;
327};
328
329// 20.7.2.2.6, shared_ptr creation
330
332template <typename T, typename... Args>
334{
335 return shared_ptr<T>{new T{std::forward<Args>(args)...}};
336}
337
338template <typename T, typename A, typename... Args>
339inline shared_ptr<T> allocate_shared(const A& a, Args&&... args) = delete;
340
341// 20.7.2.2.7, shared_ptr comparisons
342
344template <typename T, typename U>
345inline bool operator==(const shared_ptr<T>& sp1, const shared_ptr<U>& sp2)
346{
347 return sp1.get() == sp2.get();
348}
349
350template <typename T>
351inline bool operator==(const shared_ptr<T>& sp, std::nullptr_t) noexcept
352{
353 return !sp;
354}
355
356template <typename T>
357inline bool operator==(std::nullptr_t, const shared_ptr<T>& sp) noexcept
358{
359 return !sp;
360}
361
363template <typename T, typename U>
364inline bool operator!=(const shared_ptr<T>& sp1, const shared_ptr<U>& sp2)
365{
366 return sp1.get() != sp2.get();
367}
368
369template <typename T>
370inline bool operator!=(const shared_ptr<T>& sp, std::nullptr_t) noexcept
371{
372 return bool{sp};
373}
374
375template <typename T>
376inline bool operator!=(std::nullptr_t, const shared_ptr<T>& sp) noexcept
377{
378 return bool{sp};
379}
380
381// 20.7.2.2.8, shared_ptr specialized algorithms
382
384template <typename T>
385inline void swap(shared_ptr<T>& sp1, shared_ptr<T>& sp2)
386{
387 sp1.swap(sp2);
388}
389
390// 20.7.2.2.9, shared_ptr casts
391
392template <typename T, typename U>
393inline shared_ptr<T> static_pointer_cast(const shared_ptr<U>& sp) noexcept
394{
395 using _Sp = shared_ptr<T>;
396 return _Sp(sp, static_cast<typename _Sp::element_type*>(sp.get()));
397}
398
399template <typename T, typename U>
400inline shared_ptr<T> const_pointer_cast(const shared_ptr<U>& sp) noexcept
401{
402 using _Sp = shared_ptr<T>;
403 return _Sp(sp, const_cast<typename _Sp::element_type*>(sp.get()));
404}
405
406template <typename T, typename U>
407inline shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& sp) noexcept
408{
409 using _Sp = shared_ptr<T>;
410 if (auto* _p = dynamic_cast<typename _Sp::element_type*>(sp.get())) return _Sp(sp, _p);
411 return _Sp();
412}
413
414/* added in C++17 */
415template <typename T, typename U>
416inline shared_ptr<T> reinterpret_pointer_cast(const shared_ptr<U>& sp) noexcept
417{
418 using _Sp = shared_ptr<T>;
419 return _Sp(sp, reinterpret_cast<typename _Sp::element_type*>(sp.get()));
420}
421
422// 20.7.2.2.11, shared_ptr I/O
423
424template <class E, class T, class Y>
425inline std::basic_ostream<E, T>& operator<<(std::basic_ostream<E, T>& os, const shared_ptr<Y>& sp)
426{
427 os << sp.get();
428 return os;
429}
430
431} // namespace lagrange::internal
Definition control_block.h:24
NOT implemented: custom allocator support.
Definition control_block.h:52
element_type * operator->() const noexcept
Dereferences pointer to the managed object, operator* is not provided.
Definition shared_ptr.h:88
element_type * operator[](std::ptrdiff_t i) const noexcept
Index operator, dereferencing operators are not provided.
Definition shared_ptr.h:67
Definition shared_ptr.h:35
element_type & operator*() const noexcept
Dereferences pointer to the managed object.
Definition shared_ptr.h:40
element_type * operator->() const noexcept
Dereferences pointer to the managed object.
Definition shared_ptr.h:47
NOT implemented: custom allocator support.
Definition shared_ptr.h:111
bool unique() const noexcept
Checks if use_count == 1.
Definition shared_ptr.h:319
void reset() noexcept
Resets *this to empty.
Definition shared_ptr.h:275
shared_ptr(const shared_ptr< U > &sp) noexcept
Copy constructor: shares ownership of the object managed by sp Postconditions: use_count() == sp....
Definition shared_ptr.h:181
void reset(U *p)
Resets *this with p as the pointer to the managed object.
Definition shared_ptr.h:279
shared_ptr(U *p, D d, A a)=delete
Constructs a shared_ptr with p as the pointer to the managed object, supplied with custom deleter and...
shared_ptr(shared_ptr &&sp) noexcept
Move constructor: Move-constructs a shared_ptr from sp Postconditions: *this shall contain the old va...
Definition shared_ptr.h:191
shared_ptr & operator=(const shared_ptr< U > &sp) noexcept
Copy assignment.
Definition shared_ptr.h:243
shared_ptr & operator=(shared_ptr &&sp) noexcept
Move assignment.
Definition shared_ptr.h:250
shared_ptr & operator=(const shared_ptr &sp) noexcept
Copy assignment.
Definition shared_ptr.h:235
shared_ptr(std::nullptr_t p, D d, A a)=delete
Constructs a shared_ptr with no managed object, supplied with custom deleter and allocator Postcondit...
long use_count() const noexcept
Gets use_count.
Definition shared_ptr.h:315
shared_ptr(const shared_ptr &sp) noexcept
Copy constructor: shares ownership of the object managed by sp Postconditions: use_count() == sp....
Definition shared_ptr.h:171
shared_ptr(const shared_ptr< U > &sp, T *p) noexcept
Aliasing constructor: constructs a shared_ptr instance that stores p and shares ownership with sp Pos...
Definition shared_ptr.h:162
shared_ptr(shared_ptr< U > &&sp) noexcept
Move constructor: Move-constructs a shared_ptr from sp Postconditions: *this shall contain the old va...
Definition shared_ptr.h:203
element_type * get() const noexcept
Gets the stored pointer.
Definition shared_ptr.h:300
shared_ptr & operator=(shared_ptr< U > &&sp) noexcept
Move assignment.
Definition shared_ptr.h:258
constexpr shared_ptr() noexcept
Default constructor, creates a shared_ptr with no managed object Postconditions: use_count() == 0 && ...
Definition shared_ptr.h:126
void swap(shared_ptr &sp) noexcept
Exchanges the contents of *this and sp.
Definition shared_ptr.h:267
constexpr shared_ptr(std::nullptr_t) noexcept
Constructs a shared_ptr with no managed object Postconditions: use_count() == 0 && get() == 0.
Definition shared_ptr.h:133
shared_ptr(const weak_ptr< U > &wp)
Constructs a shared_ptr object that shares ownership with wp Postconditions: use_count() == wp....
Definition shared_ptr.h:214
void reset(U *p, D d)
Resets *this with p as the pointer to the managed object, supplied with custom deleter.
Definition shared_ptr.h:287
shared_ptr(U *p)
Constructs a shared_ptr with p as the pointer to the managed object Postconditions: use_count() == 1 ...
Definition shared_ptr.h:141
void reset(U *p, D d, A a)=delete
Resets *this with p as the pointer to the managed object, supplied with custom deleter and allocator.
Definition weak_ptr.h:26
bool expired() const noexcept
Checks if use_count == 0.
Definition weak_ptr.h:122
#define la_debug_assert(...)
Debug assertion check.
Definition assert.h:194
nullptr_t, size_t, ptrdiff_t basic_ostream bad_weak_ptr extent, remove_extent, is_array,...
Definition attribute_string_utils.h:21
bool operator==(const shared_ptr< T > &sp1, const shared_ptr< U > &sp2)
Operator == overloading.
Definition shared_ptr.h:345
void swap(shared_ptr< T > &sp1, shared_ptr< T > &sp2)
Swaps with another shared_ptr.
Definition shared_ptr.h:385
shared_ptr< T > make_shared(Args &&... args)
Creates a shared_ptr that manages a new object.
Definition shared_ptr.h:333
bool operator!=(const shared_ptr< T > &sp1, const shared_ptr< U > &sp2)
Operator != overloading.
Definition shared_ptr.h:364
Definition project.cpp:27