forked from sequitur-g2p/sequitur-g2p
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathReferenceCounting.hh
250 lines (226 loc) · 7.79 KB
/
ReferenceCounting.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
/*
* $Id: ReferenceCounting.hh 1667 2007-06-02 14:32:35Z max $
*
* Copyright (c) 2004-2005 RWTH Aachen University
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License Version 2 (June
* 1991) as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you will find it at
* http://www.gnu.org/licenses/gpl.html, or write to the Free Software
* Foundation, Inc., 51 Franlin Street, Fifth Floor, Boston, MA 02110,
* USA.
*
* Should a provision of no. 9 and 10 of the GNU General Public License
* be invalid or become invalid, a valid provision is deemed to have been
* agreed upon which comes closest to what the parties intended
* commercially. In any case guarantee/warranty shall be limited to gross
* negligent actions or intended actions or fraudulent concealment.
*/
#ifndef _CORE_REFERENCE_COUNTING
#define _CORE_REFERENCE_COUNTING
#include "Assertions.hh"
#include "Types.hh"
namespace Core {
template <class T> class Ref;
/**
* Base class for reference-counted objects.
*
* To enable reference counting for a class it need to inhert this
* class publically.
*/
class ReferenceCounted {
private:
template <class T> friend class Ref;
mutable u32 referenceCount_;
explicit ReferenceCounted(u32 rc) : referenceCount_(rc) {}
static inline ReferenceCounted *sentinel() {
static ReferenceCounted sentinel_(1);
return &sentinel_;
}
static bool isSentinel(const ReferenceCounted *object) {
return object == sentinel();
}
static bool isNotSentinel(const ReferenceCounted *object) {
return object != sentinel();
}
public:
ReferenceCounted() : referenceCount_(0) {}
ReferenceCounted(const ReferenceCounted&) : referenceCount_(0) {}
ReferenceCounted &operator= (const ReferenceCounted&) { return *this; }
u32 refCount() const { return referenceCount_; }
void free() const {
require_(!referenceCount_);
verify_(!isSentinel(this));
delete this;
}
};
/**
* Class template for smart pointers using intrusive
* reference-counting.
*
* Naming: Concrete smart pointer types should have a "Ref" suffix:
* e.g. typedef Ref<Foo> FooRef;
* (Obviously calling this class "Ref" instead of more
* correcly "Reference" deviates from the naming conventions.
* However since this class is used extensively a shorter name is
* mandated. "Ref" is analogious to the "REF" keyword in
* Modula-3.)
*
* @c T should be a decendent of ReferenceCounted.
*
* Note: Virtual derivation from ReferenceCounted is not allowed
* currently. Reasons are many but the most imporatant one is
* that we use a sentinel instead of null to represent a reference
* is invalid (i.e. void). Advantage of using a sentinel is that
* in the most frequently used functions (e.g. copy constructor)
* the sentinel can be treated as if it was a normal object. Thus
* we save a few if-clauses. Once we use a sentinel, the static
* sentinel object (delivered by ReferenceCounted::sentinel()) of
* type ReferenceCounted needs to get casted to the type
* Object. It is a dirty solution but is the only way to make the
* usage of the sentinel fast. In order to be independent of the
* order of derivation in case of multiple inheritance - i.e. if
* ReferenceCounted is the first precursor class or not -
* static_cast is used to cast the sentinel to the type Object.
* Usage of reinterpret_cast would work only if we could ensure
* that ReferenceCounted was the very first class in the type
* Object. Finally, closing the series of arguments, virtual
* derivation from ReferenceCounted is not permitted by
* static_cast. It does not mean that ReferenceCounting and
* virtual inheritance does not go along at all: Make your virtual
* inheritance hiearchy first, and derive only the most specific
* class from ReferenceCounted.
*/
template <class T /* -> ReferenceCounted */>
class Ref {
private:
typedef T Object;
Object *object_;
static Object* sentinel() { return static_cast<Object*>(Object::sentinel()); }
/**
* Takes over the value of @param o.
* - Correctly handles self assignment, i.e. if @param o ==
* object_.
* - @see the function ref() for how to create a Ref object
* conveniently from a pointer.
*/
void set(Object *o) {
const Object *old = object_;
++(object_ = o)->referenceCount_;
if (!(--old->referenceCount_)) {
verify_(Object::isNotSentinel(old));
old->free();
}
}
public:
Ref() : object_(sentinel()) { ++object_->referenceCount_; }
explicit Ref(Object *o) : object_(o) {
require_(o);
++object_->referenceCount_;
}
/**
* Copy Constructor for the Type Ref<T>
*
* @warning: Implementaion of this constructor is necesseary
* although the template copy constructor implements exactly
* the same function. If this constructor is not defined, the
* compiler creates a default copy constructor instead of
* using the template one.
*/
Ref(const Ref &r) : object_(r.object_) {
++object_->referenceCount_;
}
/**
* Template Copy Constuctor.
*
* Using a template allows automatic conversion in following cases:
* - from non-const to const reference
* - from derived to precursor class reference
* For all classes S which are not derived from T, this
* constructor will fail to compile.
*/
template<class S> Ref(const Ref<S> &r) : object_(r._get()) {
++object_->referenceCount_;
}
~Ref() {
if (!(--object_->referenceCount_)) {
verify_(Object::isNotSentinel(object_));
object_->free();
}
}
Ref &operator=(const Ref &rhs) {
set(rhs.object_);
return *this;
}
template<class S> Ref &operator=(const Ref<S> &rhs) {
set(rhs._get());
return *this;
}
/**
* Reset to void.
* Corresponds to assigning zero to normal pointer.
*/
void reset() {
if (Object::isNotSentinel(object_)) {
if (!(--object_->referenceCount_)) {
object_->free();
}
++(object_ = sentinel())->referenceCount_;
}
}
/** Test for identity */
bool operator==(const Ref &r) const {
return object_ == r.object_;
}
template<class S> bool operator==(const Ref<S> &r) const {
return object_ == r._get();
}
/** Test for non-identity */
bool operator!=(const Ref &r) const {
return object_ != r.object_;
}
template<class S> bool operator!=(const Ref<S> &r) const {
return object_ != r._get();
}
/** Test for non-voidness. */
operator bool() const {
return Object::isNotSentinel(object_);
}
/** Test for voidness. */
bool operator!() const {
return Object::isSentinel(object_);
}
Object &operator* () const {
require_(Object::isNotSentinel(object_));
return *object_;
}
Object *operator-> () const {
require_(Object::isNotSentinel(object_));
return object_;
}
/** Explicit conversion to normal pointer.
* @warning This defeats the reference counting mechanism.
* Use with caution!
*/
Object* get() const {
return Object::isNotSentinel(object_) ? object_ : 0;
}
/** Value of internal pointer.
* @warning Do not use this function. It is only used in the
* template copy contructor and the template operator= functions.
*/
Object* _get() const { return object_; }
};
/** Convenience constructors for Ref smart pointers. */
template <class T>
inline Ref<T> ref(T *o) { return Ref<T>(o); }
} // Core
#endif // _CORE_REFERENCE_COUNTING