1 //===---------------------SharingPtr.h --------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef utility_SharingPtr_h_
10 #define utility_SharingPtr_h_
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
26 //#define ENABLE_SP_LOGGING 1 // DON'T CHECK THIS LINE IN UNLESS COMMENTED OUT
27 #if defined(ENABLE_SP_LOGGING)
29 extern "C" void track_sp(void *sp_this, void *ptr, long count);
33 namespace lldb_private {
38 shared_count(const shared_count &) = delete;
39 shared_count &operator=(const shared_count &) = delete;
42 explicit shared_count(long refs = 0) : shared_owners_(refs) {}
45 void release_shared();
46 long use_count() const { return shared_owners_ + 1; }
52 std::atomic<long> shared_owners_;
54 virtual ~shared_count();
57 virtual void on_zero_shared() = 0;
60 template <class T> class shared_ptr_pointer : public shared_count {
64 shared_ptr_pointer(T p) : data_(p) {}
67 void on_zero_shared() override;
69 shared_ptr_pointer(const shared_ptr_pointer &) = delete;
70 shared_ptr_pointer &operator=(const shared_ptr_pointer &) = delete;
73 template <class T> void shared_ptr_pointer<T>::on_zero_shared() {
77 template <class T> class shared_ptr_emplace : public shared_count {
81 shared_ptr_emplace() : data_() {}
83 template <class A0> shared_ptr_emplace(A0 &a0) : data_(a0) {}
85 template <class A0, class A1>
86 shared_ptr_emplace(A0 &a0, A1 &a1) : data_(a0, a1) {}
88 template <class A0, class A1, class A2>
89 shared_ptr_emplace(A0 &a0, A1 &a1, A2 &a2) : data_(a0, a1, a2) {}
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) {}
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) {}
99 void on_zero_shared() override;
102 T *get() { return &data_; }
105 template <class T> void shared_ptr_emplace<T>::on_zero_shared() {}
109 template <class T> class SharingPtr {
111 typedef T element_type;
115 imp::shared_count *cntrl_;
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);
132 SharingPtr &operator=(const SharingPtr &r);
133 template <class Y> SharingPtr &operator=(const SharingPtr<Y> &r);
135 void swap(SharingPtr &r);
137 template <class Y> void reset(Y *p);
138 void reset(std::nullptr_t);
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(); }
148 static SharingPtr<T> make_shared();
150 template <class A0> static SharingPtr<T> make_shared(A0 &);
152 template <class A0, class A1> static SharingPtr<T> make_shared(A0 &, A1 &);
154 template <class A0, class A1, class A2>
155 static SharingPtr<T> make_shared(A0 &, A1 &, A2 &);
157 template <class A0, class A1, class A2, class A3>
158 static SharingPtr<T> make_shared(A0 &, A1 &, A2 &, A3 &);
160 template <class A0, class A1, class A2, class A3, class A4>
161 static SharingPtr<T> make_shared(A0 &, A1 &, A2 &, A3 &, A4 &);
164 template <class U> friend class SharingPtr;
168 inline SharingPtr<T>::SharingPtr() : ptr_(nullptr), cntrl_(nullptr) {}
171 inline SharingPtr<T>::SharingPtr(std::nullptr_t)
172 : ptr_(nullptr), cntrl_(nullptr) {}
176 SharingPtr<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);
185 SharingPtr<T>::SharingPtr(Y *p, imp::shared_count *cntrl_block)
186 : ptr_(p), cntrl_(cntrl_block) {}
190 inline SharingPtr<T>::SharingPtr(const SharingPtr<Y> &r, element_type *p)
191 : ptr_(p), cntrl_(r.cntrl_) {
193 cntrl_->add_shared();
197 inline SharingPtr<T>::SharingPtr(const SharingPtr &r)
198 : ptr_(r.ptr_), cntrl_(r.cntrl_) {
200 cntrl_->add_shared();
205 inline SharingPtr<T>::SharingPtr(const SharingPtr<Y> &r)
206 : ptr_(r.ptr_), cntrl_(r.cntrl_) {
208 cntrl_->add_shared();
211 template <class T> SharingPtr<T>::~SharingPtr() {
213 cntrl_->release_shared();
217 inline SharingPtr<T> &SharingPtr<T>::operator=(const SharingPtr &r) {
218 SharingPtr(r).swap(*this);
224 inline SharingPtr<T> &SharingPtr<T>::operator=(const SharingPtr<Y> &r) {
225 SharingPtr(r).swap(*this);
229 template <class T> inline void SharingPtr<T>::swap(SharingPtr &r) {
230 std::swap(ptr_, r.ptr_);
231 std::swap(cntrl_, r.cntrl_);
234 template <class T> inline void SharingPtr<T>::reset() {
235 SharingPtr().swap(*this);
238 template <class T> inline void SharingPtr<T>::reset(std::nullptr_t p) {
242 template <class T> template <class Y> inline void SharingPtr<T>::reset(Y *p) {
243 SharingPtr(p).swap(*this);
246 template <class T> SharingPtr<T> SharingPtr<T>::make_shared() {
247 typedef imp::shared_ptr_emplace<T> CntrlBlk;
249 r.cntrl_ = new CntrlBlk();
250 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get();
256 SharingPtr<T> SharingPtr<T>::make_shared(A0 &a0) {
257 typedef imp::shared_ptr_emplace<T> CntrlBlk;
259 r.cntrl_ = new CntrlBlk(a0);
260 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get();
265 template <class A0, class A1>
266 SharingPtr<T> SharingPtr<T>::make_shared(A0 &a0, A1 &a1) {
267 typedef imp::shared_ptr_emplace<T> CntrlBlk;
269 r.cntrl_ = new CntrlBlk(a0, a1);
270 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get();
275 template <class A0, class A1, class A2>
276 SharingPtr<T> SharingPtr<T>::make_shared(A0 &a0, A1 &a1, A2 &a2) {
277 typedef imp::shared_ptr_emplace<T> CntrlBlk;
279 r.cntrl_ = new CntrlBlk(a0, a1, a2);
280 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get();
285 template <class A0, class A1, class A2, class A3>
286 SharingPtr<T> SharingPtr<T>::make_shared(A0 &a0, A1 &a1, A2 &a2, A3 &a3) {
287 typedef imp::shared_ptr_emplace<T> CntrlBlk;
289 r.cntrl_ = new CntrlBlk(a0, a1, a2, a3);
290 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get();
295 template <class A0, class A1, class A2, class A3, class A4>
296 SharingPtr<T> SharingPtr<T>::make_shared(A0 &a0, A1 &a1, A2 &a2, A3 &a3,
298 typedef imp::shared_ptr_emplace<T> CntrlBlk;
300 r.cntrl_ = new CntrlBlk(a0, a1, a2, a3, a4);
301 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get();
305 template <class T> inline SharingPtr<T> make_shared() {
306 return SharingPtr<T>::make_shared();
309 template <class T, class A0> inline SharingPtr<T> make_shared(A0 &a0) {
310 return SharingPtr<T>::make_shared(a0);
313 template <class T, class A0, class A1>
314 inline SharingPtr<T> make_shared(A0 &a0, A1 &a1) {
315 return SharingPtr<T>::make_shared(a0, a1);
318 template <class T, class A0, class A1, class A2>
319 inline SharingPtr<T> make_shared(A0 &a0, A1 &a1, A2 &a2) {
320 return SharingPtr<T>::make_shared(a0, a1, a2);
323 template <class T, class A0, class A1, class A2, class A3>
324 inline SharingPtr<T> make_shared(A0 &a0, A1 &a1, A2 &a2, A3 &a3) {
325 return SharingPtr<T>::make_shared(a0, a1, a2, a3);
328 template <class T, class A0, class A1, class A2, class A3, class A4>
329 inline 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);
333 template <class T, class U>
334 inline bool operator==(const SharingPtr<T> &__x, const SharingPtr<U> &__y) {
335 return __x.get() == __y.get();
338 template <class T, class U>
339 inline bool operator!=(const SharingPtr<T> &__x, const SharingPtr<U> &__y) {
340 return !(__x == __y);
343 template <class T, class U>
344 inline bool operator<(const SharingPtr<T> &__x, const SharingPtr<U> &__y) {
345 return __x.get() < __y.get();
348 template <class T> inline void swap(SharingPtr<T> &__x, SharingPtr<T> &__y) {
352 template <class T, class U>
353 inline SharingPtr<T> static_pointer_cast(const SharingPtr<U> &r) {
354 return SharingPtr<T>(r, static_cast<T *>(r.get()));
357 template <class T, class U>
358 SharingPtr<T> const_pointer_cast(const SharingPtr<U> &r) {
359 return SharingPtr<T>(r, const_cast<T *>(r.get()));
362 template <class T> class LoggingSharingPtr : public SharingPtr<T> {
363 typedef SharingPtr<T> base;
366 typedef void (*Callback)(void *, const LoggingSharingPtr &, bool action);
367 // action: false means increment just happened
368 // true means decrement is about to happen
370 LoggingSharingPtr() : cb_(0), baton_(nullptr) {}
372 LoggingSharingPtr(Callback cb, void *baton) : cb_(cb), baton_(baton) {
374 cb_(baton_, *this, false);
378 LoggingSharingPtr(Y *p) : base(p), cb_(0), baton_(nullptr) {}
381 LoggingSharingPtr(Y *p, Callback cb, void *baton)
382 : base(p), cb_(cb), baton_(baton) {
384 cb_(baton_, *this, false);
387 ~LoggingSharingPtr() {
389 cb_(baton_, *this, true);
392 LoggingSharingPtr(const LoggingSharingPtr &p)
393 : base(p), cb_(p.cb_), baton_(p.baton_) {
395 cb_(baton_, *this, false);
398 LoggingSharingPtr &operator=(const LoggingSharingPtr &p) {
400 cb_(baton_, *this, true);
405 cb_(baton_, *this, false);
411 cb_(baton_, *this, true);
415 template <class Y> void reset(Y *p) {
417 cb_(baton_, *this, true);
420 cb_(baton_, *this, false);
423 void SetCallback(Callback cb, void *baton) {
428 void ClearCallback() {
438 template <class T> class IntrusiveSharingPtr;
440 template <class T> class ReferenceCountedBase {
442 explicit ReferenceCountedBase() : shared_owners_(-1) {}
446 void release_shared();
448 long use_count() const { return shared_owners_ + 1; }
453 friend class IntrusiveSharingPtr<T>;
456 ReferenceCountedBase(const ReferenceCountedBase &) = delete;
457 ReferenceCountedBase &operator=(const ReferenceCountedBase &) = delete;
460 template <class T> void lldb_private::ReferenceCountedBase<T>::add_shared() {
462 _InterlockedIncrement(&shared_owners_);
469 void lldb_private::ReferenceCountedBase<T>::release_shared() {
471 if (_InterlockedDecrement(&shared_owners_) == -1)
473 if (--shared_owners_ == -1)
475 delete static_cast<T *>(this);
479 class ReferenceCountedBaseVirtual : public imp::shared_count {
481 explicit ReferenceCountedBaseVirtual() : imp::shared_count(-1) {}
483 ~ReferenceCountedBaseVirtual() override = default;
485 void on_zero_shared() override;
488 template <class T> void ReferenceCountedBaseVirtual<T>::on_zero_shared() {}
490 template <typename T> class IntrusiveSharingPtr {
492 typedef T element_type;
494 explicit IntrusiveSharingPtr() : ptr_(0) {}
496 explicit IntrusiveSharingPtr(T *ptr) : ptr_(ptr) { add_shared(); }
498 IntrusiveSharingPtr(const IntrusiveSharingPtr &rhs) : ptr_(rhs.ptr_) {
503 IntrusiveSharingPtr(const IntrusiveSharingPtr<X> &rhs) : ptr_(rhs.get()) {
507 IntrusiveSharingPtr &operator=(const IntrusiveSharingPtr &rhs) {
513 IntrusiveSharingPtr &operator=(const IntrusiveSharingPtr<X> &rhs) {
518 IntrusiveSharingPtr &operator=(T *ptr) {
523 ~IntrusiveSharingPtr() {
528 T &operator*() const { return *ptr_; }
530 T *operator->() const { return ptr_; }
532 T *get() const { return ptr_; }
534 explicit operator bool() const { return ptr_ != 0; }
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());
544 void reset(T *ptr = nullptr) { IntrusiveSharingPtr(ptr).swap(*this); }
546 long use_count() const {
548 return ptr_->use_count();
552 bool unique() const { return use_count() == 1; }
560 #if defined(ENABLE_SP_LOGGING)
561 track_sp(this, ptr_, ptr_->use_count());
565 void release_shared() {
567 #if defined(ENABLE_SP_LOGGING)
568 track_sp(this, nullptr, ptr_->use_count() - 1);
570 ptr_->release_shared();
575 template <class T, class U>
576 inline bool operator==(const IntrusiveSharingPtr<T> &lhs,
577 const IntrusiveSharingPtr<U> &rhs) {
578 return lhs.get() == rhs.get();
581 template <class T, class U>
582 inline bool operator!=(const IntrusiveSharingPtr<T> &lhs,
583 const IntrusiveSharingPtr<U> &rhs) {
584 return lhs.get() != rhs.get();
587 template <class T, class U>
588 inline bool operator==(const IntrusiveSharingPtr<T> &lhs, U *rhs) {
589 return lhs.get() == rhs;
592 template <class T, class U>
593 inline bool operator!=(const IntrusiveSharingPtr<T> &lhs, U *rhs) {
594 return lhs.get() != rhs;
597 template <class T, class U>
598 inline bool operator==(T *lhs, const IntrusiveSharingPtr<U> &rhs) {
599 return lhs == rhs.get();
602 template <class T, class U>
603 inline bool operator!=(T *lhs, const IntrusiveSharingPtr<U> &rhs) {
604 return lhs != rhs.get();
607 } // namespace lldb_private
609 #endif // utility_SharingPtr_h_