1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://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,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef API_BASE_CONTAINERS_UNIQUE_PTR_H
17 #define API_BASE_CONTAINERS_UNIQUE_PTR_H
18
19 #include <cstddef>
20
21 #include <base/containers/type_traits.h>
22 #include <base/namespace.h>
23
24 BASE_BEGIN_NAMESPACE()
25 template<class T>
26 struct default_delete {
27 constexpr default_delete() noexcept = default;
28
29 template<class U>
30 default_delete(const default_delete<U>& d) noexcept
31 {}
32
operator ()default_delete33 void operator()(T* ptr) const
34 {
35 static_assert(sizeof(T), "can't delete an incomplete type");
36 delete ptr;
37 }
38
39 template<class U>
operator ()default_delete40 void operator()(U* ptr) const
41 {
42 static_assert(sizeof(U), "can't delete an incomplete type");
43 delete ptr;
44 }
45 };
46
47 template<class T>
48 struct default_delete<T[]> {
49 constexpr default_delete() noexcept = default;
50
51 template<class U>
52 default_delete(const default_delete<U[]>& d) noexcept
53 {}
54
operator ()default_delete55 void operator()(T* ptr) const
56 {
57 static_assert(sizeof(T), "can't delete an incomplete type");
58 delete[] ptr;
59 }
60
61 template<class U>
operator ()default_delete62 void operator()(U* ptr) const
63 {
64 static_assert(sizeof(U), "can't delete an incomplete type");
65 delete[] ptr;
66 }
67 };
68
69 template<class T, class D = default_delete<T>>
70 class unique_ptr {
71 public:
72 using pointer = BASE_NS::remove_reference_t<T>*;
73 using element_type = T;
74 using deleter_type = D;
75
76 constexpr unique_ptr() noexcept {};
77
78 constexpr unique_ptr(nullptr_t) noexcept {}
79
ptr_(p)80 explicit unique_ptr(pointer p) noexcept : ptr_(p) {}
81
82 // D is non-reference
83 template<class dt = D, enable_if_t<!is_reference_v<dt>, int> = 0>
forward(deleter)84 unique_ptr(pointer p, const D& deleter) noexcept : ptr_(p), deleter_(BASE_NS::forward<decltype(deleter)>(deleter))
85 {}
86 template<class dt = D, enable_if_t<!is_reference_v<dt>, int> = 0>
87 unique_ptr(pointer p, BASE_NS::remove_reference_t<D>&& deleter) noexcept
forward(deleter)88 : ptr_(p), deleter_(BASE_NS::forward<decltype(deleter)>(deleter))
89 {}
90
91 // D is lvalue-reference "A&"
92 template<class d = D, class dt = BASE_NS::remove_reference_t<D>,
93 BASE_NS::enable_if_t<(BASE_NS::is_lvalue_reference_v<d> && !BASE_NS::is_const_v<dt>), int> = 0>
forward(deleter)94 unique_ptr(pointer p, D& deleter) noexcept : ptr_(p), deleter_(BASE_NS::forward<decltype(deleter)>(deleter))
95 {}
96 template<class d = D, class dt = BASE_NS::remove_reference_t<D>,
97 BASE_NS::enable_if_t<(BASE_NS::is_lvalue_reference_v<d> && !BASE_NS::is_const_v<dt>), int> = 0>
98 unique_ptr(pointer p, BASE_NS::remove_reference_t<D>&& deleter) = delete;
99
100 // D is lvalue-reference "const A&"
101 template<class d = D, class dt = BASE_NS::remove_reference_t<D>,
102 BASE_NS::enable_if_t<(BASE_NS::is_lvalue_reference_v<d> && BASE_NS::is_const_v<dt>), int> = 0>
forward(deleter)103 unique_ptr(pointer p, const D& deleter) noexcept : ptr_(p), deleter_(BASE_NS::forward<decltype(deleter)>(deleter))
104 {}
105 template<class d = D, class dt = BASE_NS::remove_reference_t<D>,
106 BASE_NS::enable_if_t<(BASE_NS::is_lvalue_reference_v<d> && BASE_NS::is_const_v<dt>), int> = 0>
107 unique_ptr(pointer p, const BASE_NS::remove_reference_t<D>&& deleter) = delete;
108
109 // if E is a reference type, this deleter is copy constructed from u's deleter
110 template<class U, class E, enable_if_t<!is_array_v<U> && is_reference_v<E>, int> = 0>
deleter_(u.get_deleter())111 unique_ptr(unique_ptr<U, E>&& u) noexcept : ptr_(u.release()), deleter_(u.get_deleter())
112 {}
113
114 // if E is a non-reference type, this D is move constructed from u's D
115 template<class U, class E, enable_if_t<!is_array_v<U> && !is_reference_v<E>, int> = 0>
move(u.get_deleter())116 unique_ptr(unique_ptr<U, E>&& u) noexcept : ptr_(u.release()), deleter_(BASE_NS::move(u.get_deleter()))
117 {}
118
~unique_ptr()119 ~unique_ptr()
120 {
121 if (ptr_) {
122 deleter_(ptr_);
123 }
124 }
125
126 deleter_type& get_deleter() noexcept
127 {
128 return deleter_;
129 }
130 const deleter_type& get_deleter() const noexcept
131 {
132 return deleter_;
133 }
134
135 pointer get() const noexcept
136 {
137 return ptr_;
138 }
139
140 pointer release() noexcept
141 {
142 pointer res = ptr_;
143 ptr_ = nullptr;
144 return res;
145 }
146
147 void reset(pointer ptr = pointer()) noexcept
148 {
149 pointer old_ptr = ptr_;
150 ptr_ = ptr;
151 if (old_ptr) {
152 deleter_(old_ptr);
153 }
154 }
155
156 unique_ptr& operator=(nullptr_t) noexcept
157 {
158 reset();
159 return *this;
160 }
161
162 unique_ptr& operator=(unique_ptr&& r) noexcept
163 {
164 reset(r.release());
165 deleter_ = r.get_deleter();
166 return *this;
167 }
168
169 template<class U, class E>
170 unique_ptr& operator=(unique_ptr<U, E>&& r) noexcept
171 {
172 reset(r.release());
173 deleter_ = r.get_deleter();
174 return *this;
175 }
176
177 void swap(unique_ptr& other) noexcept
178 {
179 pointer tmp = ptr_;
180 ptr_ = other.ptr_;
181 other.ptr_ = tmp;
182 auto tmp2 = deleter_;
183 deleter_ = other.deleter_;
184 other.deleter_ = tmp2;
185 }
186
187 explicit operator bool() const noexcept
188 {
189 return (ptr_ != nullptr);
190 }
191
192 pointer operator->() const noexcept
193 {
194 return ptr_;
195 }
196
operator *() const197 typename BASE_NS::add_lvalue_reference<T>::type operator*() const
198 {
199 return *ptr_;
200 }
201
202 unique_ptr(const unique_ptr&) = delete;
203 unique_ptr& operator=(const unique_ptr&) = delete;
204
205 protected:
206 pointer ptr_ { nullptr };
207 D deleter_;
208 };
209
210 template<class T, class D>
211 class unique_ptr<T[], D> {
212 public:
213 using pointer = BASE_NS::remove_reference_t<T>*;
214 using element_type = T;
215 using deleter_type = D;
216
217 constexpr unique_ptr() noexcept {}
218
219 constexpr unique_ptr(nullptr_t) noexcept {}
220
ptr_(p)221 explicit unique_ptr(pointer p) noexcept : ptr_(p) {}
222
223 template<class U>
ptr_(p)224 explicit unique_ptr(U p) noexcept : ptr_(p)
225 {}
226
227 // D is non-reference
228 template<class dt = D, enable_if_t<!is_reference_v<dt>, int> = 0>
forward(d)229 unique_ptr(pointer p, const D& d) noexcept : ptr_(p), deleter_(BASE_NS::forward<decltype(d)>(d))
230 {}
231 template<class dt = D, enable_if_t<!is_reference_v<dt>, int> = 0>
232 unique_ptr(pointer p, BASE_NS::remove_reference_t<D>&& d) noexcept
forward(d)233 : ptr_(p), deleter_(BASE_NS::forward<decltype(d)>(d))
234 {}
235
236 // D is lvalue-reference "A&"
237 template<class d = D, class dt = BASE_NS::remove_reference_t<D>,
238 BASE_NS::enable_if_t<(BASE_NS::is_lvalue_reference_v<d> && !BASE_NS::is_const_v<dt>), int> = 0>
forward(deleter)239 unique_ptr(pointer p, D& deleter) noexcept : ptr_(p), deleter_(BASE_NS::forward<decltype(deleter)>(deleter))
240 {}
241 template<class d = D, class dt = BASE_NS::remove_reference_t<D>,
242 BASE_NS::enable_if_t<(BASE_NS::is_lvalue_reference_v<d> && !BASE_NS::is_const_v<dt>), int> = 0>
243 unique_ptr(pointer p, BASE_NS::remove_reference_t<D>&& deleter) = delete;
244
245 // D is lvalue-reference "const A&"
246 template<class d = D, class dt = BASE_NS::remove_reference_t<D>,
247 BASE_NS::enable_if_t<(BASE_NS::is_lvalue_reference_v<d> && BASE_NS::is_const_v<dt>), int> = 0>
forward(deleter)248 unique_ptr(pointer p, const D& deleter) noexcept : ptr_(p), deleter_(BASE_NS::forward<decltype(deleter)>(deleter))
249 {}
250 template<class d = D, class dt = BASE_NS::remove_reference_t<D>,
251 BASE_NS::enable_if_t<(BASE_NS::is_lvalue_reference_v<d> && BASE_NS::is_const_v<dt>), int> = 0>
252 unique_ptr(pointer p, const BASE_NS::remove_reference_t<D>&& deleter) = delete;
253
254 // if E is a reference type, this deleter is copy constructed from u's deleter
255 template<class U, class E, enable_if_t<is_array_v<U> && is_reference_v<E>, int> = 0>
deleter_(u.get_deleter())256 unique_ptr(unique_ptr<U, E>&& u) noexcept : ptr_(u.release()), deleter_(u.get_deleter())
257 {}
258
259 // if E is a non-reference type, this D is move constructed from u's D
260 template<class U, class E, enable_if_t<is_array_v<U> && !is_reference_v<E>, int> = 0>
move(u.get_deleter())261 unique_ptr(unique_ptr<U, E>&& u) noexcept : ptr_(u.release()), deleter_(BASE_NS::move(u.get_deleter()))
262 {}
263
~unique_ptr()264 ~unique_ptr()
265 {
266 if (ptr_) {
267 deleter_(ptr_);
268 }
269 }
270
271 deleter_type& get_deleter() noexcept
272 {
273 return deleter_;
274 }
275
276 const deleter_type& get_deleter() const noexcept
277 {
278 return deleter_;
279 }
280
281 pointer get() const noexcept
282 {
283 return ptr_;
284 }
285
286 pointer release() noexcept
287 {
288 pointer res = ptr_;
289 ptr_ = nullptr;
290 return res;
291 }
292
293 template<class U>
294 void reset(U ptr) noexcept
295 {
296 pointer old_ptr = ptr_;
297 ptr_ = ptr;
298 if (old_ptr) {
299 deleter_(old_ptr);
300 }
301 }
302
303 void reset(nullptr_t p = nullptr) noexcept
304 {
305 reset(pointer());
306 }
307
308 unique_ptr& operator=(nullptr_t) noexcept
309 {
310 reset();
311 return *this;
312 }
313
314 unique_ptr& operator=(unique_ptr&& r) noexcept
315 {
316 reset(r.release());
317 deleter_ = r.get_deleter();
318 return *this;
319 }
320
321 template<class U, class E>
322
323 unique_ptr& operator=(unique_ptr<U, E>&& r) noexcept
324 {
325 reset(r.release());
326 deleter_ = r.get_deleter();
327 return *this;
328 }
329
330 void swap(unique_ptr& other) noexcept
331 {
332 pointer tmp = ptr_;
333 ptr_ = other.ptr_;
334 other.ptr_ = tmp;
335 auto tmp2 = deleter_;
336 deleter_ = other.deleter_;
337 other.deleter_ = tmp2;
338 }
339
340 explicit operator bool() const noexcept
341 {
342 return (ptr_ != nullptr);
343 }
344
operator [](size_t i) const345 T& operator[](size_t i) const
346 {
347 return ptr_[i];
348 }
349
350 unique_ptr(const unique_ptr&) = delete;
351
352 unique_ptr& operator=(const unique_ptr&) = delete;
353
354 protected:
355 pointer ptr_ { nullptr };
356 D deleter_;
357 };
358
359 // equality comparisons
360 template<class T1, class D1, class T2, class D2>
operator ==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)361 bool operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
362 {
363 return x.get() == y.get();
364 }
365 template<class T1, class D1>
operator ==(const unique_ptr<T1, D1>& x, nullptr_t)366 bool operator==(const unique_ptr<T1, D1>& x, nullptr_t)
367 {
368 return x.get() == nullptr;
369 }
370 template<class T1, class D1>
operator ==(nullptr_t, const unique_ptr<T1, D1>& x)371 bool operator==(nullptr_t, const unique_ptr<T1, D1>& x)
372 {
373 return x.get() == nullptr;
374 }
375
376 // in-equality comparisons
377 template<class T1, class D1, class T2, class D2>
operator !=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)378 bool operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
379 {
380 return x.get() != y.get();
381 }
382 template<class T1, class D1>
operator !=(const unique_ptr<T1, D1>& x, nullptr_t)383 bool operator!=(const unique_ptr<T1, D1>& x, nullptr_t)
384 {
385 return x.get() != nullptr;
386 }
387 template<class T1, class D1>
operator !=(nullptr_t, const unique_ptr<T1, D1>& x)388 bool operator!=(nullptr_t, const unique_ptr<T1, D1>& x)
389 {
390 return x.get() != nullptr;
391 }
392
393 // non-array types
394 template<class T, class... Args, BASE_NS::enable_if_t<!BASE_NS::is_array_v<T>, int> = 0>
make_unique(Args&&.... args)395 unique_ptr<T> make_unique(Args&&... args)
396 {
397 return unique_ptr<T>(new T(BASE_NS::forward<Args>(args)...));
398 }
399
400 // arrays with unknown bound
401 template<class T, BASE_NS::enable_if_t<BASE_NS::is_array_v<T> && BASE_NS::extent_v<T> == 0, int> = 0>
make_unique(size_t size)402 unique_ptr<T> make_unique(size_t size)
403 {
404 return unique_ptr<T>(new typename BASE_NS::remove_extent_t<T>[size]());
405 }
406
407 // arrays with known bound. (not-allowed)
408 template<class T, class... Args, BASE_NS::enable_if_t<BASE_NS::is_array_v<T> && BASE_NS::extent_v<T> != 0, int> = 0>
409 void make_unique(Args&&... args) = delete;
410 BASE_END_NAMESPACE()
411
412 #endif // API_BASE_CONTAINERS_UNIQUE_PTR_H