1 #ifndef XAPIAN_INCLUDED_INTRUSIVE_PTR_H
2 #define XAPIAN_INCLUDED_INTRUSIVE_PTR_H
5 // Based on Boost's intrusive_ptr.hpp
7 // Copyright (c) 2001, 2002 Peter Dimov
8 // Copyright (c) 2011,2013,2014,2015 Olly Betts
10 // Distributed under the Boost Software License, Version 1.0.
12 // Boost Software License - Version 1.0 - August 17th, 2003
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:
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.
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.
36 // See http://www.boost.org/libs/smart_ptr/intrusive_ptr.html for documentation.
39 #if !defined XAPIAN_IN_XAPIAN_H && !defined XAPIAN_LIB_BUILD
40 # error Never use <xapian/intrusive_ptr.h> directly; include <xapian.h> instead.
43 #include <xapian/visibility.h>
48 /// Base class for objects managed by intrusive_ptr.
49 class intrusive_base
{
51 intrusive_base(const intrusive_base
&);
53 /// Prevent assignment.
54 void operator=(const intrusive_base
&);
57 /** Construct with no references.
59 * The references get added if/when this object is put into an
62 intrusive_base() : _refs(0) { }
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*.
70 * This needs to be mutable so we can add/remove references through const
73 mutable unsigned _refs
;
80 /// A smart pointer that uses intrusive reference counting.
81 template<class T
> class intrusive_ptr
85 typedef intrusive_ptr this_type
;
89 intrusive_ptr(): px( 0 )
93 intrusive_ptr( T
* p
): px( p
)
95 if( px
!= 0 ) ++px
->_refs
;
99 intrusive_ptr( intrusive_ptr
<U
> const & rhs
)
102 if( px
!= 0 ) ++px
->_refs
;
105 intrusive_ptr(intrusive_ptr
const & rhs
): px( rhs
.px
)
107 if( px
!= 0 ) ++px
->_refs
;
112 if( px
!= 0 && --px
->_refs
== 0 ) delete px
;
115 #ifdef XAPIAN_MOVE_SEMANTICS
116 intrusive_ptr(intrusive_ptr
&& rhs
) : px( rhs
.px
)
121 intrusive_ptr
& operator=(intrusive_ptr
&& rhs
)
123 this_type( static_cast< intrusive_ptr
&& >( rhs
) ).swap(*this);
127 template<class U
> friend class intrusive_ptr
;
130 intrusive_ptr(intrusive_ptr
<U
> && rhs
) : px( rhs
.px
)
136 intrusive_ptr
& operator=(intrusive_ptr
<U
> && rhs
)
138 this_type( static_cast< intrusive_ptr
<U
> && >( rhs
) ).swap(*this);
143 intrusive_ptr
& operator=(intrusive_ptr
const & rhs
)
145 this_type(rhs
).swap(*this);
149 intrusive_ptr
& operator=(T
* rhs
)
151 this_type(rhs
).swap(*this);
160 T
& operator*() const
165 T
* operator->() const
170 void swap(intrusive_ptr
& rhs
)
182 template<class T
, class U
> inline bool operator==(intrusive_ptr
<T
> const & a
, intrusive_ptr
<U
> const & b
)
184 return a
.get() == b
.get();
187 template<class T
, class U
> inline bool operator!=(intrusive_ptr
<T
> const & a
, intrusive_ptr
<U
> const & b
)
189 return a
.get() != b
.get();
192 template<class T
, class U
> inline bool operator==(intrusive_ptr
<T
> const & a
, U
* b
)
197 template<class T
, class U
> inline bool operator!=(intrusive_ptr
<T
> const & a
, U
* b
)
202 template<class T
, class U
> inline bool operator==(T
* a
, intrusive_ptr
<U
> const & b
)
207 template<class T
, class U
> inline bool operator!=(T
* a
, intrusive_ptr
<U
> const & b
)
212 /// Base class for objects managed by opt_intrusive_ptr.
213 class XAPIAN_VISIBILITY_DEFAULT opt_intrusive_base
{
215 opt_intrusive_base(const opt_intrusive_base
&) : _refs(0) { }
217 opt_intrusive_base
& operator=(const opt_intrusive_base
&) {
218 // Don't touch _refs.
222 /** Construct object which is initially not reference counted.
224 * The reference counting starts if release() is called.
226 opt_intrusive_base() : _refs(0) { }
228 /* Subclasses of opt_intrusive_base may be deleted by calling delete on a
229 * pointer to opt_intrusive_base.
231 virtual ~opt_intrusive_base() { }
247 * This needs to be mutable so we can add/remove references through const
250 mutable unsigned _refs
;
253 /** Start reference counting.
255 * The object is constructed with _refs set to 0, meaning it isn't being
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.
262 void release() const {
272 /// A smart pointer that optionally uses intrusive reference counting.
273 template<class T
> class opt_intrusive_ptr
277 typedef opt_intrusive_ptr this_type
;
281 opt_intrusive_ptr(): px( 0 ), counting( false )
285 opt_intrusive_ptr( T
* p
): px( p
), counting( px
!= 0 && px
->_refs
)
287 if( counting
) ++px
->_refs
;
291 opt_intrusive_ptr( opt_intrusive_ptr
<U
> const & rhs
)
292 : px( rhs
.get() ), counting( rhs
.counting
)
294 if( counting
) ++px
->_refs
;
297 opt_intrusive_ptr(opt_intrusive_ptr
const & rhs
)
298 : px( rhs
.px
), counting( rhs
.counting
)
300 if( counting
) ++px
->_refs
;
305 if( counting
&& --px
->_refs
== 1 ) delete px
;
308 #ifdef XAPIAN_MOVE_SEMANTICS
309 opt_intrusive_ptr(opt_intrusive_ptr
&& rhs
)
310 : px( rhs
.px
), counting( rhs
.counting
)
316 opt_intrusive_ptr
& operator=(opt_intrusive_ptr
&& rhs
)
318 this_type( static_cast< opt_intrusive_ptr
&& >( rhs
) ).swap(*this);
322 template<class U
> friend class opt_intrusive_ptr
;
325 opt_intrusive_ptr(opt_intrusive_ptr
<U
> && rhs
)
326 : px( rhs
.px
), counting( rhs
.counting
)
333 opt_intrusive_ptr
& operator=(opt_intrusive_ptr
<U
> && rhs
)
335 this_type( static_cast< opt_intrusive_ptr
<U
> && >( rhs
) ).swap(*this);
340 opt_intrusive_ptr
& operator=(opt_intrusive_ptr
const & rhs
)
342 this_type(rhs
).swap(*this);
346 opt_intrusive_ptr
& operator=(T
* rhs
)
348 this_type(rhs
).swap(*this);
357 T
& operator*() const
362 T
* operator->() const
367 void swap(opt_intrusive_ptr
& rhs
)
372 bool tmp2
= counting
;
373 counting
= rhs
.counting
;
384 template<class T
, class U
> inline bool operator==(opt_intrusive_ptr
<T
> const & a
, opt_intrusive_ptr
<U
> const & b
)
386 return a
.get() == b
.get();
389 template<class T
, class U
> inline bool operator!=(opt_intrusive_ptr
<T
> const & a
, opt_intrusive_ptr
<U
> const & b
)
391 return a
.get() != b
.get();
394 template<class T
, class U
> inline bool operator==(opt_intrusive_ptr
<T
> const & a
, U
* b
)
399 template<class T
, class U
> inline bool operator!=(opt_intrusive_ptr
<T
> const & a
, U
* b
)
404 template<class T
, class U
> inline bool operator==(T
* a
, opt_intrusive_ptr
<U
> const & b
)
409 template<class T
, class U
> inline bool operator!=(T
* a
, opt_intrusive_ptr
<U
> const & b
)
417 #endif // XAPIAN_INCLUDED_INTRUSIVE_PTR_H