SharingPtr.h revision 341825
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 in CLR 18// mode - as such we need to "hack around it" for MSVC++ builds only using 19// 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 ptr_ = nullptr; 533 } 534 535 T &operator*() const { return *ptr_; } 536 537 T *operator->() const { return ptr_; } 538 539 T *get() const { return ptr_; } 540 541 explicit operator bool() const { return ptr_ != 0; } 542 543 void swap(IntrusiveSharingPtr &rhs) { 544 std::swap(ptr_, rhs.ptr_); 545#if defined(ENABLE_SP_LOGGING) 546 track_sp(this, ptr_, use_count()); 547 track_sp(&rhs, rhs.ptr_, rhs.use_count()); 548#endif 549 } 550 551 void reset(T *ptr = nullptr) { IntrusiveSharingPtr(ptr).swap(*this); } 552 553 long use_count() const { 554 if (ptr_) 555 return ptr_->use_count(); 556 return 0; 557 } 558 559 bool unique() const { return use_count() == 1; } 560 561private: 562 element_type *ptr_; 563 564 void add_shared() { 565 if (ptr_) { 566 ptr_->add_shared(); 567#if defined(ENABLE_SP_LOGGING) 568 track_sp(this, ptr_, ptr_->use_count()); 569#endif 570 } 571 } 572 void release_shared() { 573 if (ptr_) { 574#if defined(ENABLE_SP_LOGGING) 575 track_sp(this, nullptr, ptr_->use_count() - 1); 576#endif 577 ptr_->release_shared(); 578 } 579 } 580}; 581 582template <class T, class U> 583inline bool operator==(const IntrusiveSharingPtr<T> &lhs, 584 const IntrusiveSharingPtr<U> &rhs) { 585 return lhs.get() == rhs.get(); 586} 587 588template <class T, class U> 589inline bool operator!=(const IntrusiveSharingPtr<T> &lhs, 590 const IntrusiveSharingPtr<U> &rhs) { 591 return lhs.get() != rhs.get(); 592} 593 594template <class T, class U> 595inline bool operator==(const IntrusiveSharingPtr<T> &lhs, U *rhs) { 596 return lhs.get() == rhs; 597} 598 599template <class T, class U> 600inline bool operator!=(const IntrusiveSharingPtr<T> &lhs, U *rhs) { 601 return lhs.get() != rhs; 602} 603 604template <class T, class U> 605inline bool operator==(T *lhs, const IntrusiveSharingPtr<U> &rhs) { 606 return lhs == rhs.get(); 607} 608 609template <class T, class U> 610inline bool operator!=(T *lhs, const IntrusiveSharingPtr<U> &rhs) { 611 return lhs != rhs.get(); 612} 613 614} // namespace lldb_private 615 616#endif // utility_SharingPtr_h_ 617