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