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