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