1 //===---------------------SharingPtr.h --------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef utility_SharingPtr_h_ 11 #define utility_SharingPtr_h_ 12 13 #include <algorithm> 14 #include <memory> 15 16 //#define ENABLE_SP_LOGGING 1 // DON'T CHECK THIS LINE IN UNLESS COMMENTED OUT 17 #if defined (ENABLE_SP_LOGGING) 18 19 extern "C" void track_sp (void *sp_this, void *ptr, long count); 20 21 #endif 22 23 namespace lldb_private { 24 25 namespace imp { 26 27 template <class T> 28 inline T 29 increment(T& t) 30 { 31 return __sync_add_and_fetch(&t, 1); 32 } 33 34 template <class T> 35 inline T 36 decrement(T& t) 37 { 38 return __sync_add_and_fetch(&t, -1); 39 } 40 41 class shared_count 42 { 43 shared_count(const shared_count&); 44 shared_count& operator=(const shared_count&); 45 46 protected: 47 long shared_owners_; 48 virtual ~shared_count(); 49 private: 50 virtual void on_zero_shared() = 0; 51 52 public: 53 explicit shared_count(long refs = 0) 54 : shared_owners_(refs) {} 55 56 void add_shared(); 57 void release_shared(); 58 long use_count() const {return shared_owners_ + 1;} 59 }; 60 61 template <class T> 62 class shared_ptr_pointer 63 : public shared_count 64 { 65 T data_; 66 public: 67 shared_ptr_pointer(T p) 68 : data_(p) {} 69 70 private: 71 virtual void on_zero_shared(); 72 73 // Outlaw copy constructor and assignment operator to keep effictive C++ 74 // warnings down to a minumum 75 shared_ptr_pointer (const shared_ptr_pointer &); 76 shared_ptr_pointer & operator=(const shared_ptr_pointer &); 77 }; 78 79 template <class T> 80 void 81 shared_ptr_pointer<T>::on_zero_shared() 82 { 83 delete data_; 84 } 85 86 template <class T> 87 class shared_ptr_emplace 88 : public shared_count 89 { 90 T data_; 91 public: 92 93 shared_ptr_emplace() 94 : data_() {} 95 96 template <class A0> 97 shared_ptr_emplace(A0& a0) 98 : data_(a0) {} 99 100 template <class A0, class A1> 101 shared_ptr_emplace(A0& a0, A1& a1) 102 : data_(a0, a1) {} 103 104 template <class A0, class A1, class A2> 105 shared_ptr_emplace(A0& a0, A1& a1, A2& a2) 106 : data_(a0, a1, a2) {} 107 108 template <class A0, class A1, class A2, class A3> 109 shared_ptr_emplace(A0& a0, A1& a1, A2& a2, A3& a3) 110 : data_(a0, a1, a2, a3) {} 111 112 template <class A0, class A1, class A2, class A3, class A4> 113 shared_ptr_emplace(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4) 114 : data_(a0, a1, a2, a3, a4) {} 115 116 private: 117 virtual void on_zero_shared(); 118 public: 119 T* get() {return &data_;} 120 }; 121 122 template <class T> 123 void 124 shared_ptr_emplace<T>::on_zero_shared() 125 { 126 } 127 128 } // namespace 129 130 template<class T> 131 class SharingPtr 132 { 133 public: 134 typedef T element_type; 135 private: 136 element_type* ptr_; 137 imp::shared_count* cntrl_; 138 139 struct nat {int for_bool_;}; 140 public: 141 SharingPtr(); 142 template<class Y> explicit SharingPtr(Y* p); 143 template<class Y> explicit SharingPtr(Y* p, imp::shared_count *ctrl_block); 144 template<class Y> SharingPtr(const SharingPtr<Y>& r, element_type *p); 145 SharingPtr(const SharingPtr& r); 146 template<class Y> 147 SharingPtr(const SharingPtr<Y>& r); 148 149 ~SharingPtr(); 150 151 SharingPtr& operator=(const SharingPtr& r); 152 template<class Y> SharingPtr& operator=(const SharingPtr<Y>& r); 153 154 void swap(SharingPtr& r); 155 void reset(); 156 template<class Y> void reset(Y* p); 157 158 element_type* get() const {return ptr_;} 159 element_type& operator*() const {return *ptr_;} 160 element_type* operator->() const {return ptr_;} 161 long use_count() const {return cntrl_ ? cntrl_->use_count() : 0;} 162 bool unique() const {return use_count() == 1;} 163 bool empty() const {return cntrl_ == 0;} 164 operator nat*() const {return (nat*)get();} 165 166 static SharingPtr<T> make_shared(); 167 168 template<class A0> 169 static SharingPtr<T> make_shared(A0&); 170 171 template<class A0, class A1> 172 static SharingPtr<T> make_shared(A0&, A1&); 173 174 template<class A0, class A1, class A2> 175 static SharingPtr<T> make_shared(A0&, A1&, A2&); 176 177 template<class A0, class A1, class A2, class A3> 178 static SharingPtr<T> make_shared(A0&, A1&, A2&, A3&); 179 180 template<class A0, class A1, class A2, class A3, class A4> 181 static SharingPtr<T> make_shared(A0&, A1&, A2&, A3&, A4&); 182 183 private: 184 185 template <class U> friend class SharingPtr; 186 }; 187 188 template<class T> 189 inline 190 SharingPtr<T>::SharingPtr() 191 : ptr_(0), 192 cntrl_(0) 193 { 194 } 195 196 template<class T> 197 template<class Y> 198 SharingPtr<T>::SharingPtr(Y* p) 199 : ptr_(p), cntrl_(0) 200 { 201 std::unique_ptr<Y> hold(p); 202 typedef imp::shared_ptr_pointer<Y*> _CntrlBlk; 203 cntrl_ = new _CntrlBlk(p); 204 hold.release(); 205 } 206 207 template<class T> 208 template<class Y> 209 SharingPtr<T>::SharingPtr(Y* p, imp::shared_count *cntrl_block) 210 : ptr_(p), cntrl_(cntrl_block) 211 { 212 } 213 214 template<class T> 215 template<class Y> 216 inline 217 SharingPtr<T>::SharingPtr(const SharingPtr<Y>& r, element_type *p) 218 : ptr_(p), 219 cntrl_(r.cntrl_) 220 { 221 if (cntrl_) 222 cntrl_->add_shared(); 223 } 224 225 template<class T> 226 inline 227 SharingPtr<T>::SharingPtr(const SharingPtr& r) 228 : ptr_(r.ptr_), 229 cntrl_(r.cntrl_) 230 { 231 if (cntrl_) 232 cntrl_->add_shared(); 233 } 234 235 template<class T> 236 template<class Y> 237 inline 238 SharingPtr<T>::SharingPtr(const SharingPtr<Y>& r) 239 : ptr_(r.ptr_), 240 cntrl_(r.cntrl_) 241 { 242 if (cntrl_) 243 cntrl_->add_shared(); 244 } 245 246 template<class T> 247 SharingPtr<T>::~SharingPtr() 248 { 249 if (cntrl_) 250 cntrl_->release_shared(); 251 } 252 253 template<class T> 254 inline 255 SharingPtr<T>& 256 SharingPtr<T>::operator=(const SharingPtr& r) 257 { 258 SharingPtr(r).swap(*this); 259 return *this; 260 } 261 262 template<class T> 263 template<class Y> 264 inline 265 SharingPtr<T>& 266 SharingPtr<T>::operator=(const SharingPtr<Y>& r) 267 { 268 SharingPtr(r).swap(*this); 269 return *this; 270 } 271 272 template<class T> 273 inline 274 void 275 SharingPtr<T>::swap(SharingPtr& r) 276 { 277 std::swap(ptr_, r.ptr_); 278 std::swap(cntrl_, r.cntrl_); 279 } 280 281 template<class T> 282 inline 283 void 284 SharingPtr<T>::reset() 285 { 286 SharingPtr().swap(*this); 287 } 288 289 template<class T> 290 template<class Y> 291 inline 292 void 293 SharingPtr<T>::reset(Y* p) 294 { 295 SharingPtr(p).swap(*this); 296 } 297 298 template<class T> 299 SharingPtr<T> 300 SharingPtr<T>::make_shared() 301 { 302 typedef imp::shared_ptr_emplace<T> CntrlBlk; 303 SharingPtr<T> r; 304 r.cntrl_ = new CntrlBlk(); 305 r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get(); 306 return r; 307 } 308 309 template<class T> 310 template<class A0> 311 SharingPtr<T> 312 SharingPtr<T>::make_shared(A0& a0) 313 { 314 typedef imp::shared_ptr_emplace<T> CntrlBlk; 315 SharingPtr<T> r; 316 r.cntrl_ = new CntrlBlk(a0); 317 r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get(); 318 return r; 319 } 320 321 template<class T> 322 template<class A0, class A1> 323 SharingPtr<T> 324 SharingPtr<T>::make_shared(A0& a0, A1& a1) 325 { 326 typedef imp::shared_ptr_emplace<T> CntrlBlk; 327 SharingPtr<T> r; 328 r.cntrl_ = new CntrlBlk(a0, a1); 329 r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get(); 330 return r; 331 } 332 333 template<class T> 334 template<class A0, class A1, class A2> 335 SharingPtr<T> 336 SharingPtr<T>::make_shared(A0& a0, A1& a1, A2& a2) 337 { 338 typedef imp::shared_ptr_emplace<T> CntrlBlk; 339 SharingPtr<T> r; 340 r.cntrl_ = new CntrlBlk(a0, a1, a2); 341 r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get(); 342 return r; 343 } 344 345 template<class T> 346 template<class A0, class A1, class A2, class A3> 347 SharingPtr<T> 348 SharingPtr<T>::make_shared(A0& a0, A1& a1, A2& a2, A3& a3) 349 { 350 typedef imp::shared_ptr_emplace<T> CntrlBlk; 351 SharingPtr<T> r; 352 r.cntrl_ = new CntrlBlk(a0, a1, a2, a3); 353 r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get(); 354 return r; 355 } 356 357 template<class T> 358 template<class A0, class A1, class A2, class A3, class A4> 359 SharingPtr<T> 360 SharingPtr<T>::make_shared(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4) 361 { 362 typedef imp::shared_ptr_emplace<T> CntrlBlk; 363 SharingPtr<T> r; 364 r.cntrl_ = new CntrlBlk(a0, a1, a2, a3, a4); 365 r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get(); 366 return r; 367 } 368 369 template<class T> 370 inline 371 SharingPtr<T> 372 make_shared() 373 { 374 return SharingPtr<T>::make_shared(); 375 } 376 377 template<class T, class A0> 378 inline 379 SharingPtr<T> 380 make_shared(A0& a0) 381 { 382 return SharingPtr<T>::make_shared(a0); 383 } 384 385 template<class T, class A0, class A1> 386 inline 387 SharingPtr<T> 388 make_shared(A0& a0, A1& a1) 389 { 390 return SharingPtr<T>::make_shared(a0, a1); 391 } 392 393 template<class T, class A0, class A1, class A2> 394 inline 395 SharingPtr<T> 396 make_shared(A0& a0, A1& a1, A2& a2) 397 { 398 return SharingPtr<T>::make_shared(a0, a1, a2); 399 } 400 401 template<class T, class A0, class A1, class A2, class A3> 402 inline 403 SharingPtr<T> 404 make_shared(A0& a0, A1& a1, A2& a2, A3& a3) 405 { 406 return SharingPtr<T>::make_shared(a0, a1, a2, a3); 407 } 408 409 template<class T, class A0, class A1, class A2, class A3, class A4> 410 inline 411 SharingPtr<T> 412 make_shared(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4) 413 { 414 return SharingPtr<T>::make_shared(a0, a1, a2, a3, a4); 415 } 416 417 418 template<class T, class U> 419 inline 420 bool 421 operator==(const SharingPtr<T>& __x, const SharingPtr<U>& __y) 422 { 423 return __x.get() == __y.get(); 424 } 425 426 template<class T, class U> 427 inline 428 bool 429 operator!=(const SharingPtr<T>& __x, const SharingPtr<U>& __y) 430 { 431 return !(__x == __y); 432 } 433 434 template<class T, class U> 435 inline 436 bool 437 operator<(const SharingPtr<T>& __x, const SharingPtr<U>& __y) 438 { 439 return __x.get() < __y.get(); 440 } 441 442 template<class T> 443 inline 444 void 445 swap(SharingPtr<T>& __x, SharingPtr<T>& __y) 446 { 447 __x.swap(__y); 448 } 449 450 template<class T, class U> 451 inline 452 SharingPtr<T> 453 static_pointer_cast(const SharingPtr<U>& r) 454 { 455 return SharingPtr<T>(r, static_cast<T*>(r.get())); 456 } 457 458 template<class T, class U> 459 SharingPtr<T> 460 const_pointer_cast(const SharingPtr<U>& r) 461 { 462 return SharingPtr<T>(r, const_cast<T*>(r.get())); 463 } 464 465 template <class T> 466 class LoggingSharingPtr 467 : public SharingPtr<T> 468 { 469 typedef SharingPtr<T> base; 470 471 public: 472 typedef void (*Callback)(void*, const LoggingSharingPtr&, bool action); 473 // action: false means increment just happened 474 // true means decrement is about to happen 475 476 private: 477 Callback cb_; 478 void* baton_; 479 480 public: 481 LoggingSharingPtr() : cb_(0), baton_(0) {} 482 LoggingSharingPtr(Callback cb, void* baton) 483 : cb_(cb), baton_(baton) 484 { 485 if (cb_) 486 cb_(baton_, *this, false); 487 } 488 489 template <class Y> 490 LoggingSharingPtr(Y* p) 491 : base(p), cb_(0), baton_(0) {} 492 493 template <class Y> 494 LoggingSharingPtr(Y* p, Callback cb, void* baton) 495 : base(p), cb_(cb), baton_(baton) 496 { 497 if (cb_) 498 cb_(baton_, *this, false); 499 } 500 501 ~LoggingSharingPtr() 502 { 503 if (cb_) 504 cb_(baton_, *this, true); 505 } 506 507 LoggingSharingPtr(const LoggingSharingPtr& p) 508 : base(p), cb_(p.cb_), baton_(p.baton_) 509 { 510 if (cb_) 511 cb_(baton_, *this, false); 512 } 513 514 LoggingSharingPtr& operator=(const LoggingSharingPtr& p) 515 { 516 if (cb_) 517 cb_(baton_, *this, true); 518 base::operator=(p); 519 cb_ = p.cb_; 520 baton_ = p.baton_; 521 if (cb_) 522 cb_(baton_, *this, false); 523 return *this; 524 } 525 526 void reset() 527 { 528 if (cb_) 529 cb_(baton_, *this, true); 530 base::reset(); 531 } 532 533 template <class Y> 534 void reset(Y* p) 535 { 536 if (cb_) 537 cb_(baton_, *this, true); 538 base::reset(p); 539 if (cb_) 540 cb_(baton_, *this, false); 541 } 542 543 void SetCallback(Callback cb, void* baton) 544 { 545 cb_ = cb; 546 baton_ = baton; 547 } 548 549 void ClearCallback() 550 { 551 cb_ = 0; 552 baton_ = 0; 553 } 554 }; 555 556 557 template <class T> 558 class IntrusiveSharingPtr; 559 560 template <class T> 561 class ReferenceCountedBase 562 { 563 public: 564 explicit ReferenceCountedBase() 565 : shared_owners_(-1) 566 { 567 } 568 569 void 570 add_shared(); 571 572 void 573 release_shared(); 574 575 long 576 use_count() const 577 { 578 return shared_owners_ + 1; 579 } 580 581 protected: 582 long shared_owners_; 583 584 friend class IntrusiveSharingPtr<T>; 585 586 private: 587 ReferenceCountedBase(const ReferenceCountedBase&); 588 ReferenceCountedBase& operator=(const ReferenceCountedBase&); 589 }; 590 591 template <class T> 592 void 593 lldb_private::ReferenceCountedBase<T>::add_shared() 594 { 595 imp::increment(shared_owners_); 596 } 597 598 template <class T> 599 void 600 lldb_private::ReferenceCountedBase<T>::release_shared() 601 { 602 if (imp::decrement(shared_owners_) == -1) 603 delete static_cast<T*>(this); 604 } 605 606 607 template <class T> 608 class ReferenceCountedBaseVirtual : public imp::shared_count 609 { 610 public: 611 explicit ReferenceCountedBaseVirtual () : 612 imp::shared_count(-1) 613 { 614 } 615 616 virtual 617 ~ReferenceCountedBaseVirtual () 618 { 619 } 620 621 virtual void on_zero_shared (); 622 623 }; 624 625 template <class T> 626 void 627 ReferenceCountedBaseVirtual<T>::on_zero_shared() 628 { 629 } 630 631 template <typename T> 632 class IntrusiveSharingPtr 633 { 634 public: 635 typedef T element_type; 636 637 explicit 638 IntrusiveSharingPtr () : 639 ptr_(0) 640 { 641 } 642 643 explicit 644 IntrusiveSharingPtr (T* ptr) : 645 ptr_(ptr) 646 { 647 add_shared(); 648 } 649 650 IntrusiveSharingPtr (const IntrusiveSharingPtr& rhs) : 651 ptr_(rhs.ptr_) 652 { 653 add_shared(); 654 } 655 656 template <class X> 657 IntrusiveSharingPtr (const IntrusiveSharingPtr<X>& rhs) 658 : ptr_(rhs.get()) 659 { 660 add_shared(); 661 } 662 663 IntrusiveSharingPtr& 664 operator= (const IntrusiveSharingPtr& rhs) 665 { 666 reset(rhs.get()); 667 return *this; 668 } 669 670 template <class X> IntrusiveSharingPtr& 671 operator= (const IntrusiveSharingPtr<X>& rhs) 672 { 673 reset(rhs.get()); 674 return *this; 675 } 676 677 IntrusiveSharingPtr& 678 operator= (T *ptr) 679 { 680 reset(ptr); 681 return *this; 682 } 683 684 ~IntrusiveSharingPtr() 685 { 686 release_shared(); 687 #if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE) 688 // NULL out the pointer in objects which can help with leaks detection. 689 // We don't enable this for LLDB_CONFIGURATION_BUILD_AND_INTEGRATION or 690 // when none of the LLDB_CONFIGURATION_XXX macros are defined since 691 // those would be builds for release. But for debug and release builds 692 // that are for development, we NULL out the pointers to catch potential 693 // issues. 694 ptr_ = NULL; 695 #endif // #if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE) 696 } 697 698 T& 699 operator*() const 700 { 701 return *ptr_; 702 } 703 704 T* 705 operator->() const 706 { 707 return ptr_; 708 } 709 710 T* 711 get() const 712 { 713 return ptr_; 714 } 715 716 operator bool() const 717 { 718 return ptr_ != 0; 719 } 720 721 void 722 swap (IntrusiveSharingPtr& rhs) 723 { 724 std::swap(ptr_, rhs.ptr_); 725 #if defined (ENABLE_SP_LOGGING) 726 track_sp (this, ptr_, use_count()); 727 track_sp (&rhs, rhs.ptr_, rhs.use_count()); 728 #endif 729 } 730 731 void 732 reset(T* ptr = NULL) 733 { 734 IntrusiveSharingPtr(ptr).swap(*this); 735 } 736 737 long 738 use_count () const 739 { 740 if (ptr_) 741 return ptr_->use_count(); 742 return 0; 743 } 744 745 bool 746 unique () const 747 { 748 return use_count () == 1; 749 } 750 751 private: 752 element_type *ptr_; 753 754 void 755 add_shared() 756 { 757 if (ptr_) 758 { 759 ptr_->add_shared(); 760 #if defined (ENABLE_SP_LOGGING) 761 track_sp (this, ptr_, ptr_->use_count()); 762 #endif 763 } 764 } 765 void 766 release_shared() 767 { 768 if (ptr_) 769 { 770 #if defined (ENABLE_SP_LOGGING) 771 track_sp (this, NULL, ptr_->use_count() - 1); 772 #endif 773 ptr_->release_shared(); 774 } 775 } 776 }; 777 778 template<class T, class U> 779 inline bool operator== (const IntrusiveSharingPtr<T>& lhs, const IntrusiveSharingPtr<U>& rhs) 780 { 781 return lhs.get() == rhs.get(); 782 } 783 784 template<class T, class U> 785 inline bool operator!= (const IntrusiveSharingPtr<T>& lhs, const IntrusiveSharingPtr<U>& rhs) 786 { 787 return lhs.get() != rhs.get(); 788 } 789 790 template<class T, class U> 791 inline bool operator== (const IntrusiveSharingPtr<T>& lhs, U* rhs) 792 { 793 return lhs.get() == rhs; 794 } 795 796 template<class T, class U> 797 inline bool operator!= (const IntrusiveSharingPtr<T>& lhs, U* rhs) 798 { 799 return lhs.get() != rhs; 800 } 801 802 template<class T, class U> 803 inline bool operator== (T* lhs, const IntrusiveSharingPtr<U>& rhs) 804 { 805 return lhs == rhs.get(); 806 } 807 808 template<class T, class U> 809 inline bool operator!= (T* lhs, const IntrusiveSharingPtr<U>& rhs) 810 { 811 return lhs != rhs.get(); 812 } 813 814 } // namespace lldb_private 815 816 #endif // utility_SharingPtr_h_ 817