SharingPtr.h revision 321369
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
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
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#if defined(LLDB_CONFIGURATION_DEBUG) || defined(LLDB_CONFIGURATION_RELEASE)
533    // NULL out the pointer in objects which can help with leaks detection.
534    // We don't enable this for LLDB_CONFIGURATION_BUILD_AND_INTEGRATION or
535    // when none of the LLDB_CONFIGURATION_XXX macros are defined since
536    // those would be builds for release. But for debug and release builds
537    // that are for development, we NULL out the pointers to catch potential
538    // issues.
539    ptr_ = nullptr;
540#endif // #if defined (LLDB_CONFIGURATION_DEBUG) || defined
541       // (LLDB_CONFIGURATION_RELEASE)
542  }
543
544  T &operator*() const { return *ptr_; }
545
546  T *operator->() const { return ptr_; }
547
548  T *get() const { return ptr_; }
549
550  explicit operator bool() const { return ptr_ != 0; }
551
552  void swap(IntrusiveSharingPtr &rhs) {
553    std::swap(ptr_, rhs.ptr_);
554#if defined(ENABLE_SP_LOGGING)
555    track_sp(this, ptr_, use_count());
556    track_sp(&rhs, rhs.ptr_, rhs.use_count());
557#endif
558  }
559
560  void reset(T *ptr = nullptr) { IntrusiveSharingPtr(ptr).swap(*this); }
561
562  long use_count() const {
563    if (ptr_)
564      return ptr_->use_count();
565    return 0;
566  }
567
568  bool unique() const { return use_count() == 1; }
569
570private:
571  element_type *ptr_;
572
573  void add_shared() {
574    if (ptr_) {
575      ptr_->add_shared();
576#if defined(ENABLE_SP_LOGGING)
577      track_sp(this, ptr_, ptr_->use_count());
578#endif
579    }
580  }
581  void release_shared() {
582    if (ptr_) {
583#if defined(ENABLE_SP_LOGGING)
584      track_sp(this, nullptr, ptr_->use_count() - 1);
585#endif
586      ptr_->release_shared();
587    }
588  }
589};
590
591template <class T, class U>
592inline bool operator==(const IntrusiveSharingPtr<T> &lhs,
593                       const IntrusiveSharingPtr<U> &rhs) {
594  return lhs.get() == rhs.get();
595}
596
597template <class T, class U>
598inline bool operator!=(const IntrusiveSharingPtr<T> &lhs,
599                       const IntrusiveSharingPtr<U> &rhs) {
600  return lhs.get() != rhs.get();
601}
602
603template <class T, class U>
604inline bool operator==(const IntrusiveSharingPtr<T> &lhs, U *rhs) {
605  return lhs.get() == rhs;
606}
607
608template <class T, class U>
609inline bool operator!=(const IntrusiveSharingPtr<T> &lhs, U *rhs) {
610  return lhs.get() != rhs;
611}
612
613template <class T, class U>
614inline bool operator==(T *lhs, const IntrusiveSharingPtr<U> &rhs) {
615  return lhs == rhs.get();
616}
617
618template <class T, class U>
619inline bool operator!=(T *lhs, const IntrusiveSharingPtr<U> &rhs) {
620  return lhs != rhs.get();
621}
622
623} // namespace lldb_private
624
625#endif // utility_SharingPtr_h_
626