1 #ifndef _DESHAREDPTR_HPP 2 #define _DESHAREDPTR_HPP 3 /*------------------------------------------------------------------------- 4 * drawElements C++ Base Library 5 * ----------------------------- 6 * 7 * Copyright 2014 The Android Open Source Project 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * 21 *//*! 22 * \file 23 * \brief Shared pointer. 24 *//*--------------------------------------------------------------------*/ 25 26 #include "deDefs.hpp" 27 #include "deAtomic.h" 28 29 #include <exception> 30 #include <algorithm> 31 32 namespace de 33 { 34 35 //! Shared pointer self-test. 36 void SharedPtr_selfTest (void); 37 38 class DeadReferenceException : public std::exception 39 { 40 public: 41 DeadReferenceException (void) throw() 42 : std::exception() 43 { 44 } 45 46 const char* what (void) const throw() 47 { 48 return "DeadReferenceException"; 49 } 50 }; 51 52 struct SharedPtrStateBase 53 { 54 SharedPtrStateBase (void) 55 : strongRefCount (0) 56 , weakRefCount (0) 57 { 58 } 59 60 virtual ~SharedPtrStateBase (void) throw() {} 61 virtual void deletePtr (void) throw() = 0; 62 63 volatile deInt32 strongRefCount; 64 volatile deInt32 weakRefCount; //!< WeakPtr references + StrongPtr references. 65 }; 66 67 template<typename Type, typename Deleter> 68 struct SharedPtrState : public SharedPtrStateBase 69 { 70 SharedPtrState (Type* ptr, Deleter deleter) 71 : m_ptr (ptr) 72 , m_deleter (deleter) 73 { 74 } 75 76 virtual ~SharedPtrState (void) throw() 77 { 78 DE_ASSERT(!m_ptr); 79 } 80 81 virtual void deletePtr (void) throw() 82 { 83 m_deleter(m_ptr); 84 m_ptr = DE_NULL; 85 } 86 87 private: 88 Type* m_ptr; 89 Deleter m_deleter; 90 }; 91 92 template<typename T> 93 class SharedPtr; 94 95 template<typename T> 96 class WeakPtr; 97 98 /*--------------------------------------------------------------------*//*! 99 * \brief Shared pointer 100 * 101 * SharedPtr is smart pointer for managing shared ownership to a pointer. 102 * Multiple SharedPtrs can maintain ownership to the pointer and it is 103 * destructed when last SharedPtr is destroyed. 104 * 105 * SharedPtr can also be NULL. 106 *//*--------------------------------------------------------------------*/ 107 template<typename T> 108 class SharedPtr 109 { 110 public: 111 SharedPtr (void); 112 SharedPtr (const SharedPtr<T>& other); 113 explicit SharedPtr (T* ptr); 114 115 template<typename Deleter> 116 SharedPtr (T* ptr, Deleter deleter); 117 118 template<typename Y> 119 explicit SharedPtr (const SharedPtr<Y>& other); 120 121 template<typename Y> 122 explicit SharedPtr (const WeakPtr<Y>& other); 123 124 ~SharedPtr (void); 125 126 template<typename Y> 127 SharedPtr& operator= (const SharedPtr<Y>& other); 128 SharedPtr& operator= (const SharedPtr<T>& other); 129 130 template<typename Y> 131 SharedPtr& operator= (const WeakPtr<Y>& other); 132 133 T* get (void) const throw() { return m_ptr; } //!< Get stored pointer. 134 T* operator-> (void) const throw() { return m_ptr; } //!< Get stored pointer. 135 T& operator* (void) const throw() { return *m_ptr; } //!< De-reference pointer. 136 137 operator bool (void) const throw() { return !!m_ptr; } 138 139 void swap (SharedPtr<T>& other); 140 141 void clear (void); 142 143 template<typename Y> 144 operator SharedPtr<Y> (void) const; 145 146 private: 147 void acquire (void); 148 void acquireFromWeak (const WeakPtr<T>& other); 149 void release (void); 150 151 T* m_ptr; 152 SharedPtrStateBase* m_state; 153 154 friend class WeakPtr<T>; 155 156 template<typename U> 157 friend class SharedPtr; 158 }; 159 160 /*--------------------------------------------------------------------*//*! 161 * \brief Weak pointer 162 * 163 * WeakPtr manages weak references to objects owned by SharedPtr. Shared 164 * pointer can be converted to weak pointer and vice versa. Weak pointer 165 * differs from SharedPtr by not affecting the lifetime of the managed 166 * object. 167 * 168 * WeakPtr can be converted back to SharedPtr but that operation can fail 169 * if the object is no longer live. In such case DeadReferenceException 170 * will be thrown. 171 *//*--------------------------------------------------------------------*/ 172 template<typename T> 173 class WeakPtr 174 { 175 public: 176 WeakPtr (void); 177 WeakPtr (const WeakPtr<T>& other); 178 179 explicit WeakPtr (const SharedPtr<T>& other); 180 ~WeakPtr (void); 181 182 WeakPtr& operator= (const WeakPtr<T>& other); 183 WeakPtr& operator= (const SharedPtr<T>& other); 184 185 SharedPtr<T> lock (void); 186 187 private: 188 void acquire (void); 189 void release (void); 190 191 T* m_ptr; 192 SharedPtrStateBase* m_state; 193 194 friend class SharedPtr<T>; 195 }; 196 197 // SharedPtr template implementation. 198 199 /*--------------------------------------------------------------------*//*! 200 * \brief Construct empty shared pointer. 201 *//*--------------------------------------------------------------------*/ 202 template<typename T> 203 inline SharedPtr<T>::SharedPtr (void) 204 : m_ptr (DE_NULL) 205 , m_state (DE_NULL) 206 { 207 } 208 209 /*--------------------------------------------------------------------*//*! 210 * \brief Construct shared pointer from pointer. 211 * \param ptr Pointer to be managed. 212 * 213 * Ownership of the pointer will be transferred to SharedPtr and future 214 * SharedPtr's initialized or assigned from this SharedPtr. 215 * 216 * If allocation of shared state fails. The "ptr" argument will not be 217 * released. 218 *//*--------------------------------------------------------------------*/ 219 template<typename T> 220 inline SharedPtr<T>::SharedPtr (T* ptr) 221 : m_ptr (DE_NULL) 222 , m_state (DE_NULL) 223 { 224 try 225 { 226 m_ptr = ptr; 227 m_state = new SharedPtrState<T, DefaultDeleter<T> >(ptr, DefaultDeleter<T>()); 228 m_state->strongRefCount = 1; 229 m_state->weakRefCount = 1; 230 } 231 catch (...) 232 { 233 // \note ptr is not released. 234 delete m_state; 235 throw; 236 } 237 } 238 239 /*--------------------------------------------------------------------*//*! 240 * \brief Construct shared pointer from pointer. 241 * \param ptr Pointer to be managed. 242 * 243 * Ownership of the pointer will be transferred to SharedPtr and future 244 * SharedPtr's initialized or assigned from this SharedPtr. 245 * 246 * Deleter must be callable type and deleter is called with the pointer 247 * argument when the reference count becomes 0. 248 * 249 * If allocation of shared state fails. The "ptr" argument will not be 250 * released. 251 * 252 * Calling deleter or calling destructor for deleter should never throw. 253 *//*--------------------------------------------------------------------*/ 254 template<typename T> 255 template<typename Deleter> 256 inline SharedPtr<T>::SharedPtr (T* ptr, Deleter deleter) 257 : m_ptr (DE_NULL) 258 , m_state (DE_NULL) 259 { 260 try 261 { 262 m_ptr = ptr; 263 m_state = new SharedPtrState<T, Deleter>(ptr, deleter); 264 m_state->strongRefCount = 1; 265 m_state->weakRefCount = 1; 266 } 267 catch (...) 268 { 269 // \note ptr is not released. 270 delete m_state; 271 throw; 272 } 273 } 274 275 /*--------------------------------------------------------------------*//*! 276 * \brief Initialize shared pointer from another SharedPtr. 277 * \param other Pointer to be shared. 278 *//*--------------------------------------------------------------------*/ 279 template<typename T> 280 inline SharedPtr<T>::SharedPtr (const SharedPtr<T>& other) 281 : m_ptr (other.m_ptr) 282 , m_state (other.m_state) 283 { 284 acquire(); 285 } 286 287 /*--------------------------------------------------------------------*//*! 288 * \brief Initialize shared pointer from another SharedPtr. 289 * \param other Pointer to be shared. 290 * 291 * Y* must be convertible to T*. 292 *//*--------------------------------------------------------------------*/ 293 template<typename T> 294 template<typename Y> 295 inline SharedPtr<T>::SharedPtr (const SharedPtr<Y>& other) 296 : m_ptr (other.m_ptr) 297 , m_state (other.m_state) 298 { 299 acquire(); 300 } 301 302 /*--------------------------------------------------------------------*//*! 303 * \brief Initialize shared pointer from weak reference. 304 * \param other Pointer to be shared. 305 * 306 * Y* must be convertible to T*. 307 *//*--------------------------------------------------------------------*/ 308 template<typename T> 309 template<typename Y> 310 inline SharedPtr<T>::SharedPtr (const WeakPtr<Y>& other) 311 : m_ptr (DE_NULL) 312 , m_state (DE_NULL) 313 { 314 acquireFromWeak(other); 315 } 316 317 template<typename T> 318 inline SharedPtr<T>::~SharedPtr (void) 319 { 320 release(); 321 } 322 323 /*--------------------------------------------------------------------*//*! 324 * \brief Assign from other shared pointer. 325 * \param other Pointer to be shared. 326 * \return Reference to this SharedPtr. 327 * 328 * Reference to current pointer is released and reference to new pointer is 329 * acquired. 330 * 331 * Y* must be convertible to T*. 332 *//*--------------------------------------------------------------------*/ 333 template<typename T> 334 template<typename Y> 335 inline SharedPtr<T>& SharedPtr<T>::operator= (const SharedPtr<Y>& other) 336 { 337 if (m_state == other.m_state) 338 return *this; 339 340 // Release current reference. 341 release(); 342 343 // Copy from other and acquire reference. 344 m_ptr = other.m_ptr; 345 m_state = other.m_state; 346 347 acquire(); 348 349 return *this; 350 } 351 352 /*--------------------------------------------------------------------*//*! 353 * \brief Assign from other shared pointer. 354 * \param other Pointer to be shared. 355 * \return Reference to this SharedPtr. 356 * 357 * Reference to current pointer is released and reference to new pointer is 358 * acquired. 359 *//*--------------------------------------------------------------------*/ 360 template<typename T> 361 inline SharedPtr<T>& SharedPtr<T>::operator= (const SharedPtr<T>& other) 362 { 363 if (m_state == other.m_state) 364 return *this; 365 366 // Release current reference. 367 release(); 368 369 // Copy from other and acquire reference. 370 m_ptr = other.m_ptr; 371 m_state = other.m_state; 372 373 acquire(); 374 375 return *this; 376 } 377 378 /*--------------------------------------------------------------------*//*! 379 * \brief Assign from weak pointer. 380 * \param other Weak reference. 381 * \return Reference to this SharedPtr. 382 * 383 * Tries to acquire reference to WeakPtr, releases current reference and 384 * holds reference to new pointer. 385 * 386 * If WeakPtr can't be acquired, throws DeadReferenceException and doesn't 387 * release the current reference. 388 * 389 * If WeakPtr references same pointer as SharedPtr this call will always 390 * succeed. 391 * 392 * Y* must be convertible to T*. 393 *//*--------------------------------------------------------------------*/ 394 template<typename T> 395 template<typename Y> 396 inline SharedPtr<T>& SharedPtr<T>::operator= (const WeakPtr<Y>& other) 397 { 398 if (m_state == other.m_state) 399 return *this; 400 401 { 402 SharedPtr<T> sharedOther(other); 403 *this = other; 404 } 405 406 return *this; 407 } 408 409 /*--------------------------------------------------------------------*//*! 410 * \brief Type conversion operator. 411 * 412 * T* must be convertible to Y*. 413 *//*--------------------------------------------------------------------*/ 414 template<class T> 415 template<typename Y> 416 inline SharedPtr<T>::operator SharedPtr<Y> (void) const 417 { 418 return SharedPtr<Y>(*this); 419 } 420 421 /*--------------------------------------------------------------------*//*! 422 * \brief Compare pointers. 423 * \param a A 424 * \param b B 425 * \return true if A and B point to same object, false otherwise. 426 *//*--------------------------------------------------------------------*/ 427 template<class T, class U> 428 inline bool operator== (const SharedPtr<T>& a, const SharedPtr<U>& b) throw() 429 { 430 return a.get() == b.get(); 431 } 432 433 /*--------------------------------------------------------------------*//*! 434 * \brief Compare pointers. 435 * \param a A 436 * \param b B 437 * \return true if A and B point to different objects, false otherwise. 438 *//*--------------------------------------------------------------------*/ 439 template<class T, class U> 440 inline bool operator!= (const SharedPtr<T>& a, const SharedPtr<U>& b) throw() 441 { 442 return a.get() != b.get(); 443 } 444 445 /** Swap pointer contents. */ 446 template<typename T> 447 inline void SharedPtr<T>::swap (SharedPtr<T>& other) 448 { 449 using std::swap; 450 swap(m_ptr, other.m_ptr); 451 swap(m_state, other.m_state); 452 } 453 454 /** Swap operator for SharedPtr's. */ 455 template<typename T> 456 inline void swap (SharedPtr<T>& a, SharedPtr<T>& b) 457 { 458 a.swap(b); 459 } 460 461 /*--------------------------------------------------------------------*//*! 462 * \brief Set pointer to null. 463 * 464 * clear() removes current reference and sets pointer to null value. 465 *//*--------------------------------------------------------------------*/ 466 template<typename T> 467 inline void SharedPtr<T>::clear (void) 468 { 469 release(); 470 m_ptr = DE_NULL; 471 m_state = DE_NULL; 472 } 473 474 template<typename T> 475 inline void SharedPtr<T>::acquireFromWeak (const WeakPtr<T>& weakRef) 476 { 477 DE_ASSERT(!m_ptr && !m_state); 478 479 SharedPtrStateBase* state = weakRef.m_state; 480 481 if (!state) 482 return; // Empty reference. 483 484 { 485 deInt32 oldCount, newCount; 486 487 // Do atomic compare and increment. 488 do 489 { 490 oldCount = state->strongRefCount; 491 if (oldCount == 0) 492 throw DeadReferenceException(); 493 newCount = oldCount+1; 494 } while (deAtomicCompareExchange32((deUint32 volatile*)&state->strongRefCount, (deUint32)oldCount, (deUint32)newCount) != (deUint32)oldCount); 495 496 deAtomicIncrement32(&state->weakRefCount); 497 } 498 499 m_ptr = weakRef.m_ptr; 500 m_state = state; 501 } 502 503 template<typename T> 504 inline void SharedPtr<T>::acquire (void) 505 { 506 if (m_state) 507 { 508 deAtomicIncrement32(&m_state->strongRefCount); 509 deAtomicIncrement32(&m_state->weakRefCount); 510 } 511 } 512 513 template<typename T> 514 inline void SharedPtr<T>::release (void) 515 { 516 if (m_state) 517 { 518 if (deAtomicDecrement32(&m_state->strongRefCount) == 0) 519 { 520 m_ptr = DE_NULL; 521 m_state->deletePtr(); 522 } 523 524 if (deAtomicDecrement32(&m_state->weakRefCount) == 0) 525 { 526 delete m_state; 527 m_state = DE_NULL; 528 } 529 } 530 } 531 532 // WeakPtr template implementation. 533 534 /*--------------------------------------------------------------------*//*! 535 * \brief Construct empty weak pointer. 536 *//*--------------------------------------------------------------------*/ 537 template<typename T> 538 inline WeakPtr<T>::WeakPtr (void) 539 : m_ptr (DE_NULL) 540 , m_state (DE_NULL) 541 { 542 } 543 544 /*--------------------------------------------------------------------*//*! 545 * \brief Construct weak pointer from other weak reference. 546 * \param other Weak reference. 547 *//*--------------------------------------------------------------------*/ 548 template<typename T> 549 inline WeakPtr<T>::WeakPtr (const WeakPtr<T>& other) 550 : m_ptr (other.m_ptr) 551 , m_state (other.m_state) 552 { 553 acquire(); 554 } 555 556 /*--------------------------------------------------------------------*//*! 557 * \brief Construct weak pointer from shared pointer. 558 * \param other Shared pointer. 559 *//*--------------------------------------------------------------------*/ 560 template<typename T> 561 inline WeakPtr<T>::WeakPtr (const SharedPtr<T>& other) 562 : m_ptr (other.m_ptr) 563 , m_state (other.m_state) 564 { 565 acquire(); 566 } 567 568 template<typename T> 569 inline WeakPtr<T>::~WeakPtr (void) 570 { 571 release(); 572 } 573 574 /*--------------------------------------------------------------------*//*! 575 * \brief Assign from another weak pointer. 576 * \param other Weak reference. 577 * \return Reference to this WeakPtr. 578 * 579 * The current weak reference is removed first and then a new weak reference 580 * to the object pointed by other is taken. 581 *//*--------------------------------------------------------------------*/ 582 template<typename T> 583 inline WeakPtr<T>& WeakPtr<T>::operator= (const WeakPtr<T>& other) 584 { 585 if (this == &other) 586 return *this; 587 588 release(); 589 590 m_ptr = other.m_ptr; 591 m_state = other.m_state; 592 593 acquire(); 594 595 return *this; 596 } 597 598 /*--------------------------------------------------------------------*//*! 599 * \brief Assign from shared pointer. 600 * \param other Shared pointer. 601 * \return Reference to this WeakPtr. 602 * 603 * The current weak reference is removed first and then a new weak reference 604 * to the object pointed by other is taken. 605 *//*--------------------------------------------------------------------*/ 606 template<typename T> 607 inline WeakPtr<T>& WeakPtr<T>::operator= (const SharedPtr<T>& other) 608 { 609 release(); 610 611 m_ptr = other.m_ptr; 612 m_state = other.m_state; 613 614 acquire(); 615 616 return *this; 617 } 618 619 template<typename T> 620 inline void WeakPtr<T>::acquire (void) 621 { 622 if (m_state) 623 deAtomicIncrement32(&m_state->weakRefCount); 624 } 625 626 template<typename T> 627 inline void WeakPtr<T>::release (void) 628 { 629 if (m_state) 630 { 631 if (deAtomicDecrement32(&m_state->weakRefCount) == 0) 632 { 633 delete m_state; 634 m_state = DE_NULL; 635 m_ptr = DE_NULL; 636 } 637 } 638 } 639 640 } // de 641 642 #endif // _DESHAREDPTR_HPP 643