• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2013 Francisco Jerez
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 // OTHER DEALINGS IN THE SOFTWARE.
21 //
22 
23 #ifndef CLOVER_UTIL_POINTER_HPP
24 #define CLOVER_UTIL_POINTER_HPP
25 
26 #include <atomic>
27 
28 namespace clover {
29    ///
30    /// Base class for objects that support reference counting.
31    ///
32    class ref_counter {
33    public:
ref_counter(unsigned value=1)34       ref_counter(unsigned value = 1) : _ref_count(value) {}
35 
36       unsigned
ref_count() const37       ref_count() const {
38          return _ref_count;
39       }
40 
41       void
retain()42       retain() {
43          _ref_count++;
44       }
45 
46       bool
release()47       release() {
48          return (--_ref_count) == 0;
49       }
50 
51    private:
52       std::atomic<unsigned> _ref_count;
53    };
54 
55    ///
56    /// Simple reference to a clover::ref_counter object.  Unlike
57    /// clover::intrusive_ptr and clover::intrusive_ref, it does nothing
58    /// special when the reference count drops to zero.
59    ///
60    class ref_holder {
61    public:
ref_holder(ref_counter & o)62       ref_holder(ref_counter &o) : p(&o) {
63          p->retain();
64       }
65 
ref_holder(const ref_holder & ref)66       ref_holder(const ref_holder &ref) :
67          ref_holder(*ref.p) {
68       }
69 
ref_holder(ref_holder && ref)70       ref_holder(ref_holder &&ref) :
71          p(ref.p) {
72          ref.p = NULL;
73       }
74 
~ref_holder()75       ~ref_holder() {
76          if (p)
77             p->release();
78       }
79 
80       ref_holder &
operator =(ref_holder ref)81       operator=(ref_holder ref) {
82          std::swap(ref.p, p);
83          return *this;
84       }
85 
86       bool
operator ==(const ref_holder & ref) const87       operator==(const ref_holder &ref) const {
88          return p == ref.p;
89       }
90 
91       bool
operator !=(const ref_holder & ref) const92       operator!=(const ref_holder &ref) const {
93          return p != ref.p;
94       }
95 
96    private:
97       ref_counter *p;
98    };
99 
100    ///
101    /// Intrusive smart pointer for objects that implement the
102    /// clover::ref_counter interface.
103    ///
104    template<typename T>
105    class intrusive_ptr {
106    public:
intrusive_ptr(T * q=NULL)107       intrusive_ptr(T *q = NULL) : p(q) {
108          if (p)
109             p->retain();
110       }
111 
intrusive_ptr(const intrusive_ptr & ptr)112       intrusive_ptr(const intrusive_ptr &ptr) :
113          intrusive_ptr(ptr.p) {
114       }
115 
intrusive_ptr(intrusive_ptr && ptr)116       intrusive_ptr(intrusive_ptr &&ptr) :
117          p(ptr.p) {
118          ptr.p = NULL;
119       }
120 
~intrusive_ptr()121       ~intrusive_ptr() {
122          if (p && p->release())
123             delete p;
124       }
125 
126       intrusive_ptr &
operator =(intrusive_ptr ptr)127       operator=(intrusive_ptr ptr) {
128          std::swap(ptr.p, p);
129          return *this;
130       }
131 
132       bool
operator ==(const intrusive_ptr & ref) const133       operator==(const intrusive_ptr &ref) const {
134          return p == ref.p;
135       }
136 
137       bool
operator !=(const intrusive_ptr & ref) const138       operator!=(const intrusive_ptr &ref) const {
139          return p != ref.p;
140       }
141 
142       T &
operator *() const143       operator*() const {
144          return *p;
145       }
146 
147       T *
operator ->() const148       operator->() const {
149          return p;
150       }
151 
152       T *
operator ()() const153       operator()() const {
154          return p;
155       }
156 
operator bool() const157       explicit operator bool() const {
158          return p;
159       }
160 
operator T*() const161       explicit operator T *() const {
162          return p;
163       }
164 
165    private:
166       T *p;
167    };
168 
169    ///
170    /// Intrusive smart reference for objects that implement the
171    /// clover::ref_counter interface.
172    ///
173    template<typename T>
174    class intrusive_ref {
175    public:
intrusive_ref(T & o)176       intrusive_ref(T &o) : p(&o) {
177          p->retain();
178       }
179 
intrusive_ref(const intrusive_ref & ref)180       intrusive_ref(const intrusive_ref &ref) :
181          intrusive_ref(*ref.p) {
182       }
183 
intrusive_ref(intrusive_ref && ref)184       intrusive_ref(intrusive_ref &&ref) :
185          p(ref.p) {
186          ref.p = NULL;
187       }
188 
~intrusive_ref()189       ~intrusive_ref() {
190          if (p && p->release())
191             delete p;
192       }
193 
194       intrusive_ref &
operator =(intrusive_ref ref)195       operator=(intrusive_ref ref) {
196          std::swap(ref.p, p);
197          return *this;
198       }
199 
200       bool
operator ==(const intrusive_ref & ref) const201       operator==(const intrusive_ref &ref) const {
202          return p == ref.p;
203       }
204 
205       bool
operator !=(const intrusive_ref & ref) const206       operator!=(const intrusive_ref &ref) const {
207          return p != ref.p;
208       }
209 
210       T &
operator ()() const211       operator()() const {
212          return *p;
213       }
214 
operator T&() const215       operator T &() const {
216          return *p;
217       }
218 
219    private:
220       T *p;
221    };
222 
223    ///
224    /// Initialize a clover::intrusive_ref from a newly created object
225    /// using the specified constructor arguments.
226    ///
227    template<typename T, typename... As>
228    intrusive_ref<T>
create(As &&...as)229    create(As &&... as) {
230       intrusive_ref<T> ref { *new T(std::forward<As>(as)...) };
231       ref().release();
232       return ref;
233    }
234 
235    ///
236    /// Class that implements the usual pointer interface but in fact
237    /// contains the object it seems to be pointing to.
238    ///
239    template<typename T>
240    class pseudo_ptr {
241    public:
pseudo_ptr(T x)242       pseudo_ptr(T x) : x(x) {
243       }
244 
pseudo_ptr(const pseudo_ptr & p)245       pseudo_ptr(const pseudo_ptr &p) : x(p.x) {
246       }
247 
248       pseudo_ptr &
operator =(const pseudo_ptr & p)249       operator=(const pseudo_ptr &p) {
250          x = p.x;
251          return *this;
252       }
253 
254       T &
operator *()255       operator*() {
256          return x;
257       }
258 
259       T *
operator ->()260       operator->() {
261          return &x;
262       }
263 
operator bool() const264       explicit operator bool() const {
265          return true;
266       }
267 
268    private:
269       T x;
270    };
271 }
272 
273 #endif
274