1 : /* base.h: Reference-counted pointers
2 : *
3 : * Copyright 1999,2000,2001 BrightStation PLC
4 : * Copyright 2002 Ananova Ltd
5 : * Copyright 2002,2003,2004,2007 Olly Betts
6 : *
7 : * This program is free software; you can redistribute it and/or
8 : * modify it under the terms of the GNU General Public License as
9 : * published by the Free Software Foundation; either version 2 of the
10 : * License, or (at your option) any later version.
11 : *
12 : * This program is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with this program; if not, write to the Free Software
19 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20 : * USA
21 : */
22 :
23 : #ifndef XAPIAN_INCLUDED_BASE_H
24 : #define XAPIAN_INCLUDED_BASE_H
25 :
26 : #include <xapian/deprecated.h>
27 :
28 : namespace Xapian {
29 : namespace Internal {
30 :
31 : /** @internal Reference counted internal classes should inherit from RefCntBase.
32 : *
33 : * This gives the object a reference count used by RefCntPtr.
34 : */
35 : class RefCntBase {
36 : /* Note: We never delete a pointer to a subclass of RefCntBase using
37 : * a RefCntBase *, so we don't need a virtual destructor here.
38 : */
39 : protected:
40 : /** The copy constructor.
41 : *
42 : * This is protected since it'll only be used by derived classes,
43 : * which should only rarely need copying (this is, after all, a
44 : * refcount implementation). Sometimes it's needed, though,
45 : * since we need to zero ref_count in the copy.
46 : */
47 : RefCntBase(const RefCntBase &) : ref_count(0) { }
48 :
49 : public:
50 : /// The constructor, which initialises the ref_count to 0.
51 : RefCntBase() : ref_count(0) { }
52 :
53 : typedef unsigned int ref_count_t;
54 :
55 : /** The actual reference count. It's mutable so we can have reference
56 : * counting work with const pointers.
57 : */
58 : mutable ref_count_t ref_count;
59 : };
60 :
61 : /** @internal A reference-counted pointer. Can be used with any
62 : * class derived from RefCntBase, as long as it is allocated
63 : * on the heap by new (not new[]!).
64 : */
65 : template <class T>
66 : class RefCntPtr {
67 : private:
68 : T *dest;
69 :
70 : public:
71 : T *operator->() const;
72 : T &operator*() const;
73 : T *get() const;
74 : /** Make a RefCntPtr for an object which may already
75 : * have reference counted pointers.
76 : *
77 : * You usually pass in a newly created object, or an object may pass
78 : * in "this" to get a RefCntPtr to itself to pass to other classes.
79 : * (e.g. a database might pass a newly created postlist a reference
80 : * counted pointer to itself.)
81 : */
82 : RefCntPtr(T *dest_);
83 : RefCntPtr();
84 : RefCntPtr(const RefCntPtr &other);
85 : void operator=(const RefCntPtr &other);
86 : void operator=(T *dest_);
87 : ~RefCntPtr();
88 :
89 : template <class U>
90 : RefCntPtr(const RefCntPtr<U> &other);
91 : };
92 :
93 : template <class T>
94 19 : inline RefCntPtr<T>::RefCntPtr(T *dest_) : dest(dest_)
95 : {
96 19 : if (dest) ++dest->ref_count;
97 19 : }
98 :
99 : template <class T>
100 : inline RefCntPtr<T>::RefCntPtr() : dest(0)
101 : {
102 : }
103 :
104 : template <class T>
105 : inline RefCntPtr<T>::RefCntPtr(const RefCntPtr &other) : dest(other.dest)
106 : {
107 : if (dest) ++dest->ref_count;
108 : }
109 :
110 : template <class T>
111 : inline void RefCntPtr<T>::operator=(const RefCntPtr &other) {
112 : operator=(other.dest);
113 : }
114 :
115 : template <class T>
116 : inline void RefCntPtr<T>::operator=(T *dest_) {
117 : // check if we're assigning a pointer to itself
118 : if (dest == dest_) return;
119 :
120 : // copy the new dest in before we delete the old to avoid a small
121 : // window in which dest points to a deleted object
122 : // FIXME: if pointer assignment isn't atomic, we ought to use locking...
123 : T *old_dest = dest;
124 : dest = dest_;
125 : if (dest) ++dest->ref_count;
126 : if (old_dest && --old_dest->ref_count == 0) delete old_dest;
127 : }
128 :
129 : template <class T>
130 0 : inline RefCntPtr<T>::~RefCntPtr()
131 : {
132 0 : if (dest && --dest->ref_count == 0) {
133 : // zero before we delete to avoid a small window in which dest points
134 : // to a deleted object
135 : // FIXME: if pointer assignment isn't atomic, we ought to use locking...
136 0 : T * condemned = dest;
137 0 : dest = 0;
138 0 : delete condemned;
139 : }
140 0 : }
141 :
142 : template <class T>
143 : template <class U>
144 : inline
145 : RefCntPtr<T>::RefCntPtr(const RefCntPtr<U> &other)
146 : : dest(other.get())
147 : {
148 : if (dest) ++dest->ref_count;
149 : }
150 :
151 : template <class T>
152 : inline T *RefCntPtr<T>::operator->() const
153 : {
154 : return dest;
155 : }
156 :
157 : template <class T>
158 : inline T &RefCntPtr<T>::operator*() const
159 : {
160 : return *dest;
161 : }
162 :
163 : template <class T>
164 30 : inline T *RefCntPtr<T>::get() const
165 : {
166 30 : return dest;
167 : }
168 :
169 : }
170 : }
171 :
172 : #endif /* XAPIAN_INCLUDED_BASE_H */
|