Pigweed
 
Loading...
Searching...
No Matches
shared_ptr.h
1// Copyright 2025 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <cstddef>
17#include <utility>
18
19#include "pw_allocator/internal/control_block.h"
20#include "pw_allocator/internal/managed_ptr.h"
21
22namespace pw {
23
24// Forward declaration.
25template <typename T>
26class WeakPtr;
27
43template <typename T>
44class SharedPtr final : public ::pw::allocator::internal::ManagedPtr<T> {
45 private:
46 using Base = ::pw::allocator::internal::ManagedPtr<T>;
47 using ControlBlock = ::pw::allocator::internal::ControlBlock;
48
49 public:
50 using element_type = typename Base::element_type;
51 using weak_type = WeakPtr<T>;
52
55
60 constexpr SharedPtr() noexcept = default;
61
66 constexpr SharedPtr(std::nullptr_t) noexcept : SharedPtr() {}
67
69 constexpr SharedPtr(const SharedPtr& other) noexcept : SharedPtr() {
70 *this = other;
71 }
72
77 template <typename U>
78 constexpr SharedPtr(const SharedPtr<U>& other) noexcept : SharedPtr() {
79 *this = other;
80 }
81
87 template <typename U>
88 SharedPtr(SharedPtr<U>&& other) noexcept : SharedPtr() {
89 *this = std::move(other);
90 }
91
95 constexpr SharedPtr& operator=(const SharedPtr& other) noexcept {
96 operator= <T>(other);
97 return *this;
98 }
99
106 template <typename U>
107 constexpr SharedPtr& operator=(const SharedPtr<U>& other) noexcept;
108
115 template <typename U>
116 SharedPtr& operator=(SharedPtr<U>&& other) noexcept;
117
122 SharedPtr& operator=(std::nullptr_t) noexcept;
123
127 size_t size() const {
128 static_assert(std::is_array_v<T>,
129 "size() cannot be called on non-array types");
130 return control_block_ == nullptr ? 0 : control_block_->size();
131 }
132
135 size_t use_count() const {
136 return control_block_ == nullptr ? 0 : control_block_->num_shared();
137 }
138
144 void reset() noexcept;
145
147 void swap(SharedPtr& other) noexcept;
148
151 template <typename PtrType>
152 bool owner_before(const PtrType& other) const noexcept {
153 return control_block_ < other.control_block();
154 }
155
156 private:
157 // Allow construction with to the implementation of `MakeShared`.
158 friend class Allocator;
159
160 // Allow SharedPtr<T> to access SharedPtr<U> and vice versa.
161 template <typename>
162 friend class SharedPtr;
163
164 // Allow WeakPtr<T> to promote to a SharedPtr<T>.
165 template <typename>
166 friend class WeakPtr;
167
175 SharedPtr(element_type* value, ControlBlock* control_block)
176 : Base(value), control_block_(control_block) {}
177
178 ControlBlock* control_block() const { return control_block_; }
179
181 template <typename U>
182 void CopyFrom(const SharedPtr<U>& other);
183
186 void Release();
187
189 template <typename U>
190 constexpr void CheckArrayTypes();
191
192 ControlBlock* control_block_ = nullptr;
193};
194
195// Template method implementations.
196
197template <typename T>
198template <typename U>
199constexpr SharedPtr<T>& SharedPtr<T>::operator=(
200 const SharedPtr<U>& other) noexcept {
201 CheckArrayTypes<U>();
202 CopyFrom(other);
203 if (control_block_ != nullptr) {
204 control_block_->IncrementShared();
205 }
206 return *this;
207}
208
209template <typename T>
210template <typename U>
211SharedPtr<T>& SharedPtr<T>::operator=(SharedPtr<U>&& other) noexcept {
212 CheckArrayTypes<U>();
213 reset();
214 CopyFrom(other);
215 other.Release();
216 return *this;
217}
218
219template <typename T>
220SharedPtr<T>& SharedPtr<T>::operator=(std::nullptr_t) noexcept {
221 reset();
222 return *this;
223}
224
225template <typename T>
226void SharedPtr<T>::reset() noexcept {
227 if (*this == nullptr) {
228 return;
229 }
230 auto action = control_block_->DecrementShared();
231 if (action == ControlBlock::Action::kNone) {
232 // Other `SharedPtr`s associated with this control block remain.
233 Release();
234 return;
235 }
236
237 // This was the last `SharedPtr` associated with this control block.
238 Allocator* allocator = control_block_->allocator();
239 if (!Base::HasCapability(allocator, allocator::kSkipsDestroy)) {
240 if constexpr (std::is_array_v<T>) {
241 Base::Destroy(control_block_->size());
242 } else {
243 Base::Destroy();
244 }
245 }
246
247 if (action == ControlBlock::Action::kExpire) {
248 // Keep the control block. Trying to promote any of the remaining
249 // `WeakPtr`s will fail.
250 Base::Resize(allocator, control_block_, sizeof(ControlBlock));
251 } else {
252 // No `WeakPtr`s remain, and all of the memory can be freed.
253 Base::Deallocate(allocator, control_block_);
254 }
255
256 Release();
257}
258
259template <typename T>
260void SharedPtr<T>::swap(SharedPtr<T>& other) noexcept {
261 Base::Swap(other);
262 std::swap(control_block_, other.control_block_);
263}
264
265template <typename T>
266template <typename U>
267void SharedPtr<T>::CopyFrom(const SharedPtr<U>& other) {
268 CheckArrayTypes<U>();
269 Base::CopyFrom(other);
270 control_block_ = other.control_block_;
271}
272
273template <typename T>
274void SharedPtr<T>::Release() {
275 Base::Release();
276 control_block_ = nullptr;
277}
278
279template <typename T>
280template <typename U>
281constexpr void SharedPtr<T>::CheckArrayTypes() {
282 if constexpr (std::is_array_v<T>) {
283 static_assert(std::is_array_v<U>,
284 "non-array type used with SharedPtr<T[]>");
285 } else {
286 static_assert(!std::is_array_v<U>, "array type used with SharedPtr<T>");
287 }
288}
289
290} // namespace pw
Definition: allocator.h:34
Definition: shared_ptr.h:44
SharedPtr(SharedPtr< U > &&other) noexcept
Definition: shared_ptr.h:88
SharedPtr & operator=(SharedPtr< U > &&other) noexcept
bool owner_before(const PtrType &other) const noexcept
Definition: shared_ptr.h:152
size_t size() const
Definition: shared_ptr.h:127
void swap(SharedPtr &other) noexcept
Swaps the managed pointer and deallocator of this and another object.
Definition: shared_ptr.h:260
size_t use_count() const
Definition: shared_ptr.h:135
~SharedPtr()
Releases any currently-held value.
Definition: shared_ptr.h:54
constexpr SharedPtr & operator=(const SharedPtr< U > &other) noexcept
constexpr SharedPtr() noexcept=default
constexpr SharedPtr(const SharedPtr &other) noexcept
Copy-constructs a SharedPtr<T> from a SharedPtr<T>.
Definition: shared_ptr.h:69
constexpr SharedPtr & operator=(const SharedPtr &other) noexcept
Definition: shared_ptr.h:95
constexpr SharedPtr(const SharedPtr< U > &other) noexcept
Definition: shared_ptr.h:78
void reset() noexcept
Definition: shared_ptr.h:226
Definition: weak_ptr.h:30
Provides basic helpers for reading and writing UTF-8 encoded strings.
Definition: alignment.h:27