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   /// Base class for objects that support reference counting.
31   ///
32   class ref_counter {
33   public:
34      ref_counter(unsigned value = 1) : _ref_count(value) {}
35
36      unsigned
37      ref_count() const {
38         return _ref_count;
39      }
40
41      void
42      retain() {
43         _ref_count++;
44      }
45
46      bool
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:
62      ref_holder(ref_counter &o) : p(&o) {
63         p->retain();
64      }
65
66      ref_holder(const ref_holder &ref) :
67         ref_holder(*ref.p) {
68      }
69
70      ref_holder(ref_holder &&ref) :
71         p(ref.p) {
72         ref.p = NULL;
73      }
74
75      ~ref_holder() {
76         if (p)
77            p->release();
78      }
79
80      ref_holder &
81      operator=(ref_holder ref) {
82         std::swap(ref.p, p);
83         return *this;
84      }
85
86      bool
87      operator==(const ref_holder &ref) const {
88         return p == ref.p;
89      }
90
91      bool
92      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:
107      intrusive_ptr(T *q = NULL) : p(q) {
108         if (p)
109            p->retain();
110      }
111
112      intrusive_ptr(const intrusive_ptr &ptr) :
113         intrusive_ptr(ptr.p) {
114      }
115
116      intrusive_ptr(intrusive_ptr &&ptr) :
117         p(ptr.p) {
118         ptr.p = NULL;
119      }
120
121      ~intrusive_ptr() {
122         if (p && p->release())
123            delete p;
124      }
125
126      intrusive_ptr &
127      operator=(intrusive_ptr ptr) {
128         std::swap(ptr.p, p);
129         return *this;
130      }
131
132      bool
133      operator==(const intrusive_ptr &ref) const {
134         return p == ref.p;
135      }
136
137      bool
138      operator!=(const intrusive_ptr &ref) const {
139         return p != ref.p;
140      }
141
142      T &
143      operator*() const {
144         return *p;
145      }
146
147      T *
148      operator->() const {
149         return p;
150      }
151
152      T *
153      operator()() const {
154         return p;
155      }
156
157      explicit operator bool() const {
158         return p;
159      }
160
161      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:
176      intrusive_ref(T &o) : p(&o) {
177         p->retain();
178      }
179
180      intrusive_ref(const intrusive_ref &ref) :
181         intrusive_ref(*ref.p) {
182      }
183
184      intrusive_ref(intrusive_ref &&ref) :
185         p(ref.p) {
186         ref.p = NULL;
187      }
188
189      ~intrusive_ref() {
190         if (p && p->release())
191            delete p;
192      }
193
194      intrusive_ref &
195      operator=(intrusive_ref ref) {
196         std::swap(ref.p, p);
197         return *this;
198      }
199
200      bool
201      operator==(const intrusive_ref &ref) const {
202         return p == ref.p;
203      }
204
205      bool
206      operator!=(const intrusive_ref &ref) const {
207         return p != ref.p;
208      }
209
210      T &
211      operator()() const {
212         return *p;
213      }
214
215      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>
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:
242      pseudo_ptr(T x) : x(x) {
243      }
244
245      pseudo_ptr(const pseudo_ptr &p) : x(p.x) {
246      }
247
248      pseudo_ptr &
249      operator=(const pseudo_ptr &p) {
250         x = p.x;
251         return *this;
252      }
253
254      T &
255      operator*() {
256         return x;
257      }
258
259      T *
260      operator->() {
261         return &x;
262      }
263
264      explicit operator bool() const {
265         return true;
266      }
267
268   private:
269      T x;
270   };
271}
272
273#endif
274