File Coverage

src/panda/refcnt.h
Criterion Covered Total %
statement 20 20 100.0
branch 12 14 85.7
condition n/a
subroutine n/a
pod n/a
total 32 34 94.1


line stmt bran cond sub pod time code
1             #pragma once
2             #include "cast.h"
3             #include "traits.h"
4             #include
5             #include
6             #include
7             #include
8              
9             namespace panda {
10              
11             using std::nullptr_t;
12              
13             template
14             struct iptr {
15             template friend struct iptr;
16             typedef T element_type;
17              
18 447           iptr () : ptr(NULL) {}
19             iptr (T* pointer) : ptr(pointer) { if (ptr) refcnt_inc(ptr); }
20 70 100         iptr (const iptr& oth) : ptr(oth.ptr) { if (ptr) refcnt_inc(ptr); }
21              
22             template >
23             iptr (const iptr& oth) : ptr(oth.ptr) { if (ptr) refcnt_inc(ptr); }
24              
25             iptr (iptr&& oth) {
26             ptr = oth.ptr;
27             oth.ptr = NULL;
28             }
29              
30             template >
31             iptr (iptr&& oth) {
32             ptr = oth.ptr;
33             oth.ptr = NULL;
34             }
35              
36 1024 100         ~iptr () { if (ptr) refcnt_dec(ptr); }
37              
38 29           iptr& operator= (T* pointer) {
39 29 100         if (pointer) refcnt_inc(pointer);
40 29 100         if (ptr) refcnt_dec(ptr);
41 29           ptr = pointer;
42 29           return *this;
43             }
44              
45             iptr& operator= (const iptr& oth) { return operator=(oth.ptr); }
46              
47             template >
48             iptr& operator= (const iptr& oth) { return operator=(oth.ptr); }
49              
50             iptr& operator= (iptr&& oth) {
51             std::swap(ptr, oth.ptr);
52             return *this;
53             }
54              
55             template >
56             iptr& operator= (iptr&& oth) {
57             if (ptr) {
58             if (ptr == oth.ptr) return *this;
59             refcnt_dec(ptr);
60             }
61             ptr = oth.ptr;
62             oth.ptr = NULL;
63             return *this;
64             }
65              
66             void reset () {
67             if (ptr) refcnt_dec(ptr);
68             ptr = NULL;
69             }
70              
71             void reset (T* p) { operator=(p); }
72              
73 112           T* operator-> () const noexcept { return ptr; }
74             T& operator* () const noexcept { return *ptr; }
75             operator T* () const noexcept { return ptr; }
76              
77             explicit
78 1048           operator bool () const noexcept { return ptr; }
79              
80             T* get () const noexcept { return ptr; }
81              
82             uint32_t use_count () const noexcept { return refcnt_get(ptr); }
83              
84             T* detach () noexcept {
85             auto ret = ptr;
86             ptr = nullptr;
87             return ret;
88             }
89              
90             void swap (iptr& oth) noexcept {
91             std::swap(ptr, oth.ptr);
92             }
93              
94             private:
95             T* ptr;
96             };
97              
98             template inline bool operator== (const iptr& x, const iptr& y) { return x.get() == y.get(); }
99             template inline bool operator!= (const iptr& x, const iptr& y) { return x.get() != y.get(); }
100             template inline bool operator< (const iptr& x, const iptr& y) { return x.get() < y.get(); }
101             template inline bool operator<= (const iptr& x, const iptr& y) { return x.get() <= y.get(); }
102             template inline bool operator> (const iptr& x, const iptr& y) { return x.get() > y.get(); }
103             template inline bool operator>= (const iptr& x, const iptr& y) { return x.get() >= y.get(); }
104              
105             template inline bool operator== (const iptr& x, nullptr_t) noexcept { return !x.get(); }
106             template inline bool operator== (nullptr_t, const iptr& x) noexcept { return !x.get(); }
107             template inline bool operator!= (const iptr& x, nullptr_t) noexcept { return x.get(); }
108             template inline bool operator!= (nullptr_t, const iptr& x) noexcept { return x.get(); }
109             template inline bool operator< (const iptr& x, nullptr_t) noexcept { return x.get() < nullptr; }
110             template inline bool operator< (nullptr_t, const iptr& x) noexcept { return nullptr < x.get(); }
111             template inline bool operator<= (const iptr& x, nullptr_t) noexcept { return x.get() <= nullptr; }
112             template inline bool operator<= (nullptr_t, const iptr& x) noexcept { return nullptr <= x.get(); }
113             template inline bool operator> (const iptr& x, nullptr_t) noexcept { return x.get() > nullptr; }
114             template inline bool operator> (nullptr_t, const iptr& x) noexcept { return nullptr > x.get(); }
115             template inline bool operator>= (const iptr& x, nullptr_t) noexcept { return x.get() >= nullptr; }
116             template inline bool operator>= (nullptr_t, const iptr& x) noexcept { return nullptr >= x.get(); }
117              
118             template
119             iptr make_iptr (Args&&... args) {
120             return iptr(new T(std::forward(args)...));
121             }
122              
123             template
124             void swap (iptr& a, iptr& b) noexcept { a.swap(b); }
125              
126             struct weak_storage;
127              
128             struct Refcnt {
129 1606           void retain () const { ++_refcnt; }
130 1606           void release () const {
131 1606 100         if (_refcnt > 1) --_refcnt;
132 438 50         else delete this;
133 1606           }
134             uint32_t refcnt () const noexcept { return _refcnt; }
135              
136             protected:
137 894           Refcnt () : _refcnt(0) {}
138             virtual ~Refcnt ();
139              
140             private:
141             friend iptr refcnt_weak (const Refcnt*);
142              
143             mutable uint32_t _refcnt;
144             mutable iptr _weak;
145              
146             iptr get_weak () const;
147             };
148              
149             struct Refcntd : Refcnt {
150             void release () const {
151             if (refcnt() <= 1) const_cast(this)->on_delete();
152             Refcnt::release();
153             }
154              
155             protected:
156             virtual void on_delete () noexcept {}
157             };
158              
159 96 50         struct weak_storage : public Refcnt {
160 48           weak_storage () : valid(true) {}
161             bool valid;
162             };
163              
164 3210           inline void refcnt_inc (const Refcnt* o) { o->retain(); }
165             inline void refcnt_dec (const Refcntd* o) { o->release(); }
166 3206           inline void refcnt_dec (const Refcnt* o) { o->release(); }
167             inline uint32_t refcnt_get (const Refcnt* o) { return o->refcnt(); }
168             inline iptr refcnt_weak (const Refcnt* o) { return o->get_weak(); }
169              
170             template inline iptr static_pointer_cast (const iptr& ptr) { return iptr(static_cast(ptr.get())); }
171             template inline iptr const_pointer_cast (const iptr& ptr) { return iptr(const_cast(ptr.get())); }
172             template inline iptr dynamic_pointer_cast (const iptr& ptr) { return iptr(dyn_cast(ptr.get())); }
173              
174             template inline std::shared_ptr static_pointer_cast (const std::shared_ptr& shptr) { return std::static_pointer_cast(shptr); }
175             template inline std::shared_ptr const_pointer_cast (const std::shared_ptr& shptr) { return std::const_pointer_cast(shptr); }
176             template inline std::shared_ptr dynamic_pointer_cast (const std::shared_ptr& shptr) { return std::dynamic_pointer_cast(shptr); }
177              
178             template
179             struct weak_iptr {
180             template friend struct weak_iptr;
181             typedef T element_type;
182              
183             weak_iptr() : storage(nullptr), object(nullptr) {}
184             weak_iptr(const weak_iptr&) = default;
185             weak_iptr& operator=(const weak_iptr& o) = default;
186              
187             weak_iptr(weak_iptr&&) = default;
188             weak_iptr& operator=(weak_iptr&& o) = default;
189              
190             template >
191             weak_iptr(const iptr& src) : storage(src ? refcnt_weak(src.get()) : nullptr), object(src ? src.get() : nullptr) {}
192              
193             template >
194             weak_iptr(const weak_iptr& src) : storage(src.storage), object(src.object) {}
195              
196             template
197             weak_iptr& operator=(const weak_iptr& o) {
198             storage = o.storage;
199             object = o.object;
200             return *this;
201             }
202              
203             template
204             weak_iptr& operator=(const iptr& src) {
205             storage = src ? refcnt_weak(src.get()) : nullptr;
206             object = src ? src.get() : nullptr;
207             return *this;
208             }
209              
210             template
211             weak_iptr& operator=(weak_iptr&& o) {
212             storage = std::move(o.storage);
213             object = std::move(o.object);
214             return *this;
215             }
216              
217             iptr lock() const {
218             return expired() ? nullptr : object;
219             }
220              
221             bool expired() const {
222             return !operator bool();
223             }
224              
225             explicit operator bool() const {
226             return storage && storage->valid;
227             }
228              
229             size_t use_count() const {
230             return *this ? refcnt_get(object) : 0;
231             }
232              
233             size_t weak_count() const {
234             if (!storage) return 0;
235             if (storage->valid) return storage.use_count() - 1; // object itself refers to weak storage, ignore this reference in count
236             return storage.use_count();
237             }
238              
239             void reset() noexcept {
240             storage.reset();
241             object = nullptr;
242             }
243              
244             void swap(weak_iptr& oth) noexcept {
245             storage.swap(oth.storage);
246             std::swap(object, oth.object);
247             }
248              
249             private:
250             iptr storage;
251             T* object; // it is cache, it never invalidates itself, use storage->object to check validity
252             };
253              
254             template
255             void swap(weak_iptr& a, weak_iptr& b) noexcept { a.swap(b); }
256              
257             template struct _weak_t;
258             template struct _weak_t> {
259             using type = weak_iptr;
260             };
261              
262             template
263             using weak = typename _weak_t::type;
264              
265             }