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