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