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