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 UniquePtr(UniquePtr<U>&& other) noexcept {
106 *this = std::move(other);
107 }
108
111
118 template <typename U>
119 UniquePtr& operator=(UniquePtr<U>&& other) noexcept;
120
125 UniquePtr& operator=(std::nullptr_t) noexcept;
126
130 size_t size() const {
131 static_assert(std::is_array_v<T>,
132 "size() cannot be called with a non-array type");
133 return size_;
134 }
135
137 Deallocator* deallocator() const { return deallocator_; }
138
143 element_type* Release() noexcept;
144
149 void Reset() noexcept;
150
152 void Swap(UniquePtr& other);
153
154 private:
155 // Allow construction with to the implementation of `MakeUnique`.
156 friend class Deallocator;
157
158 // Allow UniquePtr<T> to access UniquePtr<U> and vice versa.
159 template <typename>
160 friend class UniquePtr;
161
163 template <typename U>
164 void CopyFrom(const UniquePtr<U>& other);
165
170 std::conditional_t<std::is_array_v<T>, size_t, Empty> size_;
171
174 Deallocator* deallocator_ = nullptr;
175};
176
177namespace allocator {
178
179// Alias for module consumers using the older name for the above type.
180template <typename T>
181using UniquePtr = PW_ALLOCATOR_DEPRECATED ::pw::UniquePtr<T>;
182
183} // namespace allocator
184
186
187// Template method implementations.
188
189template <typename T>
190template <typename U>
192 Reset();
193 CopyFrom(other);
194 other.Release();
195 return *this;
196}
197
198template <typename T>
199UniquePtr<T>& UniquePtr<T>::operator=(std::nullptr_t) noexcept {
200 Reset();
201 return *this;
202}
203
204template <typename T>
205typename UniquePtr<T>::element_type* UniquePtr<T>::Release() noexcept {
206 element_type* value = Base::Release();
207 deallocator_ = nullptr;
208 return value;
209}
210
211template <typename T>
212void UniquePtr<T>::Reset() noexcept {
213 if (*this == nullptr) {
214 return;
215 }
216 if (!Base::HasCapability(deallocator_, allocator::kSkipsDestroy)) {
217 if constexpr (std::is_array_v<T>) {
218 Base::Destroy(size_);
219 size_ = 0;
220 } else {
221 Base::Destroy();
222 }
223 }
224 Deallocator* deallocator = deallocator_;
225 auto* ptr = const_cast<std::remove_const_t<element_type>*>(Release());
226 Base::Deallocate(deallocator, ptr);
227}
228
229template <typename T>
231 Base::Swap(other);
232 if constexpr (std::is_array_v<T>) {
233 std::swap(size_, other.size_);
234 }
235 std::swap(deallocator_, other.deallocator_);
236}
237
238template <typename T>
239template <typename U>
240void UniquePtr<T>::CopyFrom(const UniquePtr<U>& other) {
241 static_assert(std::is_array_v<T> == std::is_array_v<U>);
242 Base::CopyFrom(other);
243 if constexpr (std::is_array_v<T>) {
244 size_ = other.size_;
245 }
246 deallocator_ = other.deallocator_;
247}
248
249} // namespace pw
Abstract interface for releasing memory.
Definition: deallocator.h:29
Definition: unique_ptr.h:43
UniquePtr(UniquePtr< U > &&other) noexcept
Definition: unique_ptr.h:105
element_type * Release() noexcept
Definition: unique_ptr.h:205
Deallocator * deallocator() const
Returns a pointer to the object that can destroy the value.
Definition: unique_ptr.h:137
void Reset() noexcept
Definition: unique_ptr.h:212
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:130
UniquePtr & operator=(UniquePtr< U > &&other) noexcept
~UniquePtr()
Frees any currently-held value.
Definition: unique_ptr.h:110
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:230
#define PW_NO_UNIQUE_ADDRESS
Definition: compiler.h:297
The Pigweed namespace.
Definition: alignment.h:27