-
Notifications
You must be signed in to change notification settings - Fork 0
/
sli_lockobj.h
322 lines (254 loc) · 6.34 KB
/
sli_lockobj.h
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
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
/*
* lockptr.h
*
* This file is part of NEST
*
* Copyright (C) 2004 by
* The NEST Initiative
*
* See the file AUTHORS for details.
*
* Permission is granted to compile and modify
* this file for non-commercial use.
* See the file LICENSE for details.
*
*/
#ifndef LOCK_PTR_H
#define LOCK_PTR_H
#ifdef NDEBUG
#define LOCK_PTR_NDEBUG
#endif
#include <cassert>
#include <cstddef>
/**
\class lockPTR
This template is the standard safe-pointer implementation
of SYNOD.
In order for this scheme to work smoothly, the user has to take some
precautions:
1. each pointer should only be used ONCE to initialize a lockPTR.
2. The lockPTR assumes that there are no other access points to the
protected pointer.
3. The lockPTR can freely be copied and passed between objects and functions.
4. lockPTR objects should be used like the pointer to the object.
5. lockPTR objects should be passed as objects in function calls and
function return values.
6. There should be no pointers to lockPTR objects.
Class lockPTR is designed to behave just like the pointer would. You
can use the dereference operators (* and ->) to access the protected
object. However, the pointer itself is (with exceptions) never
exposed to the user.
Since all access to the referenced object is done via a lockPTR, it
is possible to maintain a count of all active references. If this
count dropts to zero, the referenced object can savely be destroyed.
For dynamically allocated objects, delete is envoked on the stored
pointer.
class lockPTR distinguishes between dynamically and automatically
allocated objects by the way it is initialised:
If a lockPTR is initialised with a pointer, it assumes that the
referenced object was dynamically allocated and will call the
destructor once the reference count drops to zero.
If the lockPTR is initialised with a reference, it assumes that the
object is automatically allocated. Thus, the lockPTR wil NOT call the
destructor.
In some cases it is necessary for a routine to actually get hold of
the pointer, contained in the lockPTR object. This can be done by
using the member function get(). After the pointer has been exposed
this way, the lockPTR will regard the referenced object as unsafe,
since the user might call delete on the pointer. Thus, lockPTR will
"lock" the referenced object and deny all further access.
The object can be unlocked by calling the unlock() member.
*/
template <class D>
class RefObj
{
protected:
D data_;
mutable size_t number_of_references_;
bool locked_; //!< object is const when locked_ is true.
bool clone_on_write_; //!< If true, the object is cloned on write if multiple references exist.
public:
RefObj();
RefObj(D&);
RefObj(const RefObj&);
~RefObj();
size_t add_reference(void) const
{
return ++number_of_references_;
}
size_t remove_reference(void)
{
--number_of_references_;
if(number_of_references_ == 0)
{
delete this;
}
return number_of_references_;
}
size_t references(void) const
{
return number_of_references_;
}
bool is_locked(void) const
{
return locked_;
}
bool clone_on_write(void) const
{
return clone_on_write_;
}
void lock(void)
{
locked_ = true;
}
void unlock(void)
{
locked_ = false;
}
const D& get(void) const
{
return data_;
}
D& get(void)
{
return data_;
}
};
template<class D>
class lockPtr
{
RefObject *obj;
public:
// lockPTR() ; // generated automatically.
// The default, argumentless constructor is used in
// class declarations and generates an empty lockPTR
// object which must then be initialised, for example
// by assignement.
explicit lockPTR(D* p=NULL)
{
obj = new PointerObject(p);
assert(obj != NULL);
}
explicit lockPTR(D& p_o)
{
obj = new PointerObject(p_o);
assert(obj != NULL);
}
lockPTR(const lockPTR<D>& spd)
: obj(spd.obj)
{
assert(obj != NULL);
obj->addReference();
}
virtual ~lockPTR()
{
assert(obj != NULL);
obj->removeReference();
}
lockPTR<D> operator=(const lockPTR<D>&spd)
{
// assert(obj != NULL);
// assert(spd.obj != NULL);
// The following order of the expressions protects
// against a=a;
spd.obj->addReference();
obj->removeReference();
obj = spd.obj;
return *this;
}
lockPTR<D> operator=(D &s)
{
*this = lockPTR<D>(s);
assert(!(obj->isdeletable()));
return *this;
}
lockPTR<D> operator=(D const &s)
{
*this = lockPTR<D>(s);
assert(!(obj->isdeletable()));
return *this;
}
D* get(void)
{
assert(!obj->islocked());
obj->lock(); // Try to lock Object
return obj->get();
}
D* get(void) const
{
assert(!obj->islocked());
obj->lock(); // Try to lock Object
return obj->get();
}
D* operator->() const
{
assert(obj->get() != NULL);
return obj->get();
}
D* operator->()
{
assert(obj->get() != NULL);
return obj->get();
}
D& operator*()
{
assert(obj->get() != NULL);
return *(obj->get());
}
const D& operator*() const
{
assert(obj->get() != NULL);
return *(obj->get());
}
bool operator!() const //!< returns true if and only if obj->pointee == NULL
{
// assert(obj != NULL);
return (obj->get() == NULL);
}
bool operator==(const lockPTR<D>& p) const
{
return (obj == p.obj);
}
bool operator!=(const lockPTR<D>& p) const
{
return (obj != p.obj);
}
bool valid(void) const //!< returns true if and only if obj->pointee != NULL
{
assert(obj != NULL);
return (obj->get() != NULL);
}
bool islocked(void) const
{
assert(obj != NULL);
return (obj->islocked());
}
bool deletable(void) const
{
assert(obj != NULL);
return (obj->isdeletable());
}
void lock(void) const
{
assert(obj!=NULL);
obj->lock();
}
void unlock(void) const
{
assert(obj!=NULL);
obj->unlock();
}
void unlock(void)
{
assert(obj!=NULL);
obj->unlock();
}
size_t references(void) const
{
return (obj==NULL)? 0: obj->references();
}
};
#ifndef LOCK_PTR_NDEBUG
#undef NDEBUG
#endif
#endif