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