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