• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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         delete ptr;
36     }
37 
38     template<class U>
operatordefault_delete39     void operator()(U* ptr) const
40     {
41         delete ptr;
42     }
43 };
44 
45 template<class T>
46 struct default_delete<T[]> {
47     constexpr default_delete() noexcept = default;
48 
49     template<class U>
50     default_delete(const default_delete<U[]>& d) noexcept
51     {}
52 
53     void operator()(T* ptr) const
54     {
55         delete[] ptr;
56     }
57 
58     template<class U>
59     void operator()(U* ptr) const
60     {
61         delete[] ptr;
62     }
63 };
64 
65 template<class T, class D = default_delete<T>>
66 class unique_ptr {
67 public:
68     using pointer = BASE_NS::remove_reference_t<T>*;
69     using element_type = T;
70     using deleter_type = D;
71 
72     constexpr unique_ptr() noexcept {};
73 
74     constexpr unique_ptr(nullptr_t) noexcept {}
75 
76     explicit unique_ptr(pointer p) noexcept : ptr_(p) {}
77 
78     // D is non-reference
79     template<class dt = D, enable_if_t<!is_reference_v<dt>, int> = 0>
80     unique_ptr(pointer p, const D& deleter) noexcept : ptr_(p), deleter_(BASE_NS::forward<decltype(deleter)>(deleter))
81     {}
82     template<class dt = D, enable_if_t<!is_reference_v<dt>, int> = 0>
83     unique_ptr(pointer p, BASE_NS::remove_reference_t<D>&& deleter) noexcept
84         : ptr_(p), deleter_(BASE_NS::forward<decltype(deleter)>(deleter))
85     {}
86 
87     // D is lvalue-reference "A&"
88     template<class d = D, class dt = BASE_NS::remove_reference_t<D>,
89         BASE_NS::enable_if_t<(BASE_NS::is_lvalue_reference_v<d> && !BASE_NS::is_const_v<dt>), int> = 0>
90     unique_ptr(pointer p, D& deleter) noexcept : ptr_(p), deleter_(BASE_NS::forward<decltype(deleter)>(deleter))
91     {}
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, BASE_NS::remove_reference_t<D>&& deleter) = delete;
95 
96     // D is lvalue-reference "const A&"
97     template<class d = D, class dt = BASE_NS::remove_reference_t<D>,
98         BASE_NS::enable_if_t<(BASE_NS::is_lvalue_reference_v<d> && BASE_NS::is_const_v<dt>), int> = 0>
99     unique_ptr(pointer p, const D& deleter) noexcept : ptr_(p), deleter_(BASE_NS::forward<decltype(deleter)>(deleter))
100     {}
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 BASE_NS::remove_reference_t<D>&& deleter) = delete;
104 
105     // if E is a reference type, this deleter is copy constructed from u's deleter
106     template<class U, class E, enable_if_t<!is_array_v<U> && is_reference_v<E>, int> = 0>
107     unique_ptr(unique_ptr<U, E>&& u) noexcept : ptr_(u.release()), deleter_(u.get_deleter())
108     {}
109 
110     // if E is a non-reference type, this D is move constructed from u's D
111     template<class U, class E, enable_if_t<!is_array_v<U> && !is_reference_v<E>, int> = 0>
112     unique_ptr(unique_ptr<U, E>&& u) noexcept : ptr_(u.release()), deleter_(BASE_NS::move(u.get_deleter()))
113     {}
114 
115     ~unique_ptr()
116     {
117         if (ptr_) {
118             deleter_(ptr_);
119         }
120     }
121 
122     deleter_type& get_deleter() noexcept
123     {
124         return deleter_;
125     }
126     const deleter_type& get_deleter() const noexcept
127     {
128         return deleter_;
129     }
130 
131     pointer get() const noexcept
132     {
133         return ptr_;
134     }
135 
136     pointer release() noexcept
137     {
138         pointer res = ptr_;
139         ptr_ = nullptr;
140         return res;
141     }
142 
143     void reset(pointer ptr = pointer()) noexcept
144     {
145         pointer old_ptr = ptr_;
146         ptr_ = ptr;
147         if (old_ptr) {
148             deleter_(old_ptr);
149         }
150     }
151 
152     unique_ptr& operator=(nullptr_t) noexcept
153     {
154         reset();
155         return *this;
156     }
157 
158     unique_ptr& operator=(unique_ptr&& r) noexcept
159     {
160         reset(r.release());
161         deleter_ = r.get_deleter();
162         return *this;
163     }
164 
165     template<class U, class E>
166     unique_ptr& operator=(unique_ptr<U, E>&& r) noexcept
167     {
168         reset(r.release());
169         deleter_ = r.get_deleter();
170         return *this;
171     }
172 
173     void swap(unique_ptr& other) noexcept
174     {
175         pointer tmp = ptr_;
176         ptr_ = other.ptr_;
177         other.ptr_ = tmp;
178         auto tmp2 = deleter_;
179         deleter_ = other.deleter_;
180         other.deleter_ = tmp2;
181     }
182 
183     explicit operator bool() const noexcept
184     {
185         return (ptr_ != nullptr);
186     }
187 
188     pointer operator->() const noexcept
189     {
190         return ptr_;
191     }
192 
193     typename BASE_NS::add_lvalue_reference<T>::type operator*() const
194     {
195         return *ptr_;
196     }
197 
198     unique_ptr(const unique_ptr&) = delete;
199     unique_ptr& operator=(const unique_ptr&) = delete;
200 
201 protected:
202     pointer ptr_ { nullptr };
203     D deleter_;
204 };
205 
206 template<class T, class D>
207 class unique_ptr<T[], D> {
208 public:
209     using pointer = BASE_NS::remove_reference_t<T>*;
210     using element_type = T;
211     using deleter_type = D;
212 
213     constexpr unique_ptr() noexcept {}
214 
215     constexpr unique_ptr(nullptr_t) noexcept {}
216 
217     explicit unique_ptr(pointer p) noexcept : ptr_(p) {}
218 
219     template<class U>
220     explicit unique_ptr(U p) noexcept : ptr_(p)
221     {}
222 
223     // D is non-reference
224     template<class dt = D, enable_if_t<!is_reference_v<dt>, int> = 0>
225     unique_ptr(pointer p, const D& d) noexcept : ptr_(p), deleter_(BASE_NS::forward<decltype(d)>(d))
226     {}
227     template<class dt = D, enable_if_t<!is_reference_v<dt>, int> = 0>
228     unique_ptr(pointer p, BASE_NS::remove_reference_t<D>&& d) noexcept
229         : ptr_(p), deleter_(BASE_NS::forward<decltype(d)>(d))
230     {}
231 
232     // D is lvalue-reference "A&"
233     template<class d = D, class dt = BASE_NS::remove_reference_t<D>,
234         BASE_NS::enable_if_t<(BASE_NS::is_lvalue_reference_v<d> && !BASE_NS::is_const_v<dt>), int> = 0>
235     unique_ptr(pointer p, D& deleter) noexcept : ptr_(p), deleter_(BASE_NS::forward<decltype(deleter)>(deleter))
236     {}
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, BASE_NS::remove_reference_t<D>&& deleter) = delete;
240 
241     // D is lvalue-reference "const A&"
242     template<class d = D, class dt = BASE_NS::remove_reference_t<D>,
243         BASE_NS::enable_if_t<(BASE_NS::is_lvalue_reference_v<d> && BASE_NS::is_const_v<dt>), int> = 0>
244     unique_ptr(pointer p, const D& deleter) noexcept : ptr_(p), deleter_(BASE_NS::forward<decltype(deleter)>(deleter))
245     {}
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 BASE_NS::remove_reference_t<D>&& deleter) = delete;
249 
250     // if E is a reference type, this deleter is copy constructed from u's deleter
251     template<class U, class E, enable_if_t<is_array_v<U> && is_reference_v<E>, int> = 0>
252     unique_ptr(unique_ptr<U, E>&& u) noexcept : ptr_(u.release()), deleter_(u.get_deleter())
253     {}
254 
255     // if E is a non-reference type, this D is move constructed from u's D
256     template<class U, class E, enable_if_t<is_array_v<U> && !is_reference_v<E>, int> = 0>
257     unique_ptr(unique_ptr<U, E>&& u) noexcept : ptr_(u.release()), deleter_(BASE_NS::move(u.get_deleter()))
258     {}
259 
260     ~unique_ptr()
261     {
262         if (ptr_) {
263             deleter_(ptr_);
264         }
265     }
266 
267     deleter_type& get_deleter() noexcept
268     {
269         return deleter_;
270     }
271 
272     const deleter_type& get_deleter() const noexcept
273     {
274         return deleter_;
275     }
276 
277     pointer get() const noexcept
278     {
279         return ptr_;
280     }
281 
282     pointer release() noexcept
283     {
284         pointer res = ptr_;
285         ptr_ = nullptr;
286         return res;
287     }
288 
289     template<class U>
290     void reset(U ptr) noexcept
291     {
292         pointer old_ptr = ptr_;
293         ptr_ = ptr;
294         if (old_ptr) {
295             deleter_(old_ptr);
296         }
297     }
298 
299     void reset(nullptr_t p = nullptr) noexcept
300     {
301         reset(pointer());
302     }
303 
304     unique_ptr& operator=(nullptr_t) noexcept
305     {
306         reset();
307         return *this;
308     }
309 
310     unique_ptr& operator=(unique_ptr&& r) noexcept
311     {
312         reset(r.release());
313         deleter_ = r.get_deleter();
314         return *this;
315     }
316 
317     template<class U, class E>
318 
319     unique_ptr& operator=(unique_ptr<U, E>&& r) noexcept
320     {
321         reset(r.release());
322         deleter_ = r.get_deleter();
323         return *this;
324     }
325 
326     void swap(unique_ptr& other) noexcept
327     {
328         pointer tmp = ptr_;
329         ptr_ = other.ptr_;
330         other.ptr_ = tmp;
331         auto tmp2 = deleter_;
332         deleter_ = other.deleter_;
333         other.deleter_ = tmp2;
334     }
335 
336     explicit operator bool() const noexcept
337     {
338         return (ptr_ != nullptr);
339     }
340 
341     T& operator[](size_t i) const
342     {
343         return ptr_[i];
344     }
345 
346     unique_ptr(const unique_ptr&) = delete;
347 
348     unique_ptr& operator=(const unique_ptr&) = delete;
349 
350 protected:
351     pointer ptr_ { nullptr };
352     D deleter_;
353 };
354 
355 // equality comparisons
356 template<class T1, class D1, class T2, class D2>
357 bool operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
358 {
359     return x.get() == y.get();
360 }
361 template<class T1, class D1>
362 bool operator==(const unique_ptr<T1, D1>& x, nullptr_t)
363 {
364     return x.get() == nullptr;
365 }
366 template<class T1, class D1>
367 bool operator==(nullptr_t, const unique_ptr<T1, D1>& x)
368 {
369     return x.get() == nullptr;
370 }
371 
372 // in-equality comparisons
373 template<class T1, class D1, class T2, class D2>
374 bool operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
375 {
376     return x.get() != y.get();
377 }
378 template<class T1, class D1>
379 bool operator!=(const unique_ptr<T1, D1>& x, nullptr_t)
380 {
381     return x.get() != nullptr;
382 }
383 template<class T1, class D1>
384 bool operator!=(nullptr_t, const unique_ptr<T1, D1>& x)
385 {
386     return x.get() != nullptr;
387 }
388 
389 // non-array types
390 template<class T, class... Args, BASE_NS::enable_if_t<!BASE_NS::is_array_v<T>, int> = 0>
391 unique_ptr<T> make_unique(Args&&... args)
392 {
393     return unique_ptr<T>(new T(BASE_NS::forward<Args>(args)...));
394 }
395 
396 // arrays with unknown bound
397 template<class T, BASE_NS::enable_if_t<BASE_NS::is_array_v<T> && BASE_NS::extent_v<T> == 0, int> = 0>
398 unique_ptr<T> make_unique(size_t size)
399 {
400     return unique_ptr<T>(new typename BASE_NS::remove_extent_t<T>[size]());
401 }
402 
403 // arrays with known bound. (not-allowed)
404 template<class T, class... Args, BASE_NS::enable_if_t<BASE_NS::is_array_v<T> && BASE_NS::extent_v<T> != 0, int> = 0>
405 void make_unique(Args&&... args) = delete;
406 BASE_END_NAMESPACE()
407 
408 #endif // API_BASE_CONTAINERS_UNIQUE_PTR_H