]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/include/lldb/Utility/SharingPtr.h
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / include / lldb / Utility / SharingPtr.h
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 in CLR
18 // mode - as such we need to "hack around it" for MSVC++ builds only using
19 // 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
34 extern "C" void track_sp(void *sp_this, void *ptr, long count);
35
36 #endif
37
38 namespace lldb_private {
39
40 namespace imp {
41
42 class shared_count {
43   shared_count(const shared_count &);
44   shared_count &operator=(const shared_count &);
45
46 public:
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
53 protected:
54 #ifdef _MSC_VER
55   long shared_owners_;
56 #else
57   std::atomic<long> shared_owners_;
58 #endif
59   virtual ~shared_count();
60
61 private:
62   virtual void on_zero_shared() = 0;
63 };
64
65 template <class T> class shared_ptr_pointer : public shared_count {
66   T data_;
67
68 public:
69   shared_ptr_pointer(T p) : data_(p) {}
70
71 private:
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
80 template <class T> void shared_ptr_pointer<T>::on_zero_shared() {
81   delete data_;
82 }
83
84 template <class T> class shared_ptr_emplace : public shared_count {
85   T data_;
86
87 public:
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
105 private:
106   void on_zero_shared() override;
107
108 public:
109   T *get() { return &data_; }
110 };
111
112 template <class T> void shared_ptr_emplace<T>::on_zero_shared() {}
113
114 } // namespace imp
115
116 template <class T> class SharingPtr {
117 public:
118   typedef T element_type;
119
120 private:
121   element_type *ptr_;
122   imp::shared_count *cntrl_;
123
124   struct nat {
125     int for_bool_;
126   };
127
128 public:
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
170 private:
171   template <class U> friend class SharingPtr;
172 };
173
174 template <class T>
175 inline SharingPtr<T>::SharingPtr() : ptr_(nullptr), cntrl_(nullptr) {}
176
177 template <class T>
178 inline SharingPtr<T>::SharingPtr(std::nullptr_t)
179     : ptr_(nullptr), cntrl_(nullptr) {}
180
181 template <class T>
182 template <class Y>
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);
187   hold.release();
188 }
189
190 template <class T>
191 template <class Y>
192 SharingPtr<T>::SharingPtr(Y *p, imp::shared_count *cntrl_block)
193     : ptr_(p), cntrl_(cntrl_block) {}
194
195 template <class T>
196 template <class Y>
197 inline 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
203 template <class T>
204 inline SharingPtr<T>::SharingPtr(const SharingPtr &r)
205     : ptr_(r.ptr_), cntrl_(r.cntrl_) {
206   if (cntrl_)
207     cntrl_->add_shared();
208 }
209
210 template <class T>
211 template <class Y>
212 inline SharingPtr<T>::SharingPtr(const SharingPtr<Y> &r)
213     : ptr_(r.ptr_), cntrl_(r.cntrl_) {
214   if (cntrl_)
215     cntrl_->add_shared();
216 }
217
218 template <class T> SharingPtr<T>::~SharingPtr() {
219   if (cntrl_)
220     cntrl_->release_shared();
221 }
222
223 template <class T>
224 inline SharingPtr<T> &SharingPtr<T>::operator=(const SharingPtr &r) {
225   SharingPtr(r).swap(*this);
226   return *this;
227 }
228
229 template <class T>
230 template <class Y>
231 inline SharingPtr<T> &SharingPtr<T>::operator=(const SharingPtr<Y> &r) {
232   SharingPtr(r).swap(*this);
233   return *this;
234 }
235
236 template <class T> inline void SharingPtr<T>::swap(SharingPtr &r) {
237   std::swap(ptr_, r.ptr_);
238   std::swap(cntrl_, r.cntrl_);
239 }
240
241 template <class T> inline void SharingPtr<T>::reset() {
242   SharingPtr().swap(*this);
243 }
244
245 template <class T> inline void SharingPtr<T>::reset(std::nullptr_t p) {
246   reset();
247 }
248
249 template <class T> template <class Y> inline void SharingPtr<T>::reset(Y *p) {
250   SharingPtr(p).swap(*this);
251 }
252
253 template <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
261 template <class T>
262 template <class A0>
263 SharingPtr<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
271 template <class T>
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;
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
281 template <class T>
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;
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
291 template <class T>
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;
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
301 template <class T>
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,
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
312 template <class T> inline SharingPtr<T> make_shared() {
313   return SharingPtr<T>::make_shared();
314 }
315
316 template <class T, class A0> inline SharingPtr<T> make_shared(A0 &a0) {
317   return SharingPtr<T>::make_shared(a0);
318 }
319
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);
323 }
324
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);
328 }
329
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);
333 }
334
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);
338 }
339
340 template <class T, class U>
341 inline bool operator==(const SharingPtr<T> &__x, const SharingPtr<U> &__y) {
342   return __x.get() == __y.get();
343 }
344
345 template <class T, class U>
346 inline bool operator!=(const SharingPtr<T> &__x, const SharingPtr<U> &__y) {
347   return !(__x == __y);
348 }
349
350 template <class T, class U>
351 inline bool operator<(const SharingPtr<T> &__x, const SharingPtr<U> &__y) {
352   return __x.get() < __y.get();
353 }
354
355 template <class T> inline void swap(SharingPtr<T> &__x, SharingPtr<T> &__y) {
356   __x.swap(__y);
357 }
358
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()));
362 }
363
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()));
367 }
368
369 template <class T> class LoggingSharingPtr : public SharingPtr<T> {
370   typedef SharingPtr<T> base;
371
372 public:
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
440 private:
441   Callback cb_;
442   void *baton_;
443 };
444
445 template <class T> class IntrusiveSharingPtr;
446
447 template <class T> class ReferenceCountedBase {
448 public:
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
457 protected:
458   long shared_owners_;
459
460   friend class IntrusiveSharingPtr<T>;
461
462 private:
463   ReferenceCountedBase(const ReferenceCountedBase &);
464   ReferenceCountedBase &operator=(const ReferenceCountedBase &);
465 };
466
467 template <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
475 template <class T>
476 void 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
485 template <class T>
486 class ReferenceCountedBaseVirtual : public imp::shared_count {
487 public:
488   explicit ReferenceCountedBaseVirtual() : imp::shared_count(-1) {}
489
490   ~ReferenceCountedBaseVirtual() override = default;
491
492   void on_zero_shared() override;
493 };
494
495 template <class T> void ReferenceCountedBaseVirtual<T>::on_zero_shared() {}
496
497 template <typename T> class IntrusiveSharingPtr {
498 public:
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     ptr_ = nullptr;
533   }
534
535   T &operator*() const { return *ptr_; }
536
537   T *operator->() const { return ptr_; }
538
539   T *get() const { return ptr_; }
540
541   explicit operator bool() const { return ptr_ != 0; }
542
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());
548 #endif
549   }
550
551   void reset(T *ptr = nullptr) { IntrusiveSharingPtr(ptr).swap(*this); }
552
553   long use_count() const {
554     if (ptr_)
555       return ptr_->use_count();
556     return 0;
557   }
558
559   bool unique() const { return use_count() == 1; }
560
561 private:
562   element_type *ptr_;
563
564   void add_shared() {
565     if (ptr_) {
566       ptr_->add_shared();
567 #if defined(ENABLE_SP_LOGGING)
568       track_sp(this, ptr_, ptr_->use_count());
569 #endif
570     }
571   }
572   void release_shared() {
573     if (ptr_) {
574 #if defined(ENABLE_SP_LOGGING)
575       track_sp(this, nullptr, ptr_->use_count() - 1);
576 #endif
577       ptr_->release_shared();
578     }
579   }
580 };
581
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();
586 }
587
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();
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!=(const IntrusiveSharingPtr<T> &lhs, U *rhs) {
601   return lhs.get() != rhs;
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 template <class T, class U>
610 inline bool operator!=(T *lhs, const IntrusiveSharingPtr<U> &rhs) {
611   return lhs != rhs.get();
612 }
613
614 } // namespace lldb_private
615
616 #endif // utility_SharingPtr_h_