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