-
Notifications
You must be signed in to change notification settings - Fork 116
/
handle.h
369 lines (342 loc) · 12.3 KB
/
handle.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
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
/*
(c) Copyright 2005, Jacob N. Smith, Erik Mckee, Texas Agricultural
Experiment Station & Texas Engineering Experiment Station.
*/
#ifndef CHILTBX_HANDLE_H
#define CHILTBX_HANDLE_H
#include<chiltbx/childef.h>
#include<chiltbx/str.h>
namespace chiltbx {
namespace handle {
struct handle_error {
handle_error ( string const& str=string() ) : what_("Error in chiltbx::handle::handle: "+str) {}
const string what () const {
return this->what_;
}
string what_;
};
// defines an arbitrary type for the default storage policy
#ifndef CHILTBX_GENERIC_HANDLE_DEFAULT_STORAGE_POLICY_TYPE
#define CHILTBX_GENERIC_HANDLE_DEFAULT_STORAGE_POLICY_TYPE chiltbx::handle::by_value
#endif
//
// ---- Policies ----
//
// interface: defines classes which templatize to be interfaces
//
// by_value: holds the value, T
// on_heap: holds the value, T* = new T
// counted: reference counted
// copy_on_write: derives from counted, copies when "written" to
//
// unsafe: the standard synchronization method
// NOTE: only synchronizes reference-counting related mechanisms!!!
// My personal experience is limited, this may need to be rewritten!!!
// IMPORTANT UPDATE: Ralph! Please help the synchronization!
//
// ---- type_* ----
//
// type_interface: carries a type and an interface to that type (a "base class")
//
// type_store: carries the back-end storage type and the front-end storage type
// allowing differently-typed back-ends to be friended to their front-end
// basically ... cheap "friend injection"
//
struct interface;
struct by_value;
struct on_heap;
struct counted;
struct copy_on_write;
struct unsafe {};
template < typename T, typename Interface > struct type_interface;
template < typename BackStore, typename FrontStore > struct type_store;
// a simple class for counting and storage
template < typename T >
struct counter {
counter () : count(0) {}
counter ( T const& t ) : count(1), value(t) {}
std::size_t count;
T value;
};
// the handle type with defaults, ole!
template < typename Interface=void,
typename Storage=CHILTBX_GENERIC_HANDLE_DEFAULT_STORAGE_POLICY_TYPE,
typename Synchronization=unsafe > class handle;
// the interface to the back-ends
template < typename Interface, typename Synch >
class handle<type_interface<interface,Interface>,void,Synch> {
public:
typedef handle<type_interface<interface,Interface>,void,Synch> h_interface;
typedef Interface* interface_type;
typedef Interface const* const_interface_type;
virtual ~ handle () {}
virtual h_interface * clone () const = 0;
virtual interface_type get () = 0;
virtual const_interface_type const_get () const = 0;
};
//
// A set of back-ends specialized over their storage mechanisms
//
//
// by_value
//
template < typename T, typename Interface, typename Storage, typename Synch >
class handle<type_interface<T,Interface>,type_store<by_value,Storage>,Synch>
: protected handle<type_interface<interface,Interface>,void,Synch> {
protected:
typedef handle<type_interface<interface,Interface>,void,Synch> h_interface;
typedef typename h_interface::interface_type interface_type;
typedef typename h_interface::const_interface_type const_interface_type;
friend class handle<Interface,Storage>;
handle () {}
handle ( T const& t ) : value_(t) {}
virtual ~ handle () {}
virtual h_interface * clone () const {
return new handle(this->value_);
}
virtual interface_type get () {
return &this->value_;
}
virtual const_interface_type const_get () const {
return &this->value_;
}
T value_;
};
//
// on_heap
// this is here for completeness' sake; I'm too lazy to figure out how to get it
// to work without breaking the API.
//
template < typename T, typename Interface, typename Storage, typename Synch >
class handle<type_interface<T,Interface>,type_store<on_heap,Storage>,Synch>
: protected handle<type_interface<interface,Interface>,void,Synch> {
protected:
typedef handle<type_interface<interface,Interface>,void,Synch> h_interface;
typedef typename h_interface::interface_type interface_type;
typedef typename h_interface::const_interface_type const_interface_type;
friend class handle<Interface,Storage>;
handle () : value_(0) {}
handle ( T const& t ) {
this->value_ = new T[1];
this->value_[0] = t;
}
virtual ~ handle () {
this->clear();
}
virtual h_interface * clone () const {
return new handle(*this->value_);
}
virtual interface_type get () {
return this->value_;
}
virtual const_interface_type const_get () const {
return this->value_;
}
void clear () {
if ( 0 != this->value_ )
delete [] this->value_;
this->value_ = 0;
}
T *value_;
};
//
// reference counted back-end
// this needs to be made synchronous-safe
//
template < typename T, typename Interface, typename Storage, typename Synch >
class handle<type_interface<T,Interface>,type_store<counted,Storage>,Synch>
: protected handle<type_interface<interface,Interface>,void,Synch> {
protected:
typedef handle<type_interface<interface,Interface>,void,Synch> h_interface;
typedef typename h_interface::interface_type interface_type;
typedef typename h_interface::const_interface_type const_interface_type;
friend class handle<Interface,Storage>;
handle () : reference_(0) {}
handle ( T const& t ) {
this->reference_ = new counter<T>(t);
}
handle ( counter<T> *ref ) {
Synch lock;
this->reference_ = ref;
++this->reference_->count;
}
virtual ~ handle () {
this->clear();
}
virtual h_interface * clone () const {
return new handle(this->reference_);
}
virtual interface_type get () {
return &this->reference_->value;
}
virtual const_interface_type const_get () const {
return &this->reference_->value;
}
void clear () {
Synch lock;
if ( 0 != this->reference_ )
--this->reference_->count;
if ( 0 == this->reference_->count )
delete this->reference_;
this->reference_ = 0;
}
counter<T> *reference_;
};
//
// copy-on-write (really simple); inherits from counted, also needs to be made
// synchronous-safe.
//
template < typename T, typename Interface, typename Storage, typename Synch >
class handle<type_interface<T,Interface>,type_store<copy_on_write,Storage>,Synch>
: protected handle<type_interface<T,Interface>,type_store<counted,Storage>,Synch> {
protected:
typedef handle<type_interface<T,Interface>,type_store<counted,Storage>,Synch> base;
typedef typename base::h_interface h_interface;
typedef typename base::interface_type interface_type;
friend class handle<Interface,Storage>;
typedef handle<type_interface<T,Interface>,type_store<copy_on_write,Storage>,Synch> self_type;
handle () : base() {}
handle ( T const& t ) : base(t) {}
handle ( counter<T> *ref ) : base(ref) {}
virtual h_interface * clone () const {
return new self_type(this->reference_);
}
virtual interface_type get () {
Synch lock;
if ( 1 == this->reference_->count )
return &this->reference_->value;
counter<T> *local_reference = new counter<T>(this->reference_->value);
--this->reference_->count;
this->reference_ = local_reference;
return &this->reference_->value;
}
};
// the end-user's handle class
//
// Interface: the base type of the pointer which is returned
// e.g.
// int -> int*
// my_base_class -> my_base_class*
// double* -> double**
//
// Storage: the storage policy
//
// Synch: the Synchronization (threading) policy
//
template < typename Interface, typename Storage, typename Synch >
class handle {
private:
typedef handle<type_interface<interface,Interface>,void,Synch> h_interface;
public:
typedef typename h_interface::interface_type interface_type;
typedef typename h_interface::const_interface_type const_interface_type;
typedef handle<Interface,Storage> self_type;
handle () {
this->handle_ = 0;
}
handle ( handle const& H ) {
this->handle_ = 0;
this->copy(H);
}
handle& operator = ( handle const& H ) {
this->copy(H);
return *this;
}
template < typename StorageP >
handle ( handle<Interface,StorageP> const& H ) {
this->handle_ = 0;
this->copy(H);
}
template < typename T >
handle ( T const& t ) {
this->handle_ = 0;
this->set(t);
}
virtual ~ handle () {
this->clear();
}
template < typename T, typename StorageP >
handle ( T const& t, StorageP ) {
this->handle_ = 0;
this->set<StorageP>(t);
}
template < typename StorageP >
handle& operator = ( handle<Interface,StorageP> const& H ) {
this->clear();
this->copy(H);
return *this;
}
template < typename T >
handle& operator = ( T const& t ) {
this->set(t);
return *this;
}
template < typename T >
void set ( T const& t ) {
this->set<Storage>(t);
}
template < typename StorageP, typename T >
void set ( T const& t ) {
this->clear();
this->handle_ = new handle<type_interface<T,Interface>,type_store<StorageP,Storage> >(t);
}
template < typename T >
T& get () {
if ( !this->empty() )
return *reinterpret_cast<T*>(this->handle_->get());
throw handle_error("Handle is empty.");
}
template < typename T >
T const& get () const {
return this->const_get<T>();
}
// this is here to /guarantee/ a constant access
template < typename T >
T const& const_get () const {
if ( !this->empty() )
return *reinterpret_cast<T const*>(this->handle_->const_get());
throw handle_error("Handle is empty.");
}
interface_type get_raw () {
if ( !this->empty() )
return this->handle_->get();
return 0;
}
const_interface_type get_raw () const {
if ( !this->empty() )
return this->handle_->const_get();
return 0;
}
// this is here to /guarantee/ a constant access
const_interface_type const_get_raw () const {
if ( !this->empty() )
return this->handle_->const_get();
return 0;
}
// pointer-like interface
interface_type operator -> () {
return this->get_raw();
}
const_interface_type operator -> () const {
return this->const_get_raw();
}
void clear () {
if ( !this->empty() )
delete this->handle_;
this->handle_ = 0;
}
template < typename StorageP >
void copy ( handle<Interface,StorageP> const& H ) {
this->clear();
if ( !H.empty() )
this->handle_ = H.handle_->clone();
}
bool empty () const {
return 0 == this->handle_;
}
private:
h_interface * handle_;
};
}// end handle namespace
}// end chiltbx namespace
#endif//CHILTBX_HANDLE_H