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,2016 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."
46 /// Base class for objects managed by intrusive_ptr.
47 class intrusive_base
{
49 intrusive_base(const intrusive_base
&);
51 /// Prevent assignment.
52 void operator=(const intrusive_base
&);
55 /** Construct with no references.
57 * The references get added if/when this object is put into an
60 intrusive_base() : _refs(0) { }
62 /* There's no need for a virtual destructor here as we never delete a
63 * subclass of intrusive_base by calling delete on intrusive_base*.
68 * This needs to be mutable so we can add/remove references through const
71 mutable unsigned _refs
;
78 /// A smart pointer that uses intrusive reference counting.
79 template<class T
> class intrusive_ptr
83 typedef intrusive_ptr this_type
;
87 intrusive_ptr(): px( 0 )
91 intrusive_ptr( T
* p
): px( p
)
93 if( px
!= 0 ) ++px
->_refs
;
97 intrusive_ptr( intrusive_ptr
<U
> const & rhs
)
100 if( px
!= 0 ) ++px
->_refs
;
103 intrusive_ptr(intrusive_ptr
const & rhs
): px( this == &rhs
? 0 : rhs
.px
)
105 if( px
!= 0 ) ++px
->_refs
;
110 if( px
!= 0 && --px
->_refs
== 0 ) delete px
;
113 intrusive_ptr
& operator=(intrusive_ptr
const & rhs
)
115 this_type(rhs
).swap(*this);
119 intrusive_ptr
& operator=(T
* rhs
)
121 this_type(rhs
).swap(*this);
130 T
& operator*() const
135 T
* operator->() const
140 void swap(intrusive_ptr
& rhs
)
152 template<class T
, class U
> inline bool operator==(intrusive_ptr
<T
> const & a
, intrusive_ptr
<U
> const & b
)
154 return a
.get() == b
.get();
157 template<class T
, class U
> inline bool operator!=(intrusive_ptr
<T
> const & a
, intrusive_ptr
<U
> const & b
)
159 return a
.get() != b
.get();
162 template<class T
, class U
> inline bool operator==(intrusive_ptr
<T
> const & a
, U
* b
)
167 template<class T
, class U
> inline bool operator!=(intrusive_ptr
<T
> const & a
, U
* b
)
172 template<class T
, class U
> inline bool operator==(T
* a
, intrusive_ptr
<U
> const & b
)
177 template<class T
, class U
> inline bool operator!=(T
* a
, intrusive_ptr
<U
> const & b
)
182 /// Base class for objects managed by opt_intrusive_ptr.
183 class opt_intrusive_base
{
185 opt_intrusive_base(const opt_intrusive_base
&) : _refs(0) { }
187 opt_intrusive_base
& operator=(const opt_intrusive_base
&) {
188 // Don't touch _refs.
192 /** Construct object which is initially not reference counted.
194 * The reference counting starts if release() is called.
196 opt_intrusive_base() : _refs(0) { }
198 /* Subclasses of opt_intrusive_base may be deleted by calling delete on a
199 * pointer to opt_intrusive_base.
201 virtual ~opt_intrusive_base() { }
217 * This needs to be mutable so we can add/remove references through const
220 mutable unsigned _refs
;
223 /** Start reference counting.
225 * The object is constructed with _refs set to 0, meaning it isn't being
228 * Calling release() sets _refs to 1 if it is 0, and from then
229 * opt_intrusive_ptr will increment and decrement _refs. If it is
230 * decremented to 1, the object is deleted.
232 void release() const {
242 /// A smart pointer that optionally uses intrusive reference counting.
243 template<class T
> class opt_intrusive_ptr
247 typedef opt_intrusive_ptr this_type
;
251 opt_intrusive_ptr(): px( 0 ), counting( false )
255 opt_intrusive_ptr( T
* p
): px( p
), counting( px
!= 0 && px
->_refs
)
257 if( counting
) ++px
->_refs
;
261 opt_intrusive_ptr( opt_intrusive_ptr
<U
> const & rhs
)
262 : px( rhs
.get() ), counting( rhs
.counting
)
264 if( counting
) ++px
->_refs
;
267 opt_intrusive_ptr(opt_intrusive_ptr
const & rhs
)
268 : px( this == &rhs
? 0 : rhs
.px
),
269 counting( this == &rhs
? false : rhs
.counting
)
271 if( counting
) ++px
->_refs
;
276 if( counting
&& --px
->_refs
== 1 ) delete px
;
279 opt_intrusive_ptr
& operator=(opt_intrusive_ptr
const & rhs
)
281 this_type(rhs
).swap(*this);
285 opt_intrusive_ptr
& operator=(T
* rhs
)
287 this_type(rhs
).swap(*this);
296 T
& operator*() const
301 T
* operator->() const
306 void swap(opt_intrusive_ptr
& rhs
)
311 bool tmp2
= counting
;
312 counting
= rhs
.counting
;
323 template<class T
, class U
> inline bool operator==(opt_intrusive_ptr
<T
> const & a
, opt_intrusive_ptr
<U
> const & b
)
325 return a
.get() == b
.get();
328 template<class T
, class U
> inline bool operator!=(opt_intrusive_ptr
<T
> const & a
, opt_intrusive_ptr
<U
> const & b
)
330 return a
.get() != b
.get();
333 template<class T
, class U
> inline bool operator==(opt_intrusive_ptr
<T
> const & a
, U
* b
)
338 template<class T
, class U
> inline bool operator!=(opt_intrusive_ptr
<T
> const & a
, U
* b
)
343 template<class T
, class U
> inline bool operator==(T
* a
, opt_intrusive_ptr
<U
> const & b
)
348 template<class T
, class U
> inline bool operator!=(T
* a
, opt_intrusive_ptr
<U
> const & b
)
356 #endif // XAPIAN_INCLUDED_INTRUSIVE_PTR_H