SharingPtr.h revision 321369
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 <memory> 16 17// Microsoft Visual C++ currently does not enable std::atomic to work 18// in CLR mode - as such we need to "hack around it" for MSVC++ builds only 19// using Windows specific intrinsics instead of the C++11 atomic support 20#ifdef _MSC_VER 21#include <intrin.h> 22#else 23#include <atomic> 24#endif 25 26#include <stddef.h> 27 28// Other libraries and framework includes 29// Project includes 30 31//#define ENABLE_SP_LOGGING 1 // DON'T CHECK THIS LINE IN UNLESS COMMENTED OUT 32#if defined(ENABLE_SP_LOGGING) 33 34extern "C" void track_sp(void *sp_this, void *ptr, long count); 35 36#endif 37 38namespace lldb_private { 39 40namespace imp { 41 42class shared_count { 43 shared_count(const shared_count &); 44 shared_count &operator=(const shared_count &); 45 46public: 47 explicit shared_count(long refs = 0) : shared_owners_(refs) {} 48 49 void add_shared(); 50 void release_shared(); 51 long use_count() const { return shared_owners_ + 1; } 52 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> class shared_ptr_pointer : public shared_count { 66 T data_; 67 68public: 69 shared_ptr_pointer(T p) : data_(p) {} 70 71private: 72 void on_zero_shared() override; 73 74 // Outlaw copy constructor and assignment operator to keep effective C++ 75 // warnings down to a minimum 76 shared_ptr_pointer(const shared_ptr_pointer &); 77 shared_ptr_pointer &operator=(const shared_ptr_pointer &); 78}; 79 80template <class T> void shared_ptr_pointer<T>::on_zero_shared() { 81 delete data_; 82} 83 84template <class T> class shared_ptr_emplace : public shared_count { 85 T data_; 86 87public: 88 shared_ptr_emplace() : data_() {} 89 90 template <class A0> shared_ptr_emplace(A0 &a0) : data_(a0) {} 91 92 template <class A0, class A1> 93 shared_ptr_emplace(A0 &a0, A1 &a1) : data_(a0, a1) {} 94 95 template <class A0, class A1, class A2> 96 shared_ptr_emplace(A0 &a0, A1 &a1, A2 &a2) : data_(a0, a1, a2) {} 97 98 template <class A0, class A1, class A2, class A3> 99 shared_ptr_emplace(A0 &a0, A1 &a1, A2 &a2, A3 &a3) : data_(a0, a1, a2, a3) {} 100 101 template <class A0, class A1, class A2, class A3, class A4> 102 shared_ptr_emplace(A0 &a0, A1 &a1, A2 &a2, A3 &a3, A4 &a4) 103 : data_(a0, a1, a2, a3, a4) {} 104 105private: 106 void on_zero_shared() override; 107 108public: 109 T *get() { return &data_; } 110}; 111 112template <class T> void shared_ptr_emplace<T>::on_zero_shared() {} 113 114} // namespace imp 115 116template <class T> class SharingPtr { 117public: 118 typedef T element_type; 119 120private: 121 element_type *ptr_; 122 imp::shared_count *cntrl_; 123 124 struct nat { 125 int for_bool_; 126 }; 127 128public: 129 SharingPtr(); 130 SharingPtr(std::nullptr_t); 131 template <class Y> explicit SharingPtr(Y *p); 132 template <class Y> explicit SharingPtr(Y *p, imp::shared_count *ctrl_block); 133 template <class Y> SharingPtr(const SharingPtr<Y> &r, element_type *p); 134 SharingPtr(const SharingPtr &r); 135 template <class Y> SharingPtr(const SharingPtr<Y> &r); 136 137 ~SharingPtr(); 138 139 SharingPtr &operator=(const SharingPtr &r); 140 template <class Y> SharingPtr &operator=(const SharingPtr<Y> &r); 141 142 void swap(SharingPtr &r); 143 void reset(); 144 template <class Y> void reset(Y *p); 145 void reset(std::nullptr_t); 146 147 element_type *get() const { return ptr_; } 148 element_type &operator*() const { return *ptr_; } 149 element_type *operator->() const { return ptr_; } 150 long use_count() const { return cntrl_ ? cntrl_->use_count() : 0; } 151 bool unique() const { return use_count() == 1; } 152 bool empty() const { return cntrl_ == nullptr; } 153 operator nat *() const { return (nat *)get(); } 154 155 static SharingPtr<T> make_shared(); 156 157 template <class A0> static SharingPtr<T> make_shared(A0 &); 158 159 template <class A0, class A1> static SharingPtr<T> make_shared(A0 &, A1 &); 160 161 template <class A0, class A1, class A2> 162 static SharingPtr<T> make_shared(A0 &, A1 &, A2 &); 163 164 template <class A0, class A1, class A2, class A3> 165 static SharingPtr<T> make_shared(A0 &, A1 &, A2 &, A3 &); 166 167 template <class A0, class A1, class A2, class A3, class A4> 168 static SharingPtr<T> make_shared(A0 &, A1 &, A2 &, A3 &, A4 &); 169 170private: 171 template <class U> friend class SharingPtr; 172}; 173 174template <class T> 175inline SharingPtr<T>::SharingPtr() : ptr_(nullptr), cntrl_(nullptr) {} 176 177template <class T> 178inline SharingPtr<T>::SharingPtr(std::nullptr_t) 179 : ptr_(nullptr), cntrl_(nullptr) {} 180 181template <class T> 182template <class Y> 183SharingPtr<T>::SharingPtr(Y *p) : ptr_(p), cntrl_(nullptr) { 184 std::unique_ptr<Y> hold(p); 185 typedef imp::shared_ptr_pointer<Y *> _CntrlBlk; 186 cntrl_ = new _CntrlBlk(p); 187 hold.release(); 188} 189 190template <class T> 191template <class Y> 192SharingPtr<T>::SharingPtr(Y *p, imp::shared_count *cntrl_block) 193 : ptr_(p), cntrl_(cntrl_block) {} 194 195template <class T> 196template <class Y> 197inline SharingPtr<T>::SharingPtr(const SharingPtr<Y> &r, element_type *p) 198 : ptr_(p), cntrl_(r.cntrl_) { 199 if (cntrl_) 200 cntrl_->add_shared(); 201} 202 203template <class T> 204inline SharingPtr<T>::SharingPtr(const SharingPtr &r) 205 : ptr_(r.ptr_), cntrl_(r.cntrl_) { 206 if (cntrl_) 207 cntrl_->add_shared(); 208} 209 210template <class T> 211template <class Y> 212inline SharingPtr<T>::SharingPtr(const SharingPtr<Y> &r) 213 : ptr_(r.ptr_), cntrl_(r.cntrl_) { 214 if (cntrl_) 215 cntrl_->add_shared(); 216} 217 218template <class T> SharingPtr<T>::~SharingPtr() { 219 if (cntrl_) 220 cntrl_->release_shared(); 221} 222 223template <class T> 224inline SharingPtr<T> &SharingPtr<T>::operator=(const SharingPtr &r) { 225 SharingPtr(r).swap(*this); 226 return *this; 227} 228 229template <class T> 230template <class Y> 231inline SharingPtr<T> &SharingPtr<T>::operator=(const SharingPtr<Y> &r) { 232 SharingPtr(r).swap(*this); 233 return *this; 234} 235 236template <class T> inline void SharingPtr<T>::swap(SharingPtr &r) { 237 std::swap(ptr_, r.ptr_); 238 std::swap(cntrl_, r.cntrl_); 239} 240 241template <class T> inline void SharingPtr<T>::reset() { 242 SharingPtr().swap(*this); 243} 244 245template <class T> inline void SharingPtr<T>::reset(std::nullptr_t p) { 246 reset(); 247} 248 249template <class T> template <class Y> inline void SharingPtr<T>::reset(Y *p) { 250 SharingPtr(p).swap(*this); 251} 252 253template <class T> SharingPtr<T> SharingPtr<T>::make_shared() { 254 typedef imp::shared_ptr_emplace<T> CntrlBlk; 255 SharingPtr<T> r; 256 r.cntrl_ = new CntrlBlk(); 257 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get(); 258 return r; 259} 260 261template <class T> 262template <class A0> 263SharingPtr<T> SharingPtr<T>::make_shared(A0 &a0) { 264 typedef imp::shared_ptr_emplace<T> CntrlBlk; 265 SharingPtr<T> r; 266 r.cntrl_ = new CntrlBlk(a0); 267 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get(); 268 return r; 269} 270 271template <class T> 272template <class A0, class A1> 273SharingPtr<T> SharingPtr<T>::make_shared(A0 &a0, A1 &a1) { 274 typedef imp::shared_ptr_emplace<T> CntrlBlk; 275 SharingPtr<T> r; 276 r.cntrl_ = new CntrlBlk(a0, a1); 277 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get(); 278 return r; 279} 280 281template <class T> 282template <class A0, class A1, class A2> 283SharingPtr<T> SharingPtr<T>::make_shared(A0 &a0, A1 &a1, A2 &a2) { 284 typedef imp::shared_ptr_emplace<T> CntrlBlk; 285 SharingPtr<T> r; 286 r.cntrl_ = new CntrlBlk(a0, a1, a2); 287 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get(); 288 return r; 289} 290 291template <class T> 292template <class A0, class A1, class A2, class A3> 293SharingPtr<T> SharingPtr<T>::make_shared(A0 &a0, A1 &a1, A2 &a2, A3 &a3) { 294 typedef imp::shared_ptr_emplace<T> CntrlBlk; 295 SharingPtr<T> r; 296 r.cntrl_ = new CntrlBlk(a0, a1, a2, a3); 297 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get(); 298 return r; 299} 300 301template <class T> 302template <class A0, class A1, class A2, class A3, class A4> 303SharingPtr<T> SharingPtr<T>::make_shared(A0 &a0, A1 &a1, A2 &a2, A3 &a3, 304 A4 &a4) { 305 typedef imp::shared_ptr_emplace<T> CntrlBlk; 306 SharingPtr<T> r; 307 r.cntrl_ = new CntrlBlk(a0, a1, a2, a3, a4); 308 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get(); 309 return r; 310} 311 312template <class T> inline SharingPtr<T> make_shared() { 313 return SharingPtr<T>::make_shared(); 314} 315 316template <class T, class A0> inline SharingPtr<T> make_shared(A0 &a0) { 317 return SharingPtr<T>::make_shared(a0); 318} 319 320template <class T, class A0, class A1> 321inline SharingPtr<T> make_shared(A0 &a0, A1 &a1) { 322 return SharingPtr<T>::make_shared(a0, a1); 323} 324 325template <class T, class A0, class A1, class A2> 326inline SharingPtr<T> make_shared(A0 &a0, A1 &a1, A2 &a2) { 327 return SharingPtr<T>::make_shared(a0, a1, a2); 328} 329 330template <class T, class A0, class A1, class A2, class A3> 331inline SharingPtr<T> make_shared(A0 &a0, A1 &a1, A2 &a2, A3 &a3) { 332 return SharingPtr<T>::make_shared(a0, a1, a2, a3); 333} 334 335template <class T, class A0, class A1, class A2, class A3, class A4> 336inline SharingPtr<T> make_shared(A0 &a0, A1 &a1, A2 &a2, A3 &a3, A4 &a4) { 337 return SharingPtr<T>::make_shared(a0, a1, a2, a3, a4); 338} 339 340template <class T, class U> 341inline bool operator==(const SharingPtr<T> &__x, const SharingPtr<U> &__y) { 342 return __x.get() == __y.get(); 343} 344 345template <class T, class U> 346inline bool operator!=(const SharingPtr<T> &__x, const SharingPtr<U> &__y) { 347 return !(__x == __y); 348} 349 350template <class T, class U> 351inline bool operator<(const SharingPtr<T> &__x, const SharingPtr<U> &__y) { 352 return __x.get() < __y.get(); 353} 354 355template <class T> inline void swap(SharingPtr<T> &__x, SharingPtr<T> &__y) { 356 __x.swap(__y); 357} 358 359template <class T, class U> 360inline SharingPtr<T> static_pointer_cast(const SharingPtr<U> &r) { 361 return SharingPtr<T>(r, static_cast<T *>(r.get())); 362} 363 364template <class T, class U> 365SharingPtr<T> const_pointer_cast(const SharingPtr<U> &r) { 366 return SharingPtr<T>(r, const_cast<T *>(r.get())); 367} 368 369template <class T> class LoggingSharingPtr : public SharingPtr<T> { 370 typedef SharingPtr<T> base; 371 372public: 373 typedef void (*Callback)(void *, const LoggingSharingPtr &, bool action); 374 // action: false means increment just happened 375 // true means decrement is about to happen 376 377 LoggingSharingPtr() : cb_(0), baton_(nullptr) {} 378 379 LoggingSharingPtr(Callback cb, void *baton) : cb_(cb), baton_(baton) { 380 if (cb_) 381 cb_(baton_, *this, false); 382 } 383 384 template <class Y> 385 LoggingSharingPtr(Y *p) : base(p), cb_(0), baton_(nullptr) {} 386 387 template <class Y> 388 LoggingSharingPtr(Y *p, Callback cb, void *baton) 389 : base(p), cb_(cb), baton_(baton) { 390 if (cb_) 391 cb_(baton_, *this, false); 392 } 393 394 ~LoggingSharingPtr() { 395 if (cb_) 396 cb_(baton_, *this, true); 397 } 398 399 LoggingSharingPtr(const LoggingSharingPtr &p) 400 : base(p), cb_(p.cb_), baton_(p.baton_) { 401 if (cb_) 402 cb_(baton_, *this, false); 403 } 404 405 LoggingSharingPtr &operator=(const LoggingSharingPtr &p) { 406 if (cb_) 407 cb_(baton_, *this, true); 408 base::operator=(p); 409 cb_ = p.cb_; 410 baton_ = p.baton_; 411 if (cb_) 412 cb_(baton_, *this, false); 413 return *this; 414 } 415 416 void reset() { 417 if (cb_) 418 cb_(baton_, *this, true); 419 base::reset(); 420 } 421 422 template <class Y> void reset(Y *p) { 423 if (cb_) 424 cb_(baton_, *this, true); 425 base::reset(p); 426 if (cb_) 427 cb_(baton_, *this, false); 428 } 429 430 void SetCallback(Callback cb, void *baton) { 431 cb_ = cb; 432 baton_ = baton; 433 } 434 435 void ClearCallback() { 436 cb_ = 0; 437 baton_ = 0; 438 } 439 440private: 441 Callback cb_; 442 void *baton_; 443}; 444 445template <class T> class IntrusiveSharingPtr; 446 447template <class T> class ReferenceCountedBase { 448public: 449 explicit ReferenceCountedBase() : shared_owners_(-1) {} 450 451 void add_shared(); 452 453 void release_shared(); 454 455 long use_count() const { return shared_owners_ + 1; } 456 457protected: 458 long shared_owners_; 459 460 friend class IntrusiveSharingPtr<T>; 461 462private: 463 ReferenceCountedBase(const ReferenceCountedBase &); 464 ReferenceCountedBase &operator=(const ReferenceCountedBase &); 465}; 466 467template <class T> void lldb_private::ReferenceCountedBase<T>::add_shared() { 468#ifdef _MSC_VER 469 _InterlockedIncrement(&shared_owners_); 470#else 471 ++shared_owners_; 472#endif 473} 474 475template <class T> 476void lldb_private::ReferenceCountedBase<T>::release_shared() { 477#ifdef _MSC_VER 478 if (_InterlockedDecrement(&shared_owners_) == -1) 479#else 480 if (--shared_owners_ == -1) 481#endif 482 delete static_cast<T *>(this); 483} 484 485template <class T> 486class ReferenceCountedBaseVirtual : public imp::shared_count { 487public: 488 explicit ReferenceCountedBaseVirtual() : imp::shared_count(-1) {} 489 490 ~ReferenceCountedBaseVirtual() override = default; 491 492 void on_zero_shared() override; 493}; 494 495template <class T> void ReferenceCountedBaseVirtual<T>::on_zero_shared() {} 496 497template <typename T> class IntrusiveSharingPtr { 498public: 499 typedef T element_type; 500 501 explicit IntrusiveSharingPtr() : ptr_(0) {} 502 503 explicit IntrusiveSharingPtr(T *ptr) : ptr_(ptr) { add_shared(); } 504 505 IntrusiveSharingPtr(const IntrusiveSharingPtr &rhs) : ptr_(rhs.ptr_) { 506 add_shared(); 507 } 508 509 template <class X> 510 IntrusiveSharingPtr(const IntrusiveSharingPtr<X> &rhs) : ptr_(rhs.get()) { 511 add_shared(); 512 } 513 514 IntrusiveSharingPtr &operator=(const IntrusiveSharingPtr &rhs) { 515 reset(rhs.get()); 516 return *this; 517 } 518 519 template <class X> 520 IntrusiveSharingPtr &operator=(const IntrusiveSharingPtr<X> &rhs) { 521 reset(rhs.get()); 522 return *this; 523 } 524 525 IntrusiveSharingPtr &operator=(T *ptr) { 526 reset(ptr); 527 return *this; 528 } 529 530 ~IntrusiveSharingPtr() { 531 release_shared(); 532#if defined(LLDB_CONFIGURATION_DEBUG) || defined(LLDB_CONFIGURATION_RELEASE) 533 // NULL out the pointer in objects which can help with leaks detection. 534 // We don't enable this for LLDB_CONFIGURATION_BUILD_AND_INTEGRATION or 535 // when none of the LLDB_CONFIGURATION_XXX macros are defined since 536 // those would be builds for release. But for debug and release builds 537 // that are for development, we NULL out the pointers to catch potential 538 // issues. 539 ptr_ = nullptr; 540#endif // #if defined (LLDB_CONFIGURATION_DEBUG) || defined 541 // (LLDB_CONFIGURATION_RELEASE) 542 } 543 544 T &operator*() const { return *ptr_; } 545 546 T *operator->() const { return ptr_; } 547 548 T *get() const { return ptr_; } 549 550 explicit operator bool() const { return ptr_ != 0; } 551 552 void swap(IntrusiveSharingPtr &rhs) { 553 std::swap(ptr_, rhs.ptr_); 554#if defined(ENABLE_SP_LOGGING) 555 track_sp(this, ptr_, use_count()); 556 track_sp(&rhs, rhs.ptr_, rhs.use_count()); 557#endif 558 } 559 560 void reset(T *ptr = nullptr) { IntrusiveSharingPtr(ptr).swap(*this); } 561 562 long use_count() const { 563 if (ptr_) 564 return ptr_->use_count(); 565 return 0; 566 } 567 568 bool unique() const { return use_count() == 1; } 569 570private: 571 element_type *ptr_; 572 573 void add_shared() { 574 if (ptr_) { 575 ptr_->add_shared(); 576#if defined(ENABLE_SP_LOGGING) 577 track_sp(this, ptr_, ptr_->use_count()); 578#endif 579 } 580 } 581 void release_shared() { 582 if (ptr_) { 583#if defined(ENABLE_SP_LOGGING) 584 track_sp(this, nullptr, ptr_->use_count() - 1); 585#endif 586 ptr_->release_shared(); 587 } 588 } 589}; 590 591template <class T, class U> 592inline bool operator==(const IntrusiveSharingPtr<T> &lhs, 593 const IntrusiveSharingPtr<U> &rhs) { 594 return lhs.get() == rhs.get(); 595} 596 597template <class T, class U> 598inline bool operator!=(const IntrusiveSharingPtr<T> &lhs, 599 const IntrusiveSharingPtr<U> &rhs) { 600 return lhs.get() != rhs.get(); 601} 602 603template <class T, class U> 604inline bool operator==(const IntrusiveSharingPtr<T> &lhs, U *rhs) { 605 return lhs.get() == rhs; 606} 607 608template <class T, class U> 609inline bool operator!=(const IntrusiveSharingPtr<T> &lhs, U *rhs) { 610 return lhs.get() != rhs; 611} 612 613template <class T, class U> 614inline bool operator==(T *lhs, const IntrusiveSharingPtr<U> &rhs) { 615 return lhs == rhs.get(); 616} 617 618template <class T, class U> 619inline bool operator!=(T *lhs, const IntrusiveSharingPtr<U> &rhs) { 620 return lhs != rhs.get(); 621} 622 623} // namespace lldb_private 624 625#endif // utility_SharingPtr_h_ 626