C/C++ API Reference
Loading...
Searching...
No Matches
unique_ptr.h
1// Copyright 2024 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 <type_traits>
18#include <utility>
19
20#include "pw_allocator/config.h"
21#include "pw_allocator/internal/managed_ptr.h"
22#include "pw_allocator/layout.h"
23#include "pw_preprocessor/compiler.h"
24
25namespace pw {
26
28
42template <typename T>
43class UniquePtr : public ::pw::allocator::internal::ManagedPtr<T> {
44 private:
45 using Base = ::pw::allocator::internal::ManagedPtr<T>;
46 using Empty = ::pw::allocator::internal::Empty;
47
48 public:
49 using pointer = typename Base::element_type*;
50 using element_type = typename Base::element_type;
51
56 constexpr UniquePtr() noexcept {
57 if constexpr (std::is_array_v<T>) {
58 size_ = 0;
59 }
60 }
61
62 // Not copyable.
63 UniquePtr(const UniquePtr&) = delete;
64 UniquePtr& operator=(const UniquePtr&) = delete;
65
70 constexpr UniquePtr(std::nullptr_t) noexcept : UniquePtr() {}
71
86 UniquePtr(element_type* value, Deallocator& deallocator)
87 : Base(value), deallocator_(&deallocator) {
88 static_assert(!allocator::internal::is_unbounded_array_v<T>,
89 "UniquePtr for unbounded array type must provide size");
90 if constexpr (allocator::internal::is_bounded_array_v<T>) {
91 size_ = std::extent_v<T>;
92 }
93 }
94
95 UniquePtr(element_type* value, size_t size, Deallocator& deallocator)
96 : Base(value), size_(size), deallocator_(&deallocator) {
97 static_assert(
98 allocator::internal::is_unbounded_array_v<T>,
99 "UniquePtr must not provide size unless type is an unbounded array");
100 }
102
108 template <typename U,
109 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
110 UniquePtr(UniquePtr<U>&& other) noexcept {
111 *this = std::move(other);
112 }
113
116
123 template <typename U,
124 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
125 UniquePtr& operator=(UniquePtr<U>&& other) noexcept;
126
131 UniquePtr& operator=(std::nullptr_t) noexcept;
132
144 template <typename U,
145 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
146 constexpr explicit operator UniquePtr<U>() && {
147 Deallocator& deallocator = *deallocator_;
148 return UniquePtr<U>(static_cast<U*>(Release()), deallocator);
149 }
150
151 [[nodiscard]] friend constexpr bool operator==(const UniquePtr& lhs,
152 std::nullptr_t) {
153 return lhs.Equals(nullptr);
154 }
155 [[nodiscard]] friend constexpr bool operator==(std::nullptr_t,
156 const UniquePtr& rhs) {
157 return rhs.Equals(nullptr);
158 }
159 [[nodiscard]] friend constexpr bool operator==(const UniquePtr& lhs,
160 const UniquePtr& rhs) {
161 return lhs.Equals(rhs) && lhs.control_block_ == rhs.control_block_;
162 }
163
164 [[nodiscard]] friend constexpr bool operator!=(const UniquePtr& lhs,
165 std::nullptr_t) {
166 return !lhs.Equals(nullptr);
167 }
168 [[nodiscard]] friend constexpr bool operator!=(std::nullptr_t,
169 const UniquePtr& rhs) {
170 return !rhs.Equals(nullptr);
171 }
172 [[nodiscard]] friend constexpr bool operator!=(const UniquePtr& lhs,
173 const UniquePtr& rhs) {
174 return !(lhs == rhs);
175 }
176
180 size_t size() const {
181 static_assert(std::is_array_v<T>,
182 "size() cannot be called with a non-array type");
183 return size_;
184 }
185
187 Deallocator* deallocator() const { return deallocator_; }
188
193 element_type* Release() noexcept;
194
199 void Reset() noexcept;
200
202 void Swap(UniquePtr& other);
203
204 private:
205 // Allow construction with to the implementation of `MakeUnique`.
206 friend class Deallocator;
207
208 // Allow UniquePtr<T> to access UniquePtr<U> and vice versa.
209 template <typename>
210 friend class UniquePtr;
211
213 template <typename U,
214 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
215 void CopyFrom(const UniquePtr<U>& other);
216
221 std::conditional_t<std::is_array_v<T>, size_t, Empty> size_;
222
225 Deallocator* deallocator_ = nullptr;
226};
227
228namespace allocator {
229
230// Alias for module consumers using the older name for the above type.
231template <typename T>
232using UniquePtr = PW_ALLOCATOR_DEPRECATED ::pw::UniquePtr<T>;
233
234} // namespace allocator
235
237
238// Template method implementations.
239
240template <typename T>
241template <typename U, typename>
243 Reset();
244 CopyFrom(other);
245 other.Release();
246 return *this;
247}
248
249template <typename T>
250UniquePtr<T>& UniquePtr<T>::operator=(std::nullptr_t) noexcept {
251 Reset();
252 return *this;
253}
254
255template <typename T>
256typename UniquePtr<T>::element_type* UniquePtr<T>::Release() noexcept {
257 element_type* value = Base::Release();
258 deallocator_ = nullptr;
259 if constexpr (std::is_array_v<T>) {
260 size_ = 0;
261 }
262 return value;
263}
264
265template <typename T>
266void UniquePtr<T>::Reset() noexcept {
267 if (*this == nullptr) {
268 return;
269 }
270 if (!Base::HasCapability(deallocator_, allocator::kSkipsDestroy)) {
271 if constexpr (std::is_array_v<T>) {
272 Base::Destroy(size_);
273 size_ = 0;
274 } else {
275 Base::Destroy();
276 }
277 }
278 Deallocator* deallocator = deallocator_;
279 auto* ptr = const_cast<std::remove_const_t<element_type>*>(Release());
280 Base::Deallocate(deallocator, ptr);
281}
282
283template <typename T>
285 Base::Swap(other);
286 if constexpr (std::is_array_v<T>) {
287 std::swap(size_, other.size_);
288 }
289 std::swap(deallocator_, other.deallocator_);
290}
291
292template <typename T>
293template <typename U, typename>
294void UniquePtr<T>::CopyFrom(const UniquePtr<U>& other) {
295 static_assert(std::is_array_v<T> == std::is_array_v<U>);
296 Base::CopyFrom(other);
297 if constexpr (std::is_array_v<T>) {
298 size_ = other.size_;
299 }
300 deallocator_ = other.deallocator_;
301}
302
303} // namespace pw
Abstract interface for releasing memory.
Definition: deallocator.h:29
Definition: unique_ptr.h:43
element_type * Release() noexcept
Definition: unique_ptr.h:256
Deallocator * deallocator() const
Returns a pointer to the object that can destroy the value.
Definition: unique_ptr.h:187
UniquePtr & operator=(UniquePtr< U > &&other) noexcept
void Reset() noexcept
Definition: unique_ptr.h:266
UniquePtr(element_type *value, Deallocator &deallocator)
Definition: unique_ptr.h:86
constexpr UniquePtr() noexcept
Definition: unique_ptr.h:56
size_t size() const
Definition: unique_ptr.h:180
~UniquePtr()
Frees any currently-held value.
Definition: unique_ptr.h:115
constexpr UniquePtr(std::nullptr_t) noexcept
Definition: unique_ptr.h:70
void Swap(UniquePtr &other)
Swaps the managed pointer and deallocator of this and another object.
Definition: unique_ptr.h:284
UniquePtr(UniquePtr< U > &&other) noexcept
Definition: unique_ptr.h:110
#define PW_NO_UNIQUE_ADDRESS
Definition: compiler.h:297
The Pigweed namespace.
Definition: alignment.h:27