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
66 constexpr UniquePtr(std::nullptr_t) noexcept : UniquePtr() {}
67
82 UniquePtr(element_type* value, Deallocator& deallocator)
83 : Base(value), deallocator_(&deallocator) {
84 static_assert(!allocator::internal::is_unbounded_array_v<T>,
85 "UniquePtr for unbounded array type must provide size");
86 if constexpr (allocator::internal::is_bounded_array_v<T>) {
87 size_ = std::extent_v<T>;
88 }
89 }
90
91 UniquePtr(element_type* value, size_t size, Deallocator& deallocator)
92 : Base(value), size_(size), deallocator_(&deallocator) {
93 static_assert(
94 allocator::internal::is_unbounded_array_v<T>,
95 "UniquePtr must not provide size unless type is an unbounded array");
96 }
98
104 template <typename U,
105 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
106 UniquePtr(UniquePtr<U>&& other) noexcept {
107 *this = std::move(other);
108 }
109
112
119 template <typename U,
120 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
121 UniquePtr& operator=(UniquePtr<U>&& other) noexcept;
122
127 UniquePtr& operator=(std::nullptr_t) noexcept;
128
140 template <typename U,
141 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
142 constexpr explicit operator UniquePtr<U>() && {
143 Deallocator& deallocator = *deallocator_;
144 return UniquePtr<U>(static_cast<U*>(Release()), deallocator);
145 }
146
147 [[nodiscard]] friend constexpr bool operator==(const UniquePtr& lhs,
148 std::nullptr_t) {
149 return lhs.Equals(nullptr);
150 }
151 [[nodiscard]] friend constexpr bool operator==(std::nullptr_t,
152 const UniquePtr& rhs) {
153 return rhs.Equals(nullptr);
154 }
155 [[nodiscard]] friend constexpr bool operator==(const UniquePtr& lhs,
156 const UniquePtr& rhs) {
157 return lhs.Equals(rhs) && lhs.control_block_ == rhs.control_block_;
158 }
159
160 [[nodiscard]] friend constexpr bool operator!=(const UniquePtr& lhs,
161 std::nullptr_t) {
162 return !lhs.Equals(nullptr);
163 }
164 [[nodiscard]] friend constexpr bool operator!=(std::nullptr_t,
165 const UniquePtr& rhs) {
166 return !rhs.Equals(nullptr);
167 }
168 [[nodiscard]] friend constexpr bool operator!=(const UniquePtr& lhs,
169 const UniquePtr& rhs) {
170 return !(lhs == rhs);
171 }
172
176 size_t size() const {
177 static_assert(std::is_array_v<T>,
178 "size() cannot be called with a non-array type");
179 return size_;
180 }
181
183 Deallocator* deallocator() const { return deallocator_; }
184
189 element_type* Release() noexcept;
190
195 void Reset() noexcept;
196
198 void Swap(UniquePtr& other);
199
200 private:
201 // Allow construction with to the implementation of `MakeUnique`.
202 friend class Deallocator;
203
204 // Allow UniquePtr<T> to access UniquePtr<U> and vice versa.
205 template <typename>
206 friend class UniquePtr;
207
209 template <typename U,
210 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
211 void CopyFrom(const UniquePtr<U>& other);
212
217 std::conditional_t<std::is_array_v<T>, size_t, Empty> size_;
218
221 Deallocator* deallocator_ = nullptr;
222};
223
224namespace allocator {
225
226// Alias for module consumers using the older name for the above type.
227template <typename T>
228using UniquePtr = PW_ALLOCATOR_DEPRECATED ::pw::UniquePtr<T>;
229
230} // namespace allocator
231
233
234// Template method implementations.
235
236template <typename T>
237template <typename U, typename>
239 Reset();
240 CopyFrom(other);
241 other.Release();
242 return *this;
243}
244
245template <typename T>
246UniquePtr<T>& UniquePtr<T>::operator=(std::nullptr_t) noexcept {
247 Reset();
248 return *this;
249}
250
251template <typename T>
252typename UniquePtr<T>::element_type* UniquePtr<T>::Release() noexcept {
253 element_type* value = Base::Release();
254 deallocator_ = nullptr;
255 return value;
256}
257
258template <typename T>
259void UniquePtr<T>::Reset() noexcept {
260 if (*this == nullptr) {
261 return;
262 }
263 if (!Base::HasCapability(deallocator_, allocator::kSkipsDestroy)) {
264 if constexpr (std::is_array_v<T>) {
265 Base::Destroy(size_);
266 size_ = 0;
267 } else {
268 Base::Destroy();
269 }
270 }
271 Deallocator* deallocator = deallocator_;
272 auto* ptr = const_cast<std::remove_const_t<element_type>*>(Release());
273 Base::Deallocate(deallocator, ptr);
274}
275
276template <typename T>
278 Base::Swap(other);
279 if constexpr (std::is_array_v<T>) {
280 std::swap(size_, other.size_);
281 }
282 std::swap(deallocator_, other.deallocator_);
283}
284
285template <typename T>
286template <typename U, typename>
287void UniquePtr<T>::CopyFrom(const UniquePtr<U>& other) {
288 static_assert(std::is_array_v<T> == std::is_array_v<U>);
289 Base::CopyFrom(other);
290 if constexpr (std::is_array_v<T>) {
291 size_ = other.size_;
292 }
293 deallocator_ = other.deallocator_;
294}
295
296} // namespace pw
Abstract interface for releasing memory.
Definition: deallocator.h:29
Definition: unique_ptr.h:43
element_type * Release() noexcept
Definition: unique_ptr.h:252
Deallocator * deallocator() const
Returns a pointer to the object that can destroy the value.
Definition: unique_ptr.h:183
UniquePtr & operator=(UniquePtr< U > &&other) noexcept
void Reset() noexcept
Definition: unique_ptr.h:259
UniquePtr(element_type *value, Deallocator &deallocator)
Definition: unique_ptr.h:82
constexpr UniquePtr() noexcept
Definition: unique_ptr.h:56
size_t size() const
Definition: unique_ptr.h:176
~UniquePtr()
Frees any currently-held value.
Definition: unique_ptr.h:111
constexpr UniquePtr(std::nullptr_t) noexcept
Definition: unique_ptr.h:66
void Swap(UniquePtr &other)
Swaps the managed pointer and deallocator of this and another object.
Definition: unique_ptr.h:277
UniquePtr(UniquePtr< U > &&other) noexcept
Definition: unique_ptr.h:106
#define PW_NO_UNIQUE_ADDRESS
Definition: compiler.h:297
The Pigweed namespace.
Definition: alignment.h:27