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