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    /// Some helper functions for raw pointer operations
31    ///
32    template <class T>
33    static bool
ptr_is_aligned(const T * ptr,uintptr_t a)34    ptr_is_aligned(const T *ptr, uintptr_t a) noexcept {
35       assert(a == (a & -a));
36       uintptr_t ptr_value = reinterpret_cast<uintptr_t>(ptr);
37       return (ptr_value & (a - 1)) == 0;
38    }
39 
40    ///
41    /// Base class for objects that support reference counting.
42    ///
43    class ref_counter {
44    public:
ref_counter(unsigned value=1)45       ref_counter(unsigned value = 1) : _ref_count(value) {}
46 
47       unsigned
ref_count() const48       ref_count() const {
49          return _ref_count;
50       }
51 
52       void
retain()53       retain() {
54          _ref_count++;
55       }
56 
57       bool
release()58       release() {
59          return (--_ref_count) == 0;
60       }
61 
62    private:
63       std::atomic<unsigned> _ref_count;
64    };
65 
66    ///
67    /// Simple reference to a clover::ref_counter object.  Unlike
68    /// clover::intrusive_ptr and clover::intrusive_ref, it does nothing
69    /// special when the reference count drops to zero.
70    ///
71    class ref_holder {
72    public:
ref_holder(ref_counter & o)73       ref_holder(ref_counter &o) : p(&o) {
74          p->retain();
75       }
76 
ref_holder(const ref_holder & ref)77       ref_holder(const ref_holder &ref) :
78          ref_holder(*ref.p) {
79       }
80 
ref_holder(ref_holder && ref)81       ref_holder(ref_holder &&ref) :
82          p(ref.p) {
83          ref.p = NULL;
84       }
85 
~ref_holder()86       ~ref_holder() {
87          if (p)
88             p->release();
89       }
90 
91       ref_holder &
operator =(ref_holder ref)92       operator=(ref_holder ref) {
93          std::swap(ref.p, p);
94          return *this;
95       }
96 
97       bool
operator ==(const ref_holder & ref) const98       operator==(const ref_holder &ref) const {
99          return p == ref.p;
100       }
101 
102       bool
operator !=(const ref_holder & ref) const103       operator!=(const ref_holder &ref) const {
104          return p != ref.p;
105       }
106 
107    private:
108       ref_counter *p;
109    };
110 
111    ///
112    /// Intrusive smart pointer for objects that implement the
113    /// clover::ref_counter interface.
114    ///
115    template<typename T>
116    class intrusive_ptr {
117    public:
intrusive_ptr(T * q=NULL)118       intrusive_ptr(T *q = NULL) : p(q) {
119          if (p)
120             p->retain();
121       }
122 
intrusive_ptr(const intrusive_ptr & ptr)123       intrusive_ptr(const intrusive_ptr &ptr) :
124          intrusive_ptr(ptr.p) {
125       }
126 
intrusive_ptr(intrusive_ptr && ptr)127       intrusive_ptr(intrusive_ptr &&ptr) :
128          p(ptr.p) {
129          ptr.p = NULL;
130       }
131 
~intrusive_ptr()132       ~intrusive_ptr() {
133          if (p && p->release())
134             delete p;
135       }
136 
137       intrusive_ptr &
operator =(intrusive_ptr ptr)138       operator=(intrusive_ptr ptr) {
139          std::swap(ptr.p, p);
140          return *this;
141       }
142 
143       bool
operator ==(const intrusive_ptr & ref) const144       operator==(const intrusive_ptr &ref) const {
145          return p == ref.p;
146       }
147 
148       bool
operator !=(const intrusive_ptr & ref) const149       operator!=(const intrusive_ptr &ref) const {
150          return p != ref.p;
151       }
152 
153       T &
operator *() const154       operator*() const {
155          return *p;
156       }
157 
158       T *
operator ->() const159       operator->() const {
160          return p;
161       }
162 
163       T *
operator ()() const164       operator()() const {
165          return p;
166       }
167 
operator bool() const168       explicit operator bool() const {
169          return p;
170       }
171 
operator T*() const172       explicit operator T *() const {
173          return p;
174       }
175 
176    private:
177       T *p;
178    };
179 
180    ///
181    /// Intrusive smart reference for objects that implement the
182    /// clover::ref_counter interface.
183    ///
184    template<typename T>
185    class intrusive_ref {
186    public:
intrusive_ref(T & o)187       intrusive_ref(T &o) : p(&o) {
188          p->retain();
189       }
190 
intrusive_ref(const intrusive_ref & ref)191       intrusive_ref(const intrusive_ref &ref) :
192          intrusive_ref(*ref.p) {
193       }
194 
intrusive_ref(intrusive_ref && ref)195       intrusive_ref(intrusive_ref &&ref) :
196          p(ref.p) {
197          ref.p = NULL;
198       }
199 
~intrusive_ref()200       ~intrusive_ref() {
201          if (p && p->release())
202             delete p;
203       }
204 
205       intrusive_ref &
operator =(intrusive_ref ref)206       operator=(intrusive_ref ref) {
207          std::swap(ref.p, p);
208          return *this;
209       }
210 
211       bool
operator ==(const intrusive_ref & ref) const212       operator==(const intrusive_ref &ref) const {
213          return p == ref.p;
214       }
215 
216       bool
operator !=(const intrusive_ref & ref) const217       operator!=(const intrusive_ref &ref) const {
218          return p != ref.p;
219       }
220 
221       T &
operator ()() const222       operator()() const {
223          return *p;
224       }
225 
operator T&() const226       operator T &() const {
227          return *p;
228       }
229 
230    private:
231       T *p;
232    };
233 
234    ///
235    /// Initialize a clover::intrusive_ref from a newly created object
236    /// using the specified constructor arguments.
237    ///
238    template<typename T, typename... As>
239    intrusive_ref<T>
create(As &&...as)240    create(As &&... as) {
241       intrusive_ref<T> ref { *new T(std::forward<As>(as)...) };
242       ref().release();
243       return ref;
244    }
245 
246    ///
247    /// Class that implements the usual pointer interface but in fact
248    /// contains the object it seems to be pointing to.
249    ///
250    template<typename T>
251    class pseudo_ptr {
252    public:
pseudo_ptr(T x)253       pseudo_ptr(T x) : x(x) {
254       }
255 
pseudo_ptr(const pseudo_ptr & p)256       pseudo_ptr(const pseudo_ptr &p) : x(p.x) {
257       }
258 
259       pseudo_ptr &
operator =(const pseudo_ptr & p)260       operator=(const pseudo_ptr &p) {
261          x = p.x;
262          return *this;
263       }
264 
265       T &
operator *()266       operator*() {
267          return x;
268       }
269 
270       T *
operator ->()271       operator->() {
272          return &x;
273       }
274 
operator bool() const275       explicit operator bool() const {
276          return true;
277       }
278 
279    private:
280       T x;
281    };
282 }
283 
284 #endif
285