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>
default_deletedefault_delete30     default_delete(const default_delete<U>& d) noexcept
31     {}
32 
operatordefault_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>
operatordefault_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 
55     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>
62     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 
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>
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
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>
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>
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>
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>
116     unique_ptr(unique_ptr<U, E>&& u) noexcept : ptr_(u.release()), deleter_(BASE_NS::move(u.get_deleter()))
117     {}
118 
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 
197     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 
221     explicit unique_ptr(pointer p) noexcept : ptr_(p) {}
222 
223     template<class U>
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>
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
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>
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>
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>
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>
261     unique_ptr(unique_ptr<U, E>&& u) noexcept : ptr_(u.release()), deleter_(BASE_NS::move(u.get_deleter()))
262     {}
263 
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 
345     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>
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>
366 bool operator==(const unique_ptr<T1, D1>& x, nullptr_t)
367 {
368     return x.get() == nullptr;
369 }
370 template<class T1, class D1>
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>
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>
383 bool operator!=(const unique_ptr<T1, D1>& x, nullptr_t)
384 {
385     return x.get() != nullptr;
386 }
387 template<class T1, class D1>
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>
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>
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