C/C++ API Reference
Loading...
Searching...
No Matches
weak_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 "pw_allocator/config.h"
17
18// TODO(b/402489948): Remove when portable atomics are provided by `pw_atomic`.
19#if PW_ALLOCATOR_HAS_ATOMICS
20
21#include <cstddef>
22#include <utility>
23
24#include "pw_allocator/internal/control_block.h"
25#include "pw_allocator/internal/managed_ptr.h"
26#include "pw_allocator/shared_ptr.h"
27
28namespace pw {
29
31
36template <typename T>
37class WeakPtr final : public ::pw::allocator::internal::WeakManagedPtr<T> {
38 private:
39 using Base = ::pw::allocator::internal::WeakManagedPtr<T>;
40 using ControlBlock = ::pw::allocator::internal::ControlBlock;
41
42 public:
43 using element_type = typename Base::element_type;
44
46 constexpr WeakPtr() noexcept = default;
47
49 constexpr WeakPtr(std::nullptr_t) noexcept : WeakPtr() {}
50
52 WeakPtr(const WeakPtr& other) noexcept { *this = other; }
53
58 template <typename U,
59 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
60 WeakPtr(const WeakPtr<U>& other) noexcept {
61 *this = other;
62 }
63
68 template <typename U,
69 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
70 WeakPtr(const SharedPtr<U>& other) noexcept {
71 *this = other;
72 }
73
79 template <typename U,
80 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
81 WeakPtr(WeakPtr<U>&& other) noexcept {
82 *this = other;
83 }
84
85 ~WeakPtr() { reset(); }
86
88 constexpr WeakPtr& operator=(const WeakPtr& other) noexcept {
89 operator= <T>(other);
90 return *this;
91 }
92
97 template <typename U,
98 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
99 WeakPtr& operator=(const WeakPtr<U>& other) noexcept;
100
105 template <typename U,
106 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
107 WeakPtr& operator=(const SharedPtr<U>& other) noexcept;
108
113 template <typename U,
114 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
115 WeakPtr& operator=(WeakPtr<U>&& other) noexcept;
116
128 template <typename U,
129 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
130 constexpr explicit operator const WeakPtr<U>&() const {
131 return static_cast<const WeakPtr<U>&>(
132 static_cast<const allocator::internal::BaseManagedPtr&>(*this));
133 }
134
139 void reset() noexcept;
140
142 void swap(WeakPtr& other) noexcept {
143 std::swap(control_block_, other.control_block_);
144 }
145
148 int32_t use_count() const noexcept {
149 return control_block_ == nullptr ? 0 : control_block_->num_shared();
150 }
151
154 bool expired() const noexcept { return use_count() == 0; }
155
158 SharedPtr<T> Lock() const noexcept;
159
162 template <typename PtrType>
163 bool owner_before(const PtrType& other) const noexcept {
164 return control_block_ < other.control_block();
165 }
166
167 private:
168 // Allow WeakPtr<T> to access WeakPtr<U> and vice versa.
169 template <typename>
170 friend class WeakPtr;
171
172 ControlBlock* control_block() const { return control_block_; }
173
174 ControlBlock* control_block_ = nullptr;
175};
176
177// Template implementations.
178
179template <typename T>
180template <typename U, typename>
181WeakPtr<T>& WeakPtr<T>::operator=(const WeakPtr<U>& other) noexcept {
182 Base::template CheckAssignable<U>();
183 control_block_ = other.control_block_;
184 if (control_block_ != nullptr) {
185 control_block_->IncrementWeak();
186 }
187 return *this;
188}
189
190template <typename T>
191template <typename U, typename>
192WeakPtr<T>& WeakPtr<T>::operator=(const SharedPtr<U>& other) noexcept {
193 Base::template CheckAssignable<U>();
194 control_block_ = other.control_block_;
195 if (control_block_ != nullptr) {
196 control_block_->IncrementWeak();
197 }
198 return *this;
199}
200
201template <typename T>
202template <typename U, typename>
203WeakPtr<T>& WeakPtr<T>::operator=(WeakPtr<U>&& other) noexcept {
204 Base::template CheckAssignable<U>();
205 control_block_ = other.control_block_;
206 other.control_block_ = nullptr;
207 return *this;
208}
209
210template <typename T>
211void WeakPtr<T>::reset() noexcept {
212 if (control_block_ == nullptr ||
213 control_block_->DecrementWeak() != ControlBlock::Action::kFree) {
214 return;
215 }
216 Allocator* allocator = control_block_->allocator();
217 Base::Deallocate(allocator, control_block_);
218 control_block_ = nullptr;
219}
220
221template <typename T>
223 if (control_block_ == nullptr || !control_block_->IncrementShared()) {
224 return SharedPtr<T>();
225 }
226 void* data = control_block_->data();
227 auto* t = std::launder(reinterpret_cast<element_type*>(data));
228 return SharedPtr<T>(t, control_block_);
229}
230
232
233} // namespace pw
234
235// TODO(b/402489948): Remove when portable atomics are provided by `pw_atomic`.
236#endif // PW_ALLOCATOR_HAS_ATOMICS
Definition: allocator.h:36
Definition: shared_ptr.h:60
Definition: weak_ptr.h:37
WeakPtr(const SharedPtr< U > &other) noexcept
Definition: weak_ptr.h:70
WeakPtr(WeakPtr< U > &&other) noexcept
Definition: weak_ptr.h:81
WeakPtr(const WeakPtr< U > &other) noexcept
Definition: weak_ptr.h:60
WeakPtr(const WeakPtr &other) noexcept
Copy-constructs a WeakPtr<T> from a WeakPtr<T>.
Definition: weak_ptr.h:52
WeakPtr & operator=(const SharedPtr< U > &other) noexcept
int32_t use_count() const noexcept
Definition: weak_ptr.h:148
constexpr WeakPtr & operator=(const WeakPtr &other) noexcept
Copy-assigns a WeakPtr<T> from a WeakPtr<T>.
Definition: weak_ptr.h:88
constexpr WeakPtr() noexcept=default
Creates an empty (nullptr) instance.
WeakPtr & operator=(const WeakPtr< U > &other) noexcept
bool expired() const noexcept
Definition: weak_ptr.h:154
WeakPtr & operator=(WeakPtr< U > &&other) noexcept
void swap(WeakPtr &other) noexcept
Swaps the managed pointer and deallocator of this and another object.
Definition: weak_ptr.h:142
bool owner_before(const PtrType &other) const noexcept
Definition: weak_ptr.h:163
void reset() noexcept
Definition: weak_ptr.h:211
SharedPtr< T > Lock() const noexcept
Definition: weak_ptr.h:222
The Pigweed namespace.
Definition: alignment.h:27