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
28namespace clover {
29   ///
30   /// Some helper functions for raw pointer operations
31   ///
32   template <class T>
33   static bool
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:
45      ref_counter(unsigned value = 1) : _ref_count(value) {}
46
47      unsigned
48      ref_count() const {
49         return _ref_count;
50      }
51
52      void
53      retain() {
54         _ref_count++;
55      }
56
57      bool
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:
73      ref_holder(ref_counter &o) : p(&o) {
74         p->retain();
75      }
76
77      ref_holder(const ref_holder &ref) :
78         ref_holder(*ref.p) {
79      }
80
81      ref_holder(ref_holder &&ref) :
82         p(ref.p) {
83         ref.p = NULL;
84      }
85
86      ~ref_holder() {
87         if (p)
88            p->release();
89      }
90
91      ref_holder &
92      operator=(ref_holder ref) {
93         std::swap(ref.p, p);
94         return *this;
95      }
96
97      bool
98      operator==(const ref_holder &ref) const {
99         return p == ref.p;
100      }
101
102      bool
103      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:
118      intrusive_ptr(T *q = NULL) : p(q) {
119         if (p)
120            p->retain();
121      }
122
123      intrusive_ptr(const intrusive_ptr &ptr) :
124         intrusive_ptr(ptr.p) {
125      }
126
127      intrusive_ptr(intrusive_ptr &&ptr) :
128         p(ptr.p) {
129         ptr.p = NULL;
130      }
131
132      ~intrusive_ptr() {
133         if (p && p->release())
134            delete p;
135      }
136
137      intrusive_ptr &
138      operator=(intrusive_ptr ptr) {
139         std::swap(ptr.p, p);
140         return *this;
141      }
142
143      bool
144      operator==(const intrusive_ptr &ref) const {
145         return p == ref.p;
146      }
147
148      bool
149      operator!=(const intrusive_ptr &ref) const {
150         return p != ref.p;
151      }
152
153      T &
154      operator*() const {
155         return *p;
156      }
157
158      T *
159      operator->() const {
160         return p;
161      }
162
163      T *
164      operator()() const {
165         return p;
166      }
167
168      explicit operator bool() const {
169         return p;
170      }
171
172      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:
187      intrusive_ref(T &o) : p(&o) {
188         p->retain();
189      }
190
191      intrusive_ref(const intrusive_ref &ref) :
192         intrusive_ref(*ref.p) {
193      }
194
195      intrusive_ref(intrusive_ref &&ref) :
196         p(ref.p) {
197         ref.p = NULL;
198      }
199
200      ~intrusive_ref() {
201         if (p && p->release())
202            delete p;
203      }
204
205      intrusive_ref &
206      operator=(intrusive_ref ref) {
207         std::swap(ref.p, p);
208         return *this;
209      }
210
211      bool
212      operator==(const intrusive_ref &ref) const {
213         return p == ref.p;
214      }
215
216      bool
217      operator!=(const intrusive_ref &ref) const {
218         return p != ref.p;
219      }
220
221      T &
222      operator()() const {
223         return *p;
224      }
225
226      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>
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:
253      pseudo_ptr(T x) : x(x) {
254      }
255
256      pseudo_ptr(const pseudo_ptr &p) : x(p.x) {
257      }
258
259      pseudo_ptr &
260      operator=(const pseudo_ptr &p) {
261         x = p.x;
262         return *this;
263      }
264
265      T &
266      operator*() {
267         return x;
268      }
269
270      T *
271      operator->() {
272         return &x;
273      }
274
275      explicit operator bool() const {
276         return true;
277      }
278
279   private:
280      T x;
281   };
282}
283
284#endif
285