xapian-core  2.0.0
intrusive_ptr.h
Go to the documentation of this file.
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,2017,2022 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/attributes.h>
44 #include <xapian/visibility.h>
45 
46 namespace Xapian {
47 namespace Internal {
48 
53 
55  void operator=(const intrusive_base&);
56 
57  public:
63  intrusive_base() : _refs(0) { }
64 
65  /* There's no need for a virtual destructor here as we never delete a
66  * subclass of intrusive_base by calling delete on intrusive_base*.
67  */
68 
74  mutable unsigned _refs;
75 };
76 
77 //
78 // intrusive_ptr
79 //
80 
82 template<class T> class intrusive_ptr
83 {
84 private:
85 
87 
88 public:
89 
90  intrusive_ptr(): px( 0 )
91  {
92  }
93 
94  intrusive_ptr( T * p): px( p )
95  {
96  if( px != 0 ) ++px->_refs;
97  }
98 
99  template<class U>
101  : px( rhs.get() )
102  {
103  if( px != 0 ) ++px->_refs;
104  }
105 
106  intrusive_ptr(intrusive_ptr const & rhs): px( rhs.px )
107  {
108  if( px != 0 ) ++px->_refs;
109  }
110 
112  {
113  if( px != 0 && --px->_refs == 0 ) delete px;
114  }
115 
116  intrusive_ptr(intrusive_ptr && rhs) : px( rhs.px )
117  {
118  rhs.px = 0;
119  }
120 
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>
131  {
132  rhs.px = 0;
133  }
134 
135  template<class U>
137  {
138  this_type( static_cast< intrusive_ptr<U> && >( rhs ) ).swap(*this);
139  return *this;
140  }
141 
143  {
144  this_type(rhs).swap(*this);
145  return *this;
146  }
147 
149  {
150  this_type(rhs).swap(*this);
151  return *this;
152  }
153 
154  T * get() const
155  {
156  return px;
157  }
158 
159  T & operator*() const
160  {
161  return *px;
162  }
163 
164  T * operator->() const
165  {
166  return px;
167  }
168 
169  void swap(intrusive_ptr & rhs)
170  {
171  T * tmp = px;
172  px = rhs.px;
173  rhs.px = tmp;
174  }
175 
176  explicit operator bool() const
177  {
178  return px != nullptr;
179  }
180 
181 private:
182 
183  T * px;
184 };
185 
186 template<class T, class U> inline bool operator==(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b)
187 {
188  return a.get() == b.get();
189 }
190 
191 template<class T, class U> inline bool operator!=(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b)
192 {
193  return a.get() != b.get();
194 }
195 
196 template<class T, class U> inline bool operator==(intrusive_ptr<T> const & a, U * b)
197 {
198  return a.get() == b;
199 }
200 
201 template<class T, class U> inline bool operator!=(intrusive_ptr<T> const & a, U * b)
202 {
203  return a.get() != b;
204 }
205 
206 template<class T, class U> inline bool operator==(T * a, intrusive_ptr<U> const & b)
207 {
208  return a == b.get();
209 }
210 
211 template<class T, class U> inline bool operator!=(T * a, intrusive_ptr<U> const & b)
212 {
213  return a != b.get();
214 }
215 
223 template<class T> class intrusive_ptr_nonnull
224 {
225 private:
226 
228 
229 public:
230 
232  {
233  ++px->_refs;
234  }
235 
236  template<class U>
238  : px( rhs.get() )
239  {
240  ++px->_refs;
241  }
242 
244  {
245  ++px->_refs;
246  }
247 
249  {
250  if( px && --px->_refs == 0 ) delete px;
251  }
252 
254  {
255  rhs.px = 0;
256  }
257 
259  {
260  this_type( static_cast< intrusive_ptr_nonnull && >( rhs ) ).swap(*this);
261  return *this;
262  }
263 
264  template<class U> friend class intrusive_ptr_nonnull;
265 
266  template<class U>
268  {
269  rhs.px = 0;
270  }
271 
272  template<class U>
274  {
275  this_type( static_cast< intrusive_ptr_nonnull<U> && >( rhs ) ).swap(*this);
276  return *this;
277  }
278 
280  {
281  this_type(rhs).swap(*this);
282  return *this;
283  }
284 
286  {
287  this_type(rhs).swap(*this);
288  return *this;
289  }
290 
291  T * get() const
292  {
293  return px;
294  }
295 
296  T & operator*() const
297  {
298  return *px;
299  }
300 
301  T * operator->() const
302  {
303  return px;
304  }
305 
307  {
308  T * tmp = px;
309  px = rhs.px;
310  rhs.px = tmp;
311  }
312 
313  // No operator bool() here - the held pointer should only be NULL if this
314  // pointer has been moved from, and in that case it's not valid to use its
315  // value so it seems more helpful to error on attempts to check if the
316  // pointer is NULL.
317 
318 private:
319 
320  T * px;
321 };
322 
323 template<class T, class U> inline bool operator==(intrusive_ptr_nonnull<T> const & a, intrusive_ptr_nonnull<U> const & b)
324 {
325  return a.get() == b.get();
326 }
327 
328 template<class T, class U> inline bool operator!=(intrusive_ptr_nonnull<T> const & a, intrusive_ptr_nonnull<U> const & b)
329 {
330  return a.get() != b.get();
331 }
332 
333 template<class T, class U> inline bool operator==(intrusive_ptr_nonnull<T> const & a, U * b)
334 {
335  return a.get() == b;
336 }
337 
338 template<class T, class U> inline bool operator!=(intrusive_ptr_nonnull<T> const & a, U * b)
339 {
340  return a.get() != b;
341 }
342 
343 template<class T, class U> inline bool operator==(T * a, intrusive_ptr_nonnull<U> const & b)
344 {
345  return a == b.get();
346 }
347 
348 template<class T, class U> inline bool operator!=(T * a, intrusive_ptr_nonnull<U> const & b)
349 {
350  return a != b.get();
351 }
352 
355  public:
356  opt_intrusive_base(const opt_intrusive_base&) : _refs(0) { }
357 
359  // Don't touch _refs.
360  return *this;
361  }
362 
367  opt_intrusive_base() : _refs(0) { }
368 
369  /* Subclasses of opt_intrusive_base may be deleted by calling delete on a
370  * pointer to opt_intrusive_base.
371  */
372  virtual ~opt_intrusive_base() { }
373 
374  void ref() const {
375  if (_refs == 0)
376  _refs = 2;
377  else
378  ++_refs;
379  }
380 
381  void unref() const {
382  if (--_refs == 1)
383  delete this;
384  }
385 
391  mutable unsigned _refs;
392 
393  protected:
403  void release() const {
404  if (_refs == 0)
405  _refs = 1;
406  }
407 };
408 
409 //
410 // opt_intrusive_ptr
411 //
412 
414 template<class T> class opt_intrusive_ptr
415 {
416 private:
417 
419 
420 public:
421 
423  {
424  }
425 
426  opt_intrusive_ptr( T * p): px( p ), counting( px != 0 && px->_refs )
427  {
428  if( counting ) ++px->_refs;
429  }
430 
431  template<class U>
433  : px( rhs.get() ), counting( rhs.counting )
434  {
435  if( counting ) ++px->_refs;
436  }
437 
439  : px( rhs.px ), counting( rhs.counting )
440  {
441  if( counting ) ++px->_refs;
442  }
443 
445  {
446  if( counting && --px->_refs == 1 ) delete px;
447  }
448 
450  : px( rhs.px ), counting( rhs.counting )
451  {
452  rhs.px = 0;
453  rhs.counting = 0;
454  }
455 
457  {
458  this_type( static_cast< opt_intrusive_ptr && >( rhs ) ).swap(*this);
459  return *this;
460  }
461 
462  template<class U> friend class opt_intrusive_ptr;
463 
464  template<class U>
466  : px( rhs.px ), counting( rhs.counting )
467  {
468  rhs.px = 0;
469  rhs.counting = 0;
470  }
471 
472  template<class U>
474  {
475  this_type( static_cast< opt_intrusive_ptr<U> && >( rhs ) ).swap(*this);
476  return *this;
477  }
478 
480  {
481  this_type(rhs).swap(*this);
482  return *this;
483  }
484 
486  {
487  this_type(rhs).swap(*this);
488  return *this;
489  }
490 
491  T * get() const
492  {
493  return px;
494  }
495 
496  T & operator*() const
497  {
498  return *px;
499  }
500 
501  T * operator->() const
502  {
503  return px;
504  }
505 
507  {
508  T * tmp = px;
509  px = rhs.px;
510  rhs.px = tmp;
511  bool tmp2 = counting;
512  counting = rhs.counting;
513  rhs.counting = tmp2;
514  }
515 
516  explicit operator bool() const
517  {
518  return px != nullptr;
519  }
520 
521 private:
522 
523  T * px;
524 
525  bool counting;
526 };
527 
528 template<class T, class U> inline bool operator==(opt_intrusive_ptr<T> const & a, opt_intrusive_ptr<U> const & b)
529 {
530  return a.get() == b.get();
531 }
532 
533 template<class T, class U> inline bool operator!=(opt_intrusive_ptr<T> const & a, opt_intrusive_ptr<U> const & b)
534 {
535  return a.get() != b.get();
536 }
537 
538 template<class T, class U> inline bool operator==(opt_intrusive_ptr<T> const & a, U * b)
539 {
540  return a.get() == b;
541 }
542 
543 template<class T, class U> inline bool operator!=(opt_intrusive_ptr<T> const & a, U * b)
544 {
545  return a.get() != b;
546 }
547 
548 template<class T, class U> inline bool operator==(T * a, opt_intrusive_ptr<U> const & b)
549 {
550  return a == b.get();
551 }
552 
553 template<class T, class U> inline bool operator!=(T * a, opt_intrusive_ptr<U> const & b)
554 {
555  return a != b.get();
556 }
557 
558 }
559 }
560 
561 #endif // XAPIAN_INCLUDED_INTRUSIVE_PTR_H
Compiler attribute macros.
#define XAPIAN_NONNULL(LIST)
Annotate function parameters which should be non-NULL pointers.
Definition: attributes.h:84
Base class for objects managed by intrusive_ptr.
Definition: intrusive_ptr.h:50
intrusive_base()
Construct with no references.
Definition: intrusive_ptr.h:63
void operator=(const intrusive_base &)
Prevent assignment.
intrusive_base(const intrusive_base &)
Prevent copying.
unsigned _refs
Reference count.
Definition: intrusive_ptr.h:74
A normally non-NULL smart pointer using intrusive reference counting.
intrusive_ptr_nonnull(intrusive_ptr_nonnull< U > &&rhs)
intrusive_ptr_nonnull & operator=(intrusive_ptr_nonnull &&rhs)
void swap(intrusive_ptr_nonnull &rhs)
intrusive_ptr_nonnull & operator=(T *rhs) XAPIAN_NONNULL()
intrusive_ptr_nonnull(intrusive_ptr_nonnull< U > const &rhs)
intrusive_ptr_nonnull(T *p) XAPIAN_NONNULL()
intrusive_ptr_nonnull(intrusive_ptr_nonnull &&rhs)
intrusive_ptr_nonnull & operator=(intrusive_ptr_nonnull< U > &&rhs)
intrusive_ptr_nonnull(intrusive_ptr_nonnull const &rhs)
intrusive_ptr_nonnull & operator=(intrusive_ptr_nonnull const &rhs)
A smart pointer that uses intrusive reference counting.
Definition: intrusive_ptr.h:83
intrusive_ptr(intrusive_ptr< U > const &rhs)
intrusive_ptr(intrusive_ptr const &rhs)
intrusive_ptr(intrusive_ptr< U > &&rhs)
intrusive_ptr & operator=(intrusive_ptr< U > &&rhs)
intrusive_ptr(intrusive_ptr &&rhs)
intrusive_ptr & operator=(intrusive_ptr &&rhs)
intrusive_ptr & operator=(intrusive_ptr const &rhs)
intrusive_ptr & operator=(T *rhs)
void swap(intrusive_ptr &rhs)
Base class for objects managed by opt_intrusive_ptr.
opt_intrusive_base()
Construct object which is initially not reference counted.
opt_intrusive_base & operator=(const opt_intrusive_base &)
void release() const
Start reference counting.
opt_intrusive_base(const opt_intrusive_base &)
unsigned _refs
Reference count.
A smart pointer that optionally uses intrusive reference counting.
opt_intrusive_ptr(opt_intrusive_ptr< U > const &rhs)
opt_intrusive_ptr & operator=(opt_intrusive_ptr const &rhs)
opt_intrusive_ptr & operator=(opt_intrusive_ptr &&rhs)
opt_intrusive_ptr & operator=(opt_intrusive_ptr< U > &&rhs)
opt_intrusive_ptr(opt_intrusive_ptr &&rhs)
void swap(opt_intrusive_ptr &rhs)
opt_intrusive_ptr(opt_intrusive_ptr< U > &&rhs)
opt_intrusive_ptr(opt_intrusive_ptr const &rhs)
opt_intrusive_ptr & operator=(T *rhs)
PositionList * p
#define false
Definition: header.h:9
bool operator!=(intrusive_ptr< T > const &a, intrusive_ptr< U > const &b)
bool operator==(intrusive_ptr< T > const &a, intrusive_ptr< U > const &b)
The Xapian namespace contains public interfaces for the Xapian library.
Definition: compactor.cc:82
Define XAPIAN_VISIBILITY_* macros.
#define XAPIAN_VISIBILITY_DEFAULT
Definition: visibility.h:28