1 //===---------------------SharingPtr.h --------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #ifndef utility_SharingPtr_h_
11 #define utility_SharingPtr_h_
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
28 // Other libraries and framework includes
31 //#define ENABLE_SP_LOGGING 1 // DON'T CHECK THIS LINE IN UNLESS COMMENTED OUT
32 #if defined(ENABLE_SP_LOGGING)
34 extern "C" void track_sp(void *sp_this, void *ptr, long count);
38 namespace lldb_private {
43 shared_count(const shared_count &);
44 shared_count &operator=(const shared_count &);
47 explicit shared_count(long refs = 0) : shared_owners_(refs) {}
50 void release_shared();
51 long use_count() const { return shared_owners_ + 1; }
57 std::atomic<long> shared_owners_;
59 virtual ~shared_count();
62 virtual void on_zero_shared() = 0;
65 template <class T> class shared_ptr_pointer : public shared_count {
69 shared_ptr_pointer(T p) : data_(p) {}
72 void on_zero_shared() override;
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 &);
80 template <class T> void shared_ptr_pointer<T>::on_zero_shared() {
84 template <class T> class shared_ptr_emplace : public shared_count {
88 shared_ptr_emplace() : data_() {}
90 template <class A0> shared_ptr_emplace(A0 &a0) : data_(a0) {}
92 template <class A0, class A1>
93 shared_ptr_emplace(A0 &a0, A1 &a1) : data_(a0, a1) {}
95 template <class A0, class A1, class A2>
96 shared_ptr_emplace(A0 &a0, A1 &a1, A2 &a2) : data_(a0, a1, a2) {}
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) {}
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) {}
106 void on_zero_shared() override;
109 T *get() { return &data_; }
112 template <class T> void shared_ptr_emplace<T>::on_zero_shared() {}
116 template <class T> class SharingPtr {
118 typedef T element_type;
122 imp::shared_count *cntrl_;
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);
139 SharingPtr &operator=(const SharingPtr &r);
140 template <class Y> SharingPtr &operator=(const SharingPtr<Y> &r);
142 void swap(SharingPtr &r);
144 template <class Y> void reset(Y *p);
145 void reset(std::nullptr_t);
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(); }
155 static SharingPtr<T> make_shared();
157 template <class A0> static SharingPtr<T> make_shared(A0 &);
159 template <class A0, class A1> static SharingPtr<T> make_shared(A0 &, A1 &);
161 template <class A0, class A1, class A2>
162 static SharingPtr<T> make_shared(A0 &, A1 &, A2 &);
164 template <class A0, class A1, class A2, class A3>
165 static SharingPtr<T> make_shared(A0 &, A1 &, A2 &, A3 &);
167 template <class A0, class A1, class A2, class A3, class A4>
168 static SharingPtr<T> make_shared(A0 &, A1 &, A2 &, A3 &, A4 &);
171 template <class U> friend class SharingPtr;
175 inline SharingPtr<T>::SharingPtr() : ptr_(nullptr), cntrl_(nullptr) {}
178 inline SharingPtr<T>::SharingPtr(std::nullptr_t)
179 : ptr_(nullptr), cntrl_(nullptr) {}
183 SharingPtr<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);
192 SharingPtr<T>::SharingPtr(Y *p, imp::shared_count *cntrl_block)
193 : ptr_(p), cntrl_(cntrl_block) {}
197 inline SharingPtr<T>::SharingPtr(const SharingPtr<Y> &r, element_type *p)
198 : ptr_(p), cntrl_(r.cntrl_) {
200 cntrl_->add_shared();
204 inline SharingPtr<T>::SharingPtr(const SharingPtr &r)
205 : ptr_(r.ptr_), cntrl_(r.cntrl_) {
207 cntrl_->add_shared();
212 inline SharingPtr<T>::SharingPtr(const SharingPtr<Y> &r)
213 : ptr_(r.ptr_), cntrl_(r.cntrl_) {
215 cntrl_->add_shared();
218 template <class T> SharingPtr<T>::~SharingPtr() {
220 cntrl_->release_shared();
224 inline SharingPtr<T> &SharingPtr<T>::operator=(const SharingPtr &r) {
225 SharingPtr(r).swap(*this);
231 inline SharingPtr<T> &SharingPtr<T>::operator=(const SharingPtr<Y> &r) {
232 SharingPtr(r).swap(*this);
236 template <class T> inline void SharingPtr<T>::swap(SharingPtr &r) {
237 std::swap(ptr_, r.ptr_);
238 std::swap(cntrl_, r.cntrl_);
241 template <class T> inline void SharingPtr<T>::reset() {
242 SharingPtr().swap(*this);
245 template <class T> inline void SharingPtr<T>::reset(std::nullptr_t p) {
249 template <class T> template <class Y> inline void SharingPtr<T>::reset(Y *p) {
250 SharingPtr(p).swap(*this);
253 template <class T> SharingPtr<T> SharingPtr<T>::make_shared() {
254 typedef imp::shared_ptr_emplace<T> CntrlBlk;
256 r.cntrl_ = new CntrlBlk();
257 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get();
263 SharingPtr<T> SharingPtr<T>::make_shared(A0 &a0) {
264 typedef imp::shared_ptr_emplace<T> CntrlBlk;
266 r.cntrl_ = new CntrlBlk(a0);
267 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get();
272 template <class A0, class A1>
273 SharingPtr<T> SharingPtr<T>::make_shared(A0 &a0, A1 &a1) {
274 typedef imp::shared_ptr_emplace<T> CntrlBlk;
276 r.cntrl_ = new CntrlBlk(a0, a1);
277 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get();
282 template <class A0, class A1, class A2>
283 SharingPtr<T> SharingPtr<T>::make_shared(A0 &a0, A1 &a1, A2 &a2) {
284 typedef imp::shared_ptr_emplace<T> CntrlBlk;
286 r.cntrl_ = new CntrlBlk(a0, a1, a2);
287 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get();
292 template <class A0, class A1, class A2, class A3>
293 SharingPtr<T> SharingPtr<T>::make_shared(A0 &a0, A1 &a1, A2 &a2, A3 &a3) {
294 typedef imp::shared_ptr_emplace<T> CntrlBlk;
296 r.cntrl_ = new CntrlBlk(a0, a1, a2, a3);
297 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get();
302 template <class A0, class A1, class A2, class A3, class A4>
303 SharingPtr<T> SharingPtr<T>::make_shared(A0 &a0, A1 &a1, A2 &a2, A3 &a3,
305 typedef imp::shared_ptr_emplace<T> CntrlBlk;
307 r.cntrl_ = new CntrlBlk(a0, a1, a2, a3, a4);
308 r.ptr_ = static_cast<CntrlBlk *>(r.cntrl_)->get();
312 template <class T> inline SharingPtr<T> make_shared() {
313 return SharingPtr<T>::make_shared();
316 template <class T, class A0> inline SharingPtr<T> make_shared(A0 &a0) {
317 return SharingPtr<T>::make_shared(a0);
320 template <class T, class A0, class A1>
321 inline SharingPtr<T> make_shared(A0 &a0, A1 &a1) {
322 return SharingPtr<T>::make_shared(a0, a1);
325 template <class T, class A0, class A1, class A2>
326 inline SharingPtr<T> make_shared(A0 &a0, A1 &a1, A2 &a2) {
327 return SharingPtr<T>::make_shared(a0, a1, a2);
330 template <class T, class A0, class A1, class A2, class A3>
331 inline SharingPtr<T> make_shared(A0 &a0, A1 &a1, A2 &a2, A3 &a3) {
332 return SharingPtr<T>::make_shared(a0, a1, a2, a3);
335 template <class T, class A0, class A1, class A2, class A3, class A4>
336 inline 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);
340 template <class T, class U>
341 inline bool operator==(const SharingPtr<T> &__x, const SharingPtr<U> &__y) {
342 return __x.get() == __y.get();
345 template <class T, class U>
346 inline bool operator!=(const SharingPtr<T> &__x, const SharingPtr<U> &__y) {
347 return !(__x == __y);
350 template <class T, class U>
351 inline bool operator<(const SharingPtr<T> &__x, const SharingPtr<U> &__y) {
352 return __x.get() < __y.get();
355 template <class T> inline void swap(SharingPtr<T> &__x, SharingPtr<T> &__y) {
359 template <class T, class U>
360 inline SharingPtr<T> static_pointer_cast(const SharingPtr<U> &r) {
361 return SharingPtr<T>(r, static_cast<T *>(r.get()));
364 template <class T, class U>
365 SharingPtr<T> const_pointer_cast(const SharingPtr<U> &r) {
366 return SharingPtr<T>(r, const_cast<T *>(r.get()));
369 template <class T> class LoggingSharingPtr : public SharingPtr<T> {
370 typedef SharingPtr<T> base;
373 typedef void (*Callback)(void *, const LoggingSharingPtr &, bool action);
374 // action: false means increment just happened
375 // true means decrement is about to happen
377 LoggingSharingPtr() : cb_(0), baton_(nullptr) {}
379 LoggingSharingPtr(Callback cb, void *baton) : cb_(cb), baton_(baton) {
381 cb_(baton_, *this, false);
385 LoggingSharingPtr(Y *p) : base(p), cb_(0), baton_(nullptr) {}
388 LoggingSharingPtr(Y *p, Callback cb, void *baton)
389 : base(p), cb_(cb), baton_(baton) {
391 cb_(baton_, *this, false);
394 ~LoggingSharingPtr() {
396 cb_(baton_, *this, true);
399 LoggingSharingPtr(const LoggingSharingPtr &p)
400 : base(p), cb_(p.cb_), baton_(p.baton_) {
402 cb_(baton_, *this, false);
405 LoggingSharingPtr &operator=(const LoggingSharingPtr &p) {
407 cb_(baton_, *this, true);
412 cb_(baton_, *this, false);
418 cb_(baton_, *this, true);
422 template <class Y> void reset(Y *p) {
424 cb_(baton_, *this, true);
427 cb_(baton_, *this, false);
430 void SetCallback(Callback cb, void *baton) {
435 void ClearCallback() {
445 template <class T> class IntrusiveSharingPtr;
447 template <class T> class ReferenceCountedBase {
449 explicit ReferenceCountedBase() : shared_owners_(-1) {}
453 void release_shared();
455 long use_count() const { return shared_owners_ + 1; }
460 friend class IntrusiveSharingPtr<T>;
463 ReferenceCountedBase(const ReferenceCountedBase &);
464 ReferenceCountedBase &operator=(const ReferenceCountedBase &);
467 template <class T> void lldb_private::ReferenceCountedBase<T>::add_shared() {
469 _InterlockedIncrement(&shared_owners_);
476 void lldb_private::ReferenceCountedBase<T>::release_shared() {
478 if (_InterlockedDecrement(&shared_owners_) == -1)
480 if (--shared_owners_ == -1)
482 delete static_cast<T *>(this);
486 class ReferenceCountedBaseVirtual : public imp::shared_count {
488 explicit ReferenceCountedBaseVirtual() : imp::shared_count(-1) {}
490 ~ReferenceCountedBaseVirtual() override = default;
492 void on_zero_shared() override;
495 template <class T> void ReferenceCountedBaseVirtual<T>::on_zero_shared() {}
497 template <typename T> class IntrusiveSharingPtr {
499 typedef T element_type;
501 explicit IntrusiveSharingPtr() : ptr_(0) {}
503 explicit IntrusiveSharingPtr(T *ptr) : ptr_(ptr) { add_shared(); }
505 IntrusiveSharingPtr(const IntrusiveSharingPtr &rhs) : ptr_(rhs.ptr_) {
510 IntrusiveSharingPtr(const IntrusiveSharingPtr<X> &rhs) : ptr_(rhs.get()) {
514 IntrusiveSharingPtr &operator=(const IntrusiveSharingPtr &rhs) {
520 IntrusiveSharingPtr &operator=(const IntrusiveSharingPtr<X> &rhs) {
525 IntrusiveSharingPtr &operator=(T *ptr) {
530 ~IntrusiveSharingPtr() {
535 T &operator*() const { return *ptr_; }
537 T *operator->() const { return ptr_; }
539 T *get() const { return ptr_; }
541 explicit operator bool() const { return ptr_ != 0; }
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());
551 void reset(T *ptr = nullptr) { IntrusiveSharingPtr(ptr).swap(*this); }
553 long use_count() const {
555 return ptr_->use_count();
559 bool unique() const { return use_count() == 1; }
567 #if defined(ENABLE_SP_LOGGING)
568 track_sp(this, ptr_, ptr_->use_count());
572 void release_shared() {
574 #if defined(ENABLE_SP_LOGGING)
575 track_sp(this, nullptr, ptr_->use_count() - 1);
577 ptr_->release_shared();
582 template <class T, class U>
583 inline bool operator==(const IntrusiveSharingPtr<T> &lhs,
584 const IntrusiveSharingPtr<U> &rhs) {
585 return lhs.get() == rhs.get();
588 template <class T, class U>
589 inline bool operator!=(const IntrusiveSharingPtr<T> &lhs,
590 const IntrusiveSharingPtr<U> &rhs) {
591 return lhs.get() != rhs.get();
594 template <class T, class U>
595 inline bool operator==(const IntrusiveSharingPtr<T> &lhs, U *rhs) {
596 return lhs.get() == rhs;
599 template <class T, class U>
600 inline bool operator!=(const IntrusiveSharingPtr<T> &lhs, U *rhs) {
601 return lhs.get() != rhs;
604 template <class T, class U>
605 inline bool operator==(T *lhs, const IntrusiveSharingPtr<U> &rhs) {
606 return lhs == rhs.get();
609 template <class T, class U>
610 inline bool operator!=(T *lhs, const IntrusiveSharingPtr<U> &rhs) {
611 return lhs != rhs.get();
614 } // namespace lldb_private
616 #endif // utility_SharingPtr_h_