SharingPtr.h revision 102b2c2681c9a830afe25bfea35557421905e42c
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 19extern "C" void track_sp (void *sp_this, void *ptr, long count); 20 21#endif 22 23namespace lldb_private { 24 25namespace imp { 26 27template <class T> 28inline T 29increment(T& t) 30{ 31 return __sync_add_and_fetch(&t, 1); 32} 33 34template <class T> 35inline T 36decrement(T& t) 37{ 38 return __sync_add_and_fetch(&t, -1); 39} 40 41class shared_count 42{ 43 shared_count(const shared_count&); 44 shared_count& operator=(const shared_count&); 45 46protected: 47 long shared_owners_; 48 virtual ~shared_count(); 49private: 50 virtual void on_zero_shared() = 0; 51 52public: 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 61template <class T> 62class shared_ptr_pointer 63 : public shared_count 64{ 65 T data_; 66public: 67 shared_ptr_pointer(T p) 68 : data_(p) {} 69 70private: 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 79template <class T> 80void 81shared_ptr_pointer<T>::on_zero_shared() 82{ 83 delete data_; 84} 85 86template <class T> 87class shared_ptr_emplace 88 : public shared_count 89{ 90 T data_; 91public: 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 116private: 117 virtual void on_zero_shared(); 118public: 119 T* get() {return &data_;} 120}; 121 122template <class T> 123void 124shared_ptr_emplace<T>::on_zero_shared() 125{ 126} 127 128} // namespace 129 130template<class T> 131class SharingPtr 132{ 133public: 134 typedef T element_type; 135private: 136 element_type* ptr_; 137 imp::shared_count* cntrl_; 138 139 struct nat {int for_bool_;}; 140public: 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 183private: 184 185 template <class U> friend class SharingPtr; 186}; 187 188template<class T> 189inline 190SharingPtr<T>::SharingPtr() 191 : ptr_(0), 192 cntrl_(0) 193{ 194} 195 196template<class T> 197template<class Y> 198SharingPtr<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 207template<class T> 208template<class Y> 209SharingPtr<T>::SharingPtr(Y* p, imp::shared_count *cntrl_block) 210 : ptr_(p), cntrl_(cntrl_block) 211{ 212} 213 214template<class T> 215template<class Y> 216inline 217SharingPtr<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 225template<class T> 226inline 227SharingPtr<T>::SharingPtr(const SharingPtr& r) 228 : ptr_(r.ptr_), 229 cntrl_(r.cntrl_) 230{ 231 if (cntrl_) 232 cntrl_->add_shared(); 233} 234 235template<class T> 236template<class Y> 237inline 238SharingPtr<T>::SharingPtr(const SharingPtr<Y>& r) 239 : ptr_(r.ptr_), 240 cntrl_(r.cntrl_) 241{ 242 if (cntrl_) 243 cntrl_->add_shared(); 244} 245 246template<class T> 247SharingPtr<T>::~SharingPtr() 248{ 249 if (cntrl_) 250 cntrl_->release_shared(); 251} 252 253template<class T> 254inline 255SharingPtr<T>& 256SharingPtr<T>::operator=(const SharingPtr& r) 257{ 258 SharingPtr(r).swap(*this); 259 return *this; 260} 261 262template<class T> 263template<class Y> 264inline 265SharingPtr<T>& 266SharingPtr<T>::operator=(const SharingPtr<Y>& r) 267{ 268 SharingPtr(r).swap(*this); 269 return *this; 270} 271 272template<class T> 273inline 274void 275SharingPtr<T>::swap(SharingPtr& r) 276{ 277 std::swap(ptr_, r.ptr_); 278 std::swap(cntrl_, r.cntrl_); 279} 280 281template<class T> 282inline 283void 284SharingPtr<T>::reset() 285{ 286 SharingPtr().swap(*this); 287} 288 289template<class T> 290template<class Y> 291inline 292void 293SharingPtr<T>::reset(Y* p) 294{ 295 SharingPtr(p).swap(*this); 296} 297 298template<class T> 299SharingPtr<T> 300SharingPtr<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 309template<class T> 310template<class A0> 311SharingPtr<T> 312SharingPtr<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 321template<class T> 322template<class A0, class A1> 323SharingPtr<T> 324SharingPtr<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 333template<class T> 334template<class A0, class A1, class A2> 335SharingPtr<T> 336SharingPtr<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 345template<class T> 346template<class A0, class A1, class A2, class A3> 347SharingPtr<T> 348SharingPtr<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 357template<class T> 358template<class A0, class A1, class A2, class A3, class A4> 359SharingPtr<T> 360SharingPtr<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 369template<class T> 370inline 371SharingPtr<T> 372make_shared() 373{ 374 return SharingPtr<T>::make_shared(); 375} 376 377template<class T, class A0> 378inline 379SharingPtr<T> 380make_shared(A0& a0) 381{ 382 return SharingPtr<T>::make_shared(a0); 383} 384 385template<class T, class A0, class A1> 386inline 387SharingPtr<T> 388make_shared(A0& a0, A1& a1) 389{ 390 return SharingPtr<T>::make_shared(a0, a1); 391} 392 393template<class T, class A0, class A1, class A2> 394inline 395SharingPtr<T> 396make_shared(A0& a0, A1& a1, A2& a2) 397{ 398 return SharingPtr<T>::make_shared(a0, a1, a2); 399} 400 401template<class T, class A0, class A1, class A2, class A3> 402inline 403SharingPtr<T> 404make_shared(A0& a0, A1& a1, A2& a2, A3& a3) 405{ 406 return SharingPtr<T>::make_shared(a0, a1, a2, a3); 407} 408 409template<class T, class A0, class A1, class A2, class A3, class A4> 410inline 411SharingPtr<T> 412make_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 418template<class T, class U> 419inline 420bool 421operator==(const SharingPtr<T>& __x, const SharingPtr<U>& __y) 422{ 423 return __x.get() == __y.get(); 424} 425 426template<class T, class U> 427inline 428bool 429operator!=(const SharingPtr<T>& __x, const SharingPtr<U>& __y) 430{ 431 return !(__x == __y); 432} 433 434template<class T, class U> 435inline 436bool 437operator<(const SharingPtr<T>& __x, const SharingPtr<U>& __y) 438{ 439 return __x.get() < __y.get(); 440} 441 442template<class T> 443inline 444void 445swap(SharingPtr<T>& __x, SharingPtr<T>& __y) 446{ 447 __x.swap(__y); 448} 449 450template<class T, class U> 451inline 452SharingPtr<T> 453static_pointer_cast(const SharingPtr<U>& r) 454{ 455 return SharingPtr<T>(r, static_cast<T*>(r.get())); 456} 457 458template<class T, class U> 459SharingPtr<T> 460const_pointer_cast(const SharingPtr<U>& r) 461{ 462 return SharingPtr<T>(r, const_cast<T*>(r.get())); 463} 464 465template <class T> 466class LoggingSharingPtr 467 : public SharingPtr<T> 468{ 469 typedef SharingPtr<T> base; 470 471public: 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 476private: 477 Callback cb_; 478 void* baton_; 479 480public: 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 557template <class T> 558class IntrusiveSharingPtr; 559 560template <class T> 561class ReferenceCountedBase 562{ 563public: 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 581protected: 582 long shared_owners_; 583 584 friend class IntrusiveSharingPtr<T>; 585 586private: 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 607template <class T> 608class ReferenceCountedBaseVirtual : public imp::shared_count 609{ 610public: 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 625template <class T> 626void 627ReferenceCountedBaseVirtual<T>::on_zero_shared() 628{ 629} 630 631template <typename T> 632class IntrusiveSharingPtr 633{ 634public: 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 751private: 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 778template<class T, class U> 779inline bool operator== (const IntrusiveSharingPtr<T>& lhs, const IntrusiveSharingPtr<U>& rhs) 780{ 781 return lhs.get() == rhs.get(); 782} 783 784template<class T, class U> 785inline bool operator!= (const IntrusiveSharingPtr<T>& lhs, const IntrusiveSharingPtr<U>& rhs) 786{ 787 return lhs.get() != rhs.get(); 788} 789 790template<class T, class U> 791inline bool operator== (const IntrusiveSharingPtr<T>& lhs, U* rhs) 792{ 793 return lhs.get() == rhs; 794} 795 796template<class T, class U> 797inline bool operator!= (const IntrusiveSharingPtr<T>& lhs, U* rhs) 798{ 799 return lhs.get() != rhs; 800} 801 802template<class T, class U> 803inline bool operator== (T* lhs, const IntrusiveSharingPtr<U>& rhs) 804{ 805 return lhs == rhs.get(); 806} 807 808template<class T, class U> 809inline 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