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