1 /* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SkUniquePtr_DEFINED 9 #define SkUniquePtr_DEFINED 10 11 #include "SkTLogic.h" 12 #include <cstddef> 13 #include <utility> 14 15 namespace skstd { 16 17 template <typename T> struct default_delete { 18 /*constexpr*/ default_delete() /*noexcept*/ = default; 19 20 template <typename U, typename = enable_if_t<is_convertible<U*, T*>::value>> default_deletedefault_delete21 default_delete(const default_delete<U>&) /*noexcept*/ {} 22 operatordefault_delete23 void operator()(T* obj) const { 24 static_assert(sizeof(T) > 0, "Deleting pointer to incomplete type!"); 25 delete obj; 26 } 27 }; 28 template <typename T> struct default_delete<T[]> { 29 /*constexpr*/ default_delete() /*noexcept*/ = default; 30 31 void operator()(T* obj) const { 32 static_assert(sizeof(T) > 0, "Deleting pointer to incomplete type!"); 33 delete [] obj; 34 } 35 }; 36 37 template <typename T, typename D = default_delete<T>> class unique_ptr { 38 // remove_reference_t<D>::pointer if that type exists, otherwise T*. 39 struct pointer_type_detector { 40 template <typename U> static typename U::pointer detector(typename U::pointer*); 41 template <typename U> static T* detector(...); 42 using type = decltype(detector<remove_reference_t<D>>(0)); 43 }; 44 45 public: 46 using pointer = typename pointer_type_detector::type; 47 using element_type = T; 48 using deleter_type = D; 49 50 private: 51 template <typename B, bool> 52 struct compressed_base : private B { 53 /*constexpr*/ compressed_base() : B() {} 54 /*constexpr*/ compressed_base(const B& b) : B(b) {} 55 /*constexpr*/ compressed_base(B&& b) : B(std::move(b)) {} 56 /*constexpr*/ B& get() /*noexcept*/ { return *this; } 57 /*constexpr*/ B const& get() const /*noexcept*/ { return *this; } 58 void swap(compressed_base&) /*noexcept*/ { } 59 }; 60 61 template <typename B> struct compressed_base<B, false> { 62 B fb; 63 /*constexpr*/ compressed_base() : B() {} 64 /*constexpr*/ compressed_base(const B& b) : fb(b) {} 65 /*constexpr*/ compressed_base(B&& b) : fb(std::move(b)) {} 66 /*constexpr*/ B& get() /*noexcept*/ { return fb; } 67 /*constexpr*/ B const& get() const /*noexcept*/ { return fb; } 68 void swap(compressed_base& that) /*noexcept*/ { SkTSwap(fb, that.fB); } 69 }; 70 71 // C++14 adds '&& !std::is_final<deleter_type>::value' to the bool condition. 72 // compressed_base_t exists and has this form to work around a bug in vs2013sp2-3 73 using compressed_base_t = compressed_base<deleter_type, std::is_empty<deleter_type>::value>; 74 75 struct compressed_data : private compressed_base_t { 76 pointer fPtr; 77 /*constexpr*/ compressed_data() : compressed_base_t(), fPtr() {} 78 /*constexpr*/ compressed_data(const pointer& ptr, const deleter_type& d) 79 : compressed_base_t(d), fPtr(ptr) {} 80 template <typename U1, typename U2, typename = enable_if_t< 81 is_convertible<U1, pointer>::value && is_convertible<U2, deleter_type>::value 82 >> /*constexpr*/ compressed_data(U1&& ptr, U2&& d) 83 : compressed_base_t(std::forward<U2>(d)), fPtr(std::forward<U1>(ptr)) {} 84 /*constexpr*/ pointer& getPointer() /*noexcept*/ { return fPtr; } 85 /*constexpr*/ pointer const& getPointer() const /*noexcept*/ { return fPtr; } 86 /*constexpr*/ deleter_type& getDeleter() /*noexcept*/ { 87 return compressed_base_t::get(); 88 } 89 /*constexpr*/ deleter_type const& getDeleter() const /*noexcept*/ { 90 return compressed_base_t::get(); 91 } 92 void swap(compressed_data& that) /*noexcept*/ { 93 compressed_base_t::swap(static_cast<compressed_base_t>(that)); 94 SkTSwap(fPtr, that.fPtr); 95 } 96 }; 97 compressed_data data; 98 99 public: 100 /*constexpr*/ unique_ptr() /*noexcept*/ : data() { 101 static_assert(!std::is_pointer<deleter_type>::value, "Deleter nullptr function pointer!"); 102 } 103 104 /*constexpr*/ unique_ptr(std::nullptr_t) /*noexcept*/ : unique_ptr() { } 105 106 explicit unique_ptr(pointer ptr) /*noexcept*/ : data(ptr, deleter_type()) { 107 static_assert(!std::is_pointer<deleter_type>::value, "Deleter nullptr function pointer!"); 108 } 109 110 unique_ptr(pointer ptr, 111 conditional_t<std::is_reference<deleter_type>::value, 112 deleter_type, const deleter_type&> d) 113 /*noexcept*/ : data(ptr, d) 114 {} 115 116 unique_ptr(pointer ptr, remove_reference_t<deleter_type>&& d) /*noexcept*/ 117 : data(std::move(ptr), std::move(d)) 118 { 119 static_assert(!std::is_reference<deleter_type>::value, 120 "Binding an rvalue reference deleter as an lvalue reference deleter is not allowed."); 121 } 122 123 124 unique_ptr(unique_ptr&& that) /*noexcept*/ 125 : data(that.release(), std::forward<deleter_type>(that.get_deleter())) 126 {} 127 128 template <typename U, typename ThatD, typename = enable_if_t< 129 is_convertible<typename unique_ptr<U, ThatD>::pointer, pointer>::value && 130 !std::is_array<U>::value && 131 conditional_t<std::is_reference<D>::value, 132 std::is_same<ThatD, D>, 133 is_convertible<ThatD, D>>::value>> 134 unique_ptr(unique_ptr<U, ThatD>&& that) /*noexcept*/ 135 : data(that.release(), std::forward<ThatD>(that.get_deleter())) 136 {} 137 138 ~unique_ptr() /*noexcept*/ { 139 pointer& ptr = data.getPointer(); 140 if (ptr != nullptr) { 141 get_deleter()(ptr); 142 } 143 ptr = pointer(); 144 } 145 146 unique_ptr& operator=(unique_ptr&& that) /*noexcept*/ { 147 reset(that.release()); 148 get_deleter() = std::forward<deleter_type>(that.get_deleter()); 149 return *this; 150 } 151 152 template <typename U, typename ThatD> enable_if_t< 153 is_convertible<typename unique_ptr<U, ThatD>::pointer, pointer>::value && 154 !std::is_array<U>::value, 155 unique_ptr&> operator=(unique_ptr<U, ThatD>&& that) /*noexcept*/ { 156 reset(that.release()); 157 get_deleter() = std::forward<ThatD>(that.get_deleter()); 158 return *this; 159 } 160 161 unique_ptr& operator=(std::nullptr_t) /*noexcept*/ { 162 reset(); 163 return *this; 164 } 165 166 add_lvalue_reference_t<element_type> operator*() const { 167 SkASSERT(get() != pointer()); 168 return *get(); 169 } 170 171 pointer operator->() const /*noexcept*/ { 172 SkASSERT(get() != pointer()); 173 return get(); 174 } 175 176 pointer get() const /*noexcept*/ { 177 return data.getPointer(); 178 } 179 180 deleter_type& get_deleter() /*noexcept*/ { 181 return data.getDeleter(); 182 } 183 184 const deleter_type& get_deleter() const /*noexcept*/ { 185 return data.getDeleter(); 186 } 187 188 //explicit operator bool() const noexcept { 189 bool is_attached() const /*noexcept*/ { 190 return get() == pointer() ? false : true; 191 } 192 193 pointer release() /*noexcept*/ { 194 pointer ptr = get(); 195 data.getPointer() = pointer(); 196 return ptr; 197 } 198 199 void reset(pointer ptr = pointer()) /*noexcept*/ { 200 SkTSwap(data.getPointer(), ptr); 201 if (ptr != pointer()) { 202 get_deleter()(ptr); 203 } 204 } 205 206 void swap(unique_ptr& that) /*noexcept*/ { 207 SkTSwap(data, that.data); 208 } 209 210 unique_ptr(const unique_ptr&) = delete; 211 unique_ptr& operator=(const unique_ptr&) = delete; 212 }; 213 214 template <typename T, typename D> class unique_ptr<T[], D> { 215 // remove_reference_t<D>::pointer if that type exists, otherwise T*. 216 struct pointer_type_detector { 217 template <typename U> static typename U::pointer detector(typename U::pointer*); 218 template <typename U> static T* detector(...); 219 using type = decltype(detector<remove_reference_t<D>>(0)); 220 }; 221 222 public: 223 using pointer = typename pointer_type_detector::type; 224 using element_type = T; 225 using deleter_type = D; 226 227 private: 228 template <typename B, bool> struct compressed_base : private B { 229 /*constexpr*/ compressed_base() : B() {} 230 /*constexpr*/ compressed_base(const B& b) : B(b) {} 231 /*constexpr*/ compressed_base(B&& b) : B(std::move(b)) {} 232 /*constexpr*/ B& get() /*noexcept*/ { return *this; } 233 /*constexpr*/ B const& get() const /*noexcept*/ { return *this; } 234 void swap(compressed_base&) /*noexcept*/ { } 235 }; 236 237 template <typename B> struct compressed_base<B, false> { 238 B fb; 239 /*constexpr*/ compressed_base() : B() {} 240 /*constexpr*/ compressed_base(const B& b) : fb(b) {} 241 /*constexpr*/ compressed_base(B&& b) : fb(std::move(b)) {} 242 /*constexpr*/ B& get() /*noexcept*/ { return fb; } 243 /*constexpr*/ B const& get() const /*noexcept*/ { return fb; } 244 void swap(compressed_base& that) /*noexcept*/ { SkTSwap(fb, that.fB); } 245 }; 246 247 // C++14 adds '&& !std::is_final<deleter_type>::value' to the bool condition. 248 // compressed_base_t exists and has this form to work around a bug in vs2013sp2-3 249 using compressed_base_t = compressed_base<deleter_type, std::is_empty<deleter_type>::value>; 250 251 struct compressed_data : private compressed_base_t { 252 pointer fPtr; 253 /*constexpr*/ compressed_data() : compressed_base_t(), fPtr() {} 254 /*constexpr*/ compressed_data(const pointer& ptr, const deleter_type& d) 255 : compressed_base_t(d), fPtr(ptr) {} 256 template <typename U1, typename U2, typename = enable_if_t< 257 is_convertible<U1, pointer>::value && is_convertible<U2, deleter_type>::value 258 >> /*constexpr*/ compressed_data(U1&& ptr, U2&& d) 259 : compressed_base_t(std::forward<U2>(d)), fPtr(std::forward<U1>(ptr)) {} 260 /*constexpr*/ pointer& getPointer() /*noexcept*/ { return fPtr; } 261 /*constexpr*/ pointer const& getPointer() const /*noexcept*/ { return fPtr; } 262 /*constexpr*/ deleter_type& getDeleter() /*noexcept*/ { 263 return compressed_base_t::get(); 264 } 265 /*constexpr*/ deleter_type const& getDeleter() const /*noexcept*/ { 266 return compressed_base_t::get(); 267 } 268 void swap(compressed_data& that) /*noexcept*/ { 269 compressed_base_t::swap(static_cast<compressed_base_t>(that)); 270 SkTSwap(fPtr, that.fPtr); 271 } 272 }; 273 compressed_data data; 274 275 public: 276 /*constexpr*/ unique_ptr() /*noexcept*/ : data() { 277 static_assert(!std::is_pointer<deleter_type>::value, "Deleter nullptr function pointer!"); 278 } 279 280 /*constexpr*/ unique_ptr(std::nullptr_t) /*noexcept*/ : unique_ptr() { } 281 282 explicit unique_ptr(pointer ptr) /*noexcept*/ : data(ptr, deleter_type()) { 283 static_assert(!std::is_pointer<deleter_type>::value, "Deleter nullptr function pointer!"); 284 } 285 286 unique_ptr(pointer ptr, 287 conditional_t<std::is_reference<deleter_type>::value, 288 deleter_type, const deleter_type&> d) 289 /*noexcept*/ : data(ptr, d) 290 {} 291 292 unique_ptr(pointer ptr, remove_reference_t<deleter_type>&& d) /*noexcept*/ 293 : data(std::move(ptr), std::move(d)) 294 { 295 static_assert(!std::is_reference<deleter_type>::value, 296 "Binding an rvalue reference deleter as an lvalue reference deleter is not allowed."); 297 } 298 299 unique_ptr(unique_ptr&& that) /*noexcept*/ 300 : data(that.release(), std::forward<deleter_type>(that.get_deleter())) 301 {} 302 303 ~unique_ptr() { 304 pointer& ptr = data.getPointer(); 305 if (ptr != nullptr) { 306 get_deleter()(ptr); 307 } 308 ptr = pointer(); 309 } 310 311 unique_ptr& operator=(unique_ptr&& that) /*noexcept*/ { 312 reset(that.release()); 313 get_deleter() = std::forward<deleter_type>(that.get_deleter()); 314 return *this; 315 } 316 317 unique_ptr& operator=(std::nullptr_t) /*noexcept*/ { 318 reset(); 319 return *this; 320 } 321 322 add_lvalue_reference_t<element_type> operator[](size_t i) const { 323 SkASSERT(get() != pointer()); 324 return get()[i]; 325 } 326 327 pointer get() const /*noexcept*/ { 328 return data.getPointer(); 329 } 330 331 deleter_type& get_deleter() /*noexcept*/ { 332 return data.getDeleter(); 333 } 334 335 const deleter_type& get_deleter() const /*noexcept*/ { 336 return data.getDeleter(); 337 } 338 339 //explicit operator bool() const noexcept { 340 bool is_attached() const /*noexcept*/ { 341 return get() == pointer() ? false : true; 342 } 343 344 pointer release() /*noexcept*/ { 345 pointer ptr = get(); 346 data.getPointer() = pointer(); 347 return ptr; 348 } 349 350 void reset(pointer ptr = pointer()) /*noexcept*/ { 351 SkTSwap(data.getPointer(), ptr); 352 if (ptr != pointer()) { 353 get_deleter()(ptr); 354 } 355 } 356 357 template <typename U> void reset(U*) = delete; 358 359 void swap(unique_ptr& that) /*noexcept*/ { 360 data.swap(that.data); 361 } 362 363 unique_ptr(const unique_ptr&) = delete; 364 unique_ptr& operator=(const unique_ptr&) = delete; 365 }; 366 367 template <typename T, typename D> 368 inline void swap(unique_ptr<T, D>& a, unique_ptr<T, D>& b) /*noexcept*/ { 369 a.swap(b); 370 } 371 372 template <typename T, typename D, typename U, typename ThatD> 373 inline bool operator==(const unique_ptr<T, D>& a, const unique_ptr<U, ThatD>& b) { 374 return a.get() == b.get(); 375 } 376 377 template <typename T, typename D> 378 inline bool operator==(const unique_ptr<T, D>& a, std::nullptr_t) /*noexcept*/ { 379 //return !a; 380 return !a.is_attached(); 381 } 382 383 template <typename T, typename D> 384 inline bool operator==(std::nullptr_t, const unique_ptr<T, D>& b) /*noexcept*/ { 385 //return !b; 386 return !b.is_attached(); 387 } 388 389 template <typename T, typename D, typename U, typename ThatD> 390 inline bool operator!=(const unique_ptr<T, D>& a, const unique_ptr<U, ThatD>& b) { 391 return a.get() != b.get(); 392 } 393 394 template <typename T, typename D> 395 inline bool operator!=(const unique_ptr<T, D>& a, std::nullptr_t) /*noexcept*/ { 396 //return (bool)a; 397 return a.is_attached(); 398 } 399 400 template <typename T, typename D> 401 inline bool operator!=(std::nullptr_t, const unique_ptr<T, D>& b) /*noexcept*/ { 402 //return (bool)b; 403 return b.is_attached(); 404 } 405 406 } // namespace skstd 407 408 #endif 409