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