1 #ifndef XAPIAN_INCLUDED_INTRUSIVE_PTR_H 2 #define XAPIAN_INCLUDED_INTRUSIVE_PTR_H 3 4 // 5 // Based on Boost's intrusive_ptr.hpp 6 // 7 // Copyright (c) 2001, 2002 Peter Dimov 8 // Copyright (c) 2011,2013,2014,2015 Olly Betts 9 // 10 // Distributed under the Boost Software License, Version 1.0. 11 // 12 // Boost Software License - Version 1.0 - August 17th, 2003 13 // 14 // Permission is hereby granted, free of charge, to any person or organization 15 // obtaining a copy of the software and accompanying documentation covered by 16 // this license (the "Software") to use, reproduce, display, distribute, 17 // execute, and transmit the Software, and to prepare derivative works of the 18 // Software, and to permit third-parties to whom the Software is furnished to 19 // do so, all subject to the following: 20 // 21 // The copyright notices in the Software and this entire statement, including 22 // the above license grant, this restriction and the following disclaimer, 23 // must be included in all copies of the Software, in whole or in part, and 24 // all derivative works of the Software, unless such copies or derivative 25 // works are solely in the form of machine-executable object code generated by 26 // a source language processor. 27 // 28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 29 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 30 // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 31 // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 32 // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 33 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 34 // DEALINGS IN THE SOFTWARE. 35 // 36 // See http://www.boost.org/libs/smart_ptr/intrusive_ptr.html for documentation. 37 // 38 39 #if !defined XAPIAN_IN_XAPIAN_H && !defined XAPIAN_LIB_BUILD 40 # error Never use <xapian/intrusive_ptr.h> directly; include <xapian.h> instead. 41 #endif 42 43 #include <xapian/visibility.h> 44 45 namespace Xapian { 46 namespace Internal { 47 48 /// Base class for objects managed by intrusive_ptr. 49 class intrusive_base { 50 /// Prevent copying. 51 intrusive_base(const intrusive_base&); 52 53 /// Prevent assignment. 54 void operator=(const intrusive_base&); 55 56 public: 57 /** Construct with no references. 58 * 59 * The references get added if/when this object is put into an 60 * intrusive_ptr. 61 */ intrusive_base()62 intrusive_base() : _refs(0) { } 63 64 /* There's no need for a virtual destructor here as we never delete a 65 * subclass of intrusive_base by calling delete on intrusive_base*. 66 */ 67 68 /** Reference count. 69 * 70 * This needs to be mutable so we can add/remove references through const 71 * pointers. 72 */ 73 mutable unsigned _refs; 74 }; 75 76 // 77 // intrusive_ptr 78 // 79 80 /// A smart pointer that uses intrusive reference counting. 81 template<class T> class intrusive_ptr 82 { 83 private: 84 85 typedef intrusive_ptr this_type; 86 87 public: 88 intrusive_ptr()89 intrusive_ptr(): px( 0 ) 90 { 91 } 92 intrusive_ptr(T * p)93 intrusive_ptr( T * p): px( p ) 94 { 95 if( px != 0 ) ++px->_refs; 96 } 97 98 template<class U> intrusive_ptr(intrusive_ptr<U> const & rhs)99 intrusive_ptr( intrusive_ptr<U> const & rhs ) 100 : px( rhs.get() ) 101 { 102 if( px != 0 ) ++px->_refs; 103 } 104 intrusive_ptr(intrusive_ptr const & rhs)105 intrusive_ptr(intrusive_ptr const & rhs): px( rhs.px ) 106 { 107 if( px != 0 ) ++px->_refs; 108 } 109 ~intrusive_ptr()110 ~intrusive_ptr() 111 { 112 if( px != 0 && --px->_refs == 0 ) delete px; 113 } 114 115 #ifdef XAPIAN_MOVE_SEMANTICS intrusive_ptr(intrusive_ptr && rhs)116 intrusive_ptr(intrusive_ptr && rhs) : px( rhs.px ) 117 { 118 rhs.px = 0; 119 } 120 121 intrusive_ptr & operator=(intrusive_ptr && rhs) 122 { 123 this_type( static_cast< intrusive_ptr && >( rhs ) ).swap(*this); 124 return *this; 125 } 126 127 template<class U> friend class intrusive_ptr; 128 129 template<class U> intrusive_ptr(intrusive_ptr<U> && rhs)130 intrusive_ptr(intrusive_ptr<U> && rhs) : px( rhs.px ) 131 { 132 rhs.px = 0; 133 } 134 135 template<class U> 136 intrusive_ptr & operator=(intrusive_ptr<U> && rhs) 137 { 138 this_type( static_cast< intrusive_ptr<U> && >( rhs ) ).swap(*this); 139 return *this; 140 } 141 #endif 142 143 intrusive_ptr & operator=(intrusive_ptr const & rhs) 144 { 145 this_type(rhs).swap(*this); 146 return *this; 147 } 148 149 intrusive_ptr & operator=(T * rhs) 150 { 151 this_type(rhs).swap(*this); 152 return *this; 153 } 154 get()155 T * get() const 156 { 157 return px; 158 } 159 160 T & operator*() const 161 { 162 return *px; 163 } 164 165 T * operator->() const 166 { 167 return px; 168 } 169 swap(intrusive_ptr & rhs)170 void swap(intrusive_ptr & rhs) 171 { 172 T * tmp = px; 173 px = rhs.px; 174 rhs.px = tmp; 175 } 176 177 private: 178 179 T * px; 180 }; 181 182 template<class T, class U> inline bool operator==(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b) 183 { 184 return a.get() == b.get(); 185 } 186 187 template<class T, class U> inline bool operator!=(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b) 188 { 189 return a.get() != b.get(); 190 } 191 192 template<class T, class U> inline bool operator==(intrusive_ptr<T> const & a, U * b) 193 { 194 return a.get() == b; 195 } 196 197 template<class T, class U> inline bool operator!=(intrusive_ptr<T> const & a, U * b) 198 { 199 return a.get() != b; 200 } 201 202 template<class T, class U> inline bool operator==(T * a, intrusive_ptr<U> const & b) 203 { 204 return a == b.get(); 205 } 206 207 template<class T, class U> inline bool operator!=(T * a, intrusive_ptr<U> const & b) 208 { 209 return a != b.get(); 210 } 211 212 /// Base class for objects managed by opt_intrusive_ptr. 213 class XAPIAN_VISIBILITY_DEFAULT opt_intrusive_base { 214 public: opt_intrusive_base(const opt_intrusive_base &)215 opt_intrusive_base(const opt_intrusive_base&) : _refs(0) { } 216 217 opt_intrusive_base& operator=(const opt_intrusive_base&) { 218 // Don't touch _refs. 219 return *this; 220 } 221 222 /** Construct object which is initially not reference counted. 223 * 224 * The reference counting starts if release() is called. 225 */ opt_intrusive_base()226 opt_intrusive_base() : _refs(0) { } 227 228 /* Subclasses of opt_intrusive_base may be deleted by calling delete on a 229 * pointer to opt_intrusive_base. 230 */ ~opt_intrusive_base()231 virtual ~opt_intrusive_base() { } 232 ref()233 void ref() const { 234 if (_refs == 0) 235 _refs = 2; 236 else 237 ++_refs; 238 } 239 unref()240 void unref() const { 241 if (--_refs == 1) 242 delete this; 243 } 244 245 /** Reference count. 246 * 247 * This needs to be mutable so we can add/remove references through const 248 * pointers. 249 */ 250 mutable unsigned _refs; 251 252 protected: 253 /** Start reference counting. 254 * 255 * The object is constructed with _refs set to 0, meaning it isn't being 256 * reference counted. 257 * 258 * Calling release() sets _refs to 1 if it is 0, and from then 259 * opt_intrusive_ptr will increment and decrement _refs. If it is 260 * decremented to 1, the object is deleted. 261 */ release()262 void release() const { 263 if (_refs == 0) 264 _refs = 1; 265 } 266 }; 267 268 // 269 // opt_intrusive_ptr 270 // 271 272 /// A smart pointer that optionally uses intrusive reference counting. 273 template<class T> class opt_intrusive_ptr 274 { 275 private: 276 277 typedef opt_intrusive_ptr this_type; 278 279 public: 280 opt_intrusive_ptr()281 opt_intrusive_ptr(): px( 0 ), counting( false ) 282 { 283 } 284 opt_intrusive_ptr(T * p)285 opt_intrusive_ptr( T * p): px( p ), counting( px != 0 && px->_refs ) 286 { 287 if( counting ) ++px->_refs; 288 } 289 290 template<class U> opt_intrusive_ptr(opt_intrusive_ptr<U> const & rhs)291 opt_intrusive_ptr( opt_intrusive_ptr<U> const & rhs ) 292 : px( rhs.get() ), counting( rhs.counting ) 293 { 294 if( counting ) ++px->_refs; 295 } 296 opt_intrusive_ptr(opt_intrusive_ptr const & rhs)297 opt_intrusive_ptr(opt_intrusive_ptr const & rhs) 298 : px( rhs.px ), counting( rhs.counting ) 299 { 300 if( counting ) ++px->_refs; 301 } 302 ~opt_intrusive_ptr()303 ~opt_intrusive_ptr() 304 { 305 if( counting && --px->_refs == 1 ) delete px; 306 } 307 308 #ifdef XAPIAN_MOVE_SEMANTICS opt_intrusive_ptr(opt_intrusive_ptr && rhs)309 opt_intrusive_ptr(opt_intrusive_ptr && rhs) 310 : px( rhs.px ), counting( rhs.counting ) 311 { 312 rhs.px = 0; 313 rhs.counting = 0; 314 } 315 316 opt_intrusive_ptr & operator=(opt_intrusive_ptr && rhs) 317 { 318 this_type( static_cast< opt_intrusive_ptr && >( rhs ) ).swap(*this); 319 return *this; 320 } 321 322 template<class U> friend class opt_intrusive_ptr; 323 324 template<class U> opt_intrusive_ptr(opt_intrusive_ptr<U> && rhs)325 opt_intrusive_ptr(opt_intrusive_ptr<U> && rhs) 326 : px( rhs.px ), counting( rhs.counting ) 327 { 328 rhs.px = 0; 329 rhs.counting = 0; 330 } 331 332 template<class U> 333 opt_intrusive_ptr & operator=(opt_intrusive_ptr<U> && rhs) 334 { 335 this_type( static_cast< opt_intrusive_ptr<U> && >( rhs ) ).swap(*this); 336 return *this; 337 } 338 #endif 339 340 opt_intrusive_ptr & operator=(opt_intrusive_ptr const & rhs) 341 { 342 this_type(rhs).swap(*this); 343 return *this; 344 } 345 346 opt_intrusive_ptr & operator=(T * rhs) 347 { 348 this_type(rhs).swap(*this); 349 return *this; 350 } 351 get()352 T * get() const 353 { 354 return px; 355 } 356 357 T & operator*() const 358 { 359 return *px; 360 } 361 362 T * operator->() const 363 { 364 return px; 365 } 366 swap(opt_intrusive_ptr & rhs)367 void swap(opt_intrusive_ptr & rhs) 368 { 369 T * tmp = px; 370 px = rhs.px; 371 rhs.px = tmp; 372 bool tmp2 = counting; 373 counting = rhs.counting; 374 rhs.counting = tmp2; 375 } 376 377 private: 378 379 T * px; 380 381 bool counting; 382 }; 383 384 template<class T, class U> inline bool operator==(opt_intrusive_ptr<T> const & a, opt_intrusive_ptr<U> const & b) 385 { 386 return a.get() == b.get(); 387 } 388 389 template<class T, class U> inline bool operator!=(opt_intrusive_ptr<T> const & a, opt_intrusive_ptr<U> const & b) 390 { 391 return a.get() != b.get(); 392 } 393 394 template<class T, class U> inline bool operator==(opt_intrusive_ptr<T> const & a, U * b) 395 { 396 return a.get() == b; 397 } 398 399 template<class T, class U> inline bool operator!=(opt_intrusive_ptr<T> const & a, U * b) 400 { 401 return a.get() != b; 402 } 403 404 template<class T, class U> inline bool operator==(T * a, opt_intrusive_ptr<U> const & b) 405 { 406 return a == b.get(); 407 } 408 409 template<class T, class U> inline bool operator!=(T * a, opt_intrusive_ptr<U> const & b) 410 { 411 return a != b.get(); 412 } 413 414 } 415 } 416 417 #endif // XAPIAN_INCLUDED_INTRUSIVE_PTR_H 418