Lagrange
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
13#include <cstddef>
14#include <iostream>
15#include <memory>
16#include <type_traits>
17#include <utility>
18
19namespace lagrange::internal {
20
21// Forward declarations
22
23template <typename T>
24class shared_ptr;
25template <typename T>
26class weak_ptr;
27
28// shared_ptr_access general template
29// Defines operator*, operator-> and operator[]
30// for T not array or cv void
31
32template <typename T, bool = std::is_array<T>::value, bool = std::is_void<T>::value>
34{
35public:
36 using element_type = T;
37
39 element_type& operator*() const noexcept
40 {
41 assert(_get() != nullptr);
42 return *_get();
43 }
44
46 element_type* operator->() const noexcept
47 {
48 assert(_get() != nullptr);
49 return _get();
50 }
51
52private:
53 element_type* _get() const noexcept { return static_cast<const shared_ptr<T>*>(this)->get(); }
54};
55
56// specialization of shared_ptr_access for T array type
57// Defines operator[] for shared_ptr<T[]> and shared_ptr<T[N]>
58
59template <typename T>
60class shared_ptr_access<T, true, false>
61{
62public:
63 using element_type = typename std::remove_extent<T>::type;
64
66 element_type* operator[](std::ptrdiff_t i) const noexcept
67 {
68 assert(_get() != nullptr);
69 static_assert(!std::extent<T>::value || i < std::extent<T>::value);
70 return _get()[i];
71 }
72
73private:
74 element_type* _get() const noexcept { return static_cast<const shared_ptr<T>*>(this)->get(); }
75};
76
77// specialization of shared_ptr_access for T cv void type
78// Defines operator-> for shared_ptr<cv void>
79
80template <typename T>
81class shared_ptr_access<T, false, true>
82{
83public:
84 using element_type = T;
85
87 element_type* operator->() const noexcept
88 {
89 assert(_get() != nullptr);
90 return _get();
91 }
92
93private:
94 element_type* _get() const noexcept { return static_cast<const shared_ptr<T>*>(this)->get(); }
95};
96
97// 20.7.2.2 Class template shared_ptr
98
99/* supports shared_ptr<T[]> and shared_ptr<T[N]>: added in C++17 */
100
108template <typename T>
110{
111public:
112 template <typename U>
113 friend class shared_ptr;
114
115 template <typename U>
116 friend class weak_ptr;
117
118 using element_type = typename shared_ptr_access<T>::element_type;
119 using weak_type = weak_ptr<T>; /* added in C++17 */
120
121 // 20.7.2.2.1, constructors
122
125 constexpr shared_ptr() noexcept
126 : _ptr{}
127 , _control_block{}
128 {}
129
132 constexpr shared_ptr(std::nullptr_t) noexcept
133 : _ptr{}
134 , _control_block{}
135 {}
136
139 template <typename U>
140 explicit shared_ptr(U* p)
141 : _ptr{p}
142 , _control_block{new control_block<U>{p}}
143 {}
144
148 template <typename U, typename D, typename A>
149 shared_ptr(U* p, D d, A a) = delete;
150
154 template <typename D, typename A>
155 shared_ptr(std::nullptr_t p, D d, A a) = delete;
156
160 template <typename U>
161 shared_ptr(const shared_ptr<U>& sp, T* p) noexcept
162 : _ptr{p}
163 , _control_block{sp._control_block}
164 {
165 if (_control_block) _control_block->inc_ref();
166 }
167
170 shared_ptr(const shared_ptr& sp) noexcept
171 : _ptr{sp._ptr}
172 , _control_block{sp._control_block}
173 {
174 if (_control_block) _control_block->inc_ref();
175 }
176
179 template <typename U>
180 shared_ptr(const shared_ptr<U>& sp) noexcept
181 : _ptr{sp._ptr}
182 , _control_block{sp._control_block}
183 {
184 if (_control_block) _control_block->inc_ref();
185 }
186
190 shared_ptr(shared_ptr&& sp) noexcept
191 : _ptr{std::move(sp._ptr)}
192 , _control_block{std::move(sp._control_block)}
193 {
194 sp._ptr = nullptr;
195 sp._control_block = nullptr;
196 }
197
201 template <typename U>
203 : _ptr{sp._ptr}
204 , _control_block{sp._control_block}
205 {
206 sp._ptr = nullptr;
207 sp._control_block = nullptr;
208 }
209
212 template <typename U>
213 explicit shared_ptr(const weak_ptr<U>& wp)
214 : _ptr{wp._ptr}
215 , _control_block{wp._control_block}
216 {
217 if (wp.expired()) {
218 throw std::bad_weak_ptr{};
219 } else {
220 _control_block->inc_ref();
221 }
222 }
223
224 // 20.7.2.2.2, destructor
225
227 {
228 if (_control_block) _control_block->dec_ref();
229 }
230
231 // 20.7.2.2.3, assignment
232
234 shared_ptr& operator=(const shared_ptr& sp) noexcept
235 {
236 shared_ptr{sp}.swap(*this);
237 return *this;
238 }
239
241 template <typename U>
242 shared_ptr& operator=(const shared_ptr<U>& sp) noexcept
243 {
244 shared_ptr{sp}.swap(*this);
245 return *this;
246 }
247
250 {
251 shared_ptr{std::move(sp)}.swap(*this);
252 return *this;
253 }
254
256 template <typename U>
258 {
259 shared_ptr{std::move(sp)}.swap(*this);
260 return *this;
261 }
262
263 // 20.7.2.2.4, modifiers
264
266 void swap(shared_ptr& sp) noexcept
267 {
268 using std::swap;
269 swap(_ptr, sp._ptr);
270 swap(_control_block, sp._control_block);
271 }
272
274 void reset() noexcept { shared_ptr{}.swap(*this); }
275
277 template <typename U>
278 void reset(U* p)
279 {
280 shared_ptr{p}.swap(*this);
281 }
282
285 template <typename U, typename D>
286 void reset(U* p, D d)
287 {
288 shared_ptr{p, d}.swap(*this);
289 }
290
293 template <typename U, typename D, typename A>
294 void reset(U* p, D d, A a) = delete;
295
296 // 20.7.2.2.5, observers
297
299 element_type* get() const noexcept { return _ptr; }
300
301 /* implemented in shared_ptr_access<T> */
302
303 // /// Dereferences pointer to the managed object
304 // element_type&
305 // operator*() const noexcept
306 // { return *_ptr; }
307
308 // /// Dereferences pointer to the managed object
309 // element_type*
310 // operator->() const noexcept
311 // { return _ptr; }
312
314 long use_count() const noexcept { return (_control_block) ? _control_block->use_count() : 0; }
315
316 /* deprecated in C++17, removed in C++20 */
318 bool unique() const noexcept { return (_control_block) ? _control_block->unique() : false; }
319
321 explicit operator bool() const noexcept { return (_ptr) ? true : false; }
322
323private:
324 element_type* _ptr;
325 control_block_base* _control_block;
326};
327
328// 20.7.2.2.6, shared_ptr creation
329
331template <typename T, typename... Args>
333{
334 return shared_ptr<T>{new T{std::forward<Args>(args)...}};
335}
336
337template <typename T, typename A, typename... Args>
338inline shared_ptr<T> allocate_shared(const A& a, Args&&... args) = delete;
339
340// 20.7.2.2.7, shared_ptr comparisons
341
343template <typename T, typename U>
344inline bool operator==(const shared_ptr<T>& sp1, const shared_ptr<U>& sp2)
345{
346 return sp1.get() == sp2.get();
347}
348
349template <typename T>
350inline bool operator==(const shared_ptr<T>& sp, std::nullptr_t) noexcept
351{
352 return !sp;
353}
354
355template <typename T>
356inline bool operator==(std::nullptr_t, const shared_ptr<T>& sp) noexcept
357{
358 return !sp;
359}
360
362template <typename T, typename U>
363inline bool operator!=(const shared_ptr<T>& sp1, const shared_ptr<U>& sp2)
364{
365 return sp1.get() != sp2.get();
366}
367
368template <typename T>
369inline bool operator!=(const shared_ptr<T>& sp, std::nullptr_t) noexcept
370{
371 return bool{sp};
372}
373
374template <typename T>
375inline bool operator!=(std::nullptr_t, const shared_ptr<T>& sp) noexcept
376{
377 return bool{sp};
378}
379
380// 20.7.2.2.8, shared_ptr specialized algorithms
381
383template <typename T>
384inline void swap(shared_ptr<T>& sp1, shared_ptr<T>& sp2)
385{
386 sp1.swap(sp2);
387}
388
389// 20.7.2.2.9, shared_ptr casts
390
391template <typename T, typename U>
392inline shared_ptr<T> static_pointer_cast(const shared_ptr<U>& sp) noexcept
393{
394 using _Sp = shared_ptr<T>;
395 return _Sp(sp, static_cast<typename _Sp::element_type*>(sp.get()));
396}
397
398template <typename T, typename U>
399inline shared_ptr<T> const_pointer_cast(const shared_ptr<U>& sp) noexcept
400{
401 using _Sp = shared_ptr<T>;
402 return _Sp(sp, const_cast<typename _Sp::element_type*>(sp.get()));
403}
404
405template <typename T, typename U>
406inline shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& sp) noexcept
407{
408 using _Sp = shared_ptr<T>;
409 if (auto* _p = dynamic_cast<typename _Sp::element_type*>(sp.get())) return _Sp(sp, _p);
410 return _Sp();
411}
412
413/* added in C++17 */
414template <typename T, typename U>
415inline shared_ptr<T> reinterpret_pointer_cast(const shared_ptr<U>& sp) noexcept
416{
417 using _Sp = shared_ptr<T>;
418 return _Sp(sp, reinterpret_cast<typename _Sp::element_type*>(sp.get()));
419}
420
421// 20.7.2.2.11, shared_ptr I/O
422
423template <class E, class T, class Y>
424inline std::basic_ostream<E, T>& operator<<(std::basic_ostream<E, T>& os, const shared_ptr<Y>& sp)
425{
426 os << sp.get();
427 return os;
428}
429
430} // 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:87
element_type * operator[](std::ptrdiff_t i) const noexcept
Index operator, dereferencing operators are not provided.
Definition: shared_ptr.h:66
Definition: shared_ptr.h:34
element_type & operator*() const noexcept
Dereferences pointer to the managed object.
Definition: shared_ptr.h:39
element_type * operator->() const noexcept
Dereferences pointer to the managed object.
Definition: shared_ptr.h:46
NOT implemented: custom allocator support.
Definition: shared_ptr.h:110
bool unique() const noexcept
Checks if use_count == 1.
Definition: shared_ptr.h:318
void reset() noexcept
Resets *this to empty.
Definition: shared_ptr.h:274
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:180
void reset(U *p)
Resets *this with p as the pointer to the managed object.
Definition: shared_ptr.h:278
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:190
shared_ptr & operator=(const shared_ptr< U > &sp) noexcept
Copy assignment.
Definition: shared_ptr.h:242
shared_ptr & operator=(shared_ptr &&sp) noexcept
Move assignment.
Definition: shared_ptr.h:249
shared_ptr & operator=(const shared_ptr &sp) noexcept
Copy assignment.
Definition: shared_ptr.h:234
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:314
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:170
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:161
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:202
element_type * get() const noexcept
Gets the stored pointer.
Definition: shared_ptr.h:299
shared_ptr & operator=(shared_ptr< U > &&sp) noexcept
Move assignment.
Definition: shared_ptr.h:257
constexpr shared_ptr() noexcept
Default constructor, creates a shared_ptr with no managed object Postconditions: use_count() == 0 && ...
Definition: shared_ptr.h:125
void swap(shared_ptr &sp) noexcept
Exchanges the contents of *this and sp.
Definition: shared_ptr.h:266
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:132
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:213
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:286
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:140
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
constexpr void swap(function_ref< R(Args...)> &lhs, function_ref< R(Args...)> &rhs) noexcept
Swaps the referred callables of lhs and rhs.
Definition: function_ref.h:114
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:344
void swap(shared_ptr< T > &sp1, shared_ptr< T > &sp2)
Swaps with another shared_ptr.
Definition: shared_ptr.h:384
shared_ptr< T > make_shared(Args &&... args)
Creates a shared_ptr that manages a new object.
Definition: shared_ptr.h:332
bool operator!=(const shared_ptr< T > &sp1, const shared_ptr< U > &sp2)
Operator != overloading.
Definition: shared_ptr.h:363
Definition: project.cpp:27