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/deallocator.h"
22#include "pw_allocator/internal/managed_ptr.h"
23#include "pw_allocator/layout.h"
24#include "pw_preprocessor/compiler.h"
25
26namespace pw {
27
29
43template <typename T>
44class UniquePtr : public ::pw::allocator::internal::ManagedPtr<T> {
45 private:
46 using Base = ::pw::allocator::internal::ManagedPtr<T>;
47 using Empty = ::pw::allocator::internal::Empty;
48
49 public:
50 using pointer = typename Base::element_type*;
51 using element_type = typename Base::element_type;
52
57 constexpr UniquePtr() noexcept {
58 if constexpr (std::is_array_v<T>) {
59 size_ = 0;
60 }
61 }
62
63 // Not copyable.
64 UniquePtr(const UniquePtr&) = delete;
65 UniquePtr& operator=(const UniquePtr&) = delete;
66
71 constexpr UniquePtr(std::nullptr_t) noexcept : UniquePtr() {}
72
87 UniquePtr(element_type* value, Deallocator& deallocator)
88 : Base(value), deallocator_(&deallocator) {
89 static_assert(!allocator::internal::is_unbounded_array_v<T>,
90 "UniquePtr for unbounded array type must provide size");
91 if constexpr (allocator::internal::is_bounded_array_v<T>) {
92 size_ = std::extent_v<T>;
93 }
94 }
95
96 UniquePtr(element_type* value, size_t size, Deallocator& deallocator)
97 : Base(value), size_(size), deallocator_(&deallocator) {
98 static_assert(
99 allocator::internal::is_unbounded_array_v<T>,
100 "UniquePtr must not provide size unless type is an unbounded array");
101 }
103
109 template <typename U,
110 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
111 UniquePtr(UniquePtr<U>&& other) noexcept {
112 *this = std::move(other);
113 }
114
117
124 template <typename U,
125 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
126 UniquePtr& operator=(UniquePtr<U>&& other) noexcept;
127
132 UniquePtr& operator=(std::nullptr_t) noexcept;
133
145 template <typename U,
146 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
147 constexpr explicit operator UniquePtr<U>() && {
148 Deallocator& deallocator = *deallocator_;
149 return UniquePtr<U>(static_cast<U*>(Release()), deallocator);
150 }
151
152 [[nodiscard]] friend constexpr bool operator==(const UniquePtr& lhs,
153 std::nullptr_t) {
154 return lhs.Equals(nullptr);
155 }
156 [[nodiscard]] friend constexpr bool operator==(std::nullptr_t,
157 const UniquePtr& rhs) {
158 return rhs.Equals(nullptr);
159 }
160 [[nodiscard]] friend constexpr bool operator==(const UniquePtr& lhs,
161 const UniquePtr& rhs) {
162 return lhs.Equals(rhs) && lhs.control_block_ == rhs.control_block_;
163 }
164
165 [[nodiscard]] friend constexpr bool operator!=(const UniquePtr& lhs,
166 std::nullptr_t) {
167 return !lhs.Equals(nullptr);
168 }
169 [[nodiscard]] friend constexpr bool operator!=(std::nullptr_t,
170 const UniquePtr& rhs) {
171 return !rhs.Equals(nullptr);
172 }
173 [[nodiscard]] friend constexpr bool operator!=(const UniquePtr& lhs,
174 const UniquePtr& rhs) {
175 return !(lhs == rhs);
176 }
177
181 size_t size() const {
182 static_assert(std::is_array_v<T>,
183 "size() cannot be called with a non-array type");
184 return size_;
185 }
186
188 Deallocator* deallocator() const { return deallocator_; }
189
194 element_type* Release() noexcept;
195
200 void Reset() noexcept;
201
203 void Swap(UniquePtr& other);
204
205 private:
206 // Allow construction with to the implementation of `MakeUnique`.
207 friend class Deallocator;
208
209 // Allow UniquePtr<T> to access UniquePtr<U> and vice versa.
210 template <typename>
211 friend class UniquePtr;
212
214 template <typename U,
215 typename = std::enable_if_t<std::is_assignable_v<T*&, U*>>>
216 void CopyFrom(const UniquePtr<U>& other);
217
222 std::conditional_t<std::is_array_v<T>, size_t, Empty> size_;
223
226 Deallocator* deallocator_ = nullptr;
227};
228
230
231// Template method implementations.
232
233template <typename T>
234template <typename U, typename>
235UniquePtr<T>& UniquePtr<T>::operator=(UniquePtr<U>&& other) noexcept {
236 Reset();
237 CopyFrom(other);
238 other.Release();
239 return *this;
240}
241
242template <typename T>
243UniquePtr<T>& UniquePtr<T>::operator=(std::nullptr_t) noexcept {
244 Reset();
245 return *this;
246}
247
248template <typename T>
249typename UniquePtr<T>::element_type* UniquePtr<T>::Release() noexcept {
250 element_type* value = Base::Release();
251 deallocator_ = nullptr;
252 if constexpr (std::is_array_v<T>) {
253 size_ = 0;
254 }
255 return value;
256}
257
258template <typename T>
259void UniquePtr<T>::Reset() noexcept {
260 if (*this == nullptr) {
261 return;
262 }
263 if (!deallocator_->HasCapability(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());
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:28
Definition: unique_ptr.h:44
element_type * Release() noexcept
Definition: unique_ptr.h:249
Deallocator * deallocator() const
Returns a pointer to the object that can destroy the value.
Definition: unique_ptr.h:188
UniquePtr & operator=(UniquePtr< U > &&other) noexcept
void Reset() noexcept
Definition: unique_ptr.h:259
UniquePtr(element_type *value, Deallocator &deallocator)
Definition: unique_ptr.h:87
constexpr UniquePtr() noexcept
Definition: unique_ptr.h:57
size_t size() const
Definition: unique_ptr.h:181
~UniquePtr()
Frees any currently-held value.
Definition: unique_ptr.h:116
constexpr UniquePtr(std::nullptr_t) noexcept
Definition: unique_ptr.h:71
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:111
void Deallocate(void *ptr)
Definition: deallocator.h:59
constexpr bool HasCapability(Capability capability) const
Returns whether a given capability is enabled for this object.
Definition: deallocator.h:49
#define PW_NO_UNIQUE_ADDRESS
Definition: compiler.h:297
The Pigweed namespace.
Definition: alignment.h:27