Fix handling of a self-initialised PIMPL object
[xapian.git] / xapian-core / include / xapian / intrusive_ptr.h
blob7b306dcfda1f7e487d532ff2f325cd600d0406fa
1 #ifndef XAPIAN_INCLUDED_INTRUSIVE_PTR_H
2 #define XAPIAN_INCLUDED_INTRUSIVE_PTR_H
4 //
5 // Based on Boost's intrusive_ptr.hpp
6 //
7 // Copyright (c) 2001, 2002 Peter Dimov
8 // Copyright (c) 2011,2013,2014,2015,2016 Olly Betts
9 //
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."
41 #endif
43 namespace Xapian {
44 namespace Internal {
46 /// Base class for objects managed by intrusive_ptr.
47 class intrusive_base {
48 /// Prevent copying.
49 intrusive_base(const intrusive_base&);
51 /// Prevent assignment.
52 void operator=(const intrusive_base&);
54 public:
55 /** Construct with no references.
57 * The references get added if/when this object is put into an
58 * intrusive_ptr.
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*.
66 /** Reference count.
68 * This needs to be mutable so we can add/remove references through const
69 * pointers.
71 mutable unsigned _refs;
75 // intrusive_ptr
78 /// A smart pointer that uses intrusive reference counting.
79 template<class T> class intrusive_ptr
81 private:
83 typedef intrusive_ptr this_type;
85 public:
87 intrusive_ptr(): px( 0 )
91 intrusive_ptr( T * p): px( p )
93 if( px != 0 ) ++px->_refs;
96 template<class U>
97 intrusive_ptr( intrusive_ptr<U> const & rhs )
98 : px( rhs.get() )
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;
108 ~intrusive_ptr()
110 if( px != 0 && --px->_refs == 0 ) delete px;
113 intrusive_ptr & operator=(intrusive_ptr const & rhs)
115 this_type(rhs).swap(*this);
116 return *this;
119 intrusive_ptr & operator=(T * rhs)
121 this_type(rhs).swap(*this);
122 return *this;
125 T * get() const
127 return px;
130 T & operator*() const
132 return *px;
135 T * operator->() const
137 return px;
140 void swap(intrusive_ptr & rhs)
142 T * tmp = px;
143 px = rhs.px;
144 rhs.px = tmp;
147 private:
149 T * px;
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)
164 return a.get() == b;
167 template<class T, class U> inline bool operator!=(intrusive_ptr<T> const & a, U * b)
169 return a.get() != b;
172 template<class T, class U> inline bool operator==(T * a, intrusive_ptr<U> const & b)
174 return a == b.get();
177 template<class T, class U> inline bool operator!=(T * a, intrusive_ptr<U> const & b)
179 return a != b.get();
182 /// Base class for objects managed by opt_intrusive_ptr.
183 class opt_intrusive_base {
184 public:
185 opt_intrusive_base(const opt_intrusive_base&) : _refs(0) { }
187 opt_intrusive_base& operator=(const opt_intrusive_base&) {
188 // Don't touch _refs.
189 return *this;
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() { }
203 void ref() const {
204 if (_refs == 0)
205 _refs = 2;
206 else
207 ++_refs;
210 void unref() const {
211 if (--_refs == 1)
212 delete this;
215 /** Reference count.
217 * This needs to be mutable so we can add/remove references through const
218 * pointers.
220 mutable unsigned _refs;
222 protected:
223 /** Start reference counting.
225 * The object is constructed with _refs set to 0, meaning it isn't being
226 * reference counted.
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 {
233 if (_refs == 0)
234 _refs = 1;
239 // opt_intrusive_ptr
242 /// A smart pointer that optionally uses intrusive reference counting.
243 template<class T> class opt_intrusive_ptr
245 private:
247 typedef opt_intrusive_ptr this_type;
249 public:
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;
260 template<class U>
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;
274 ~opt_intrusive_ptr()
276 if( counting && --px->_refs == 1 ) delete px;
279 opt_intrusive_ptr & operator=(opt_intrusive_ptr const & rhs)
281 this_type(rhs).swap(*this);
282 return *this;
285 opt_intrusive_ptr & operator=(T * rhs)
287 this_type(rhs).swap(*this);
288 return *this;
291 T * get() const
293 return px;
296 T & operator*() const
298 return *px;
301 T * operator->() const
303 return px;
306 void swap(opt_intrusive_ptr & rhs)
308 T * tmp = px;
309 px = rhs.px;
310 rhs.px = tmp;
311 bool tmp2 = counting;
312 counting = rhs.counting;
313 rhs.counting = tmp2;
316 private:
318 T * px;
320 bool 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)
335 return a.get() == b;
338 template<class T, class U> inline bool operator!=(opt_intrusive_ptr<T> const & a, U * b)
340 return a.get() != b;
343 template<class T, class U> inline bool operator==(T * a, opt_intrusive_ptr<U> const & b)
345 return a == b.get();
348 template<class T, class U> inline bool operator!=(T * a, opt_intrusive_ptr<U> const & b)
350 return a != b.get();
356 #endif // XAPIAN_INCLUDED_INTRUSIVE_PTR_H