forked from jamespetts/simutrans-extended
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathquickstone_tpl.h
297 lines (260 loc) · 6.33 KB
/
quickstone_tpl.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
#ifndef quickstone_tpl_h
#define quickstone_tpl_h
#include "../simtypes.h"
#include "../simdebug.h"
/**
* An implementation of the tombstone pointer checking method.
* It uses a table of pointers and indices into that table to
* implement the tombstone system. Unlike real tombstones, this
* template reuses entries from the tombstone table, but it tries
* to leave freed tombstones untouched as long as possible, to
* detect most of the dangling pointers.
*
* This templates goal is to be efficient and fairly safe.
*
* @author Hj. Malthaner
*/
template <class T> class quickstone_tpl
{
private:
/**
* Array of pointers. The first entry is always NULL!
*/
static T ** data;
/**
* Next entry to check
*/
static uint16 next;
/**
* Size of tombstone table
*/
static uint16 size;
/**
* Retrieves next free tombstone index
*/
static uint16 find_next() {
uint16 i;
// scan rest of array
for( i=next; i<size; i++ ) {
if( data[i] == 0 ) {
next = i+1;
return i;
}
}
// scan whole array
for( i=1; i<size; i++ ) {
if( data[i]==0 ) {
next = i+1;
return i;
}
}
return enlarge();
}
static uint16 enlarge()
{
// no free entry found, extend array if possible
uint16 newsize;
if (size == 65535) {
// completely out of handles
dbg->fatal("quickstone<T>::find_next()","no free index found (size=%i)",size);
return 0; //dummy for compiler
} else if (size >= 32768) {
// max out on handles, don't overflow uint16
newsize = 65535;
} else {
newsize = 2*size;
}
// Move data to new extended array
T ** newdata = new T* [newsize];
memcpy( newdata, data, sizeof(T*)*size );
for( uint16 i=size; i<newsize; i++ ) {
newdata[i] = 0;
}
delete [] data;
data = newdata;
next = size+1;
size = newsize;
return next-1;
}
/**
* The index in the table for this handle.
* (only this variable is actually saved, since the rest is static!)
*/
uint16 entry;
public:
/**
* Initializes the tombstone table. Calling init() makes all existing
* quickstones invalid.
*
* @param n number of elements
* @author Hj. Malthaner
*/
static void init(const uint16 n)
{
if(data) {
delete [] data;
}
size = n;
data = new T* [size];
// all NULL pointers are mapped to entry 0
for(int i=0; i<size; i++) {
data[i] = 0;
}
next = 1;
}
// empty handle (entry 0 is always zero)
quickstone_tpl()
{
entry = 0;
}
// connects with free handle
explicit quickstone_tpl(T* p)
{
if(p) {
entry = find_next();
data[entry] = p;
}
else {
// all NULL pointers are mapped to entry 0
entry = 0;
}
}
// connects with last handle
explicit quickstone_tpl(T* p, bool)
{
uint16 i;
// scan rest of array
for( i=size-1; i>0; i++ ) {
if( data[i] == 0 ) {
entry = i;
data[entry] = p;
return;
}
}
enlarge();
// repeat
for( i=size-1; i>0; i++ ) {
if( data[i] == 0 ) {
entry = i;
data[entry] = p;
return;
}
}
dbg->fatal( "quickstone_tpl(bool)", "No more handles!\nShould have already failed with enlarge!" );
}
// creates handle with id, fails if already taken
quickstone_tpl(T* p, uint16 id)
{
if(p) {
if( id == 0 ) {
dbg->fatal("quickstone<T>::quickstone_tpl(T*,uint16)","wants to assign non-null pointer to null index");
}
while( id >= size ) {
enlarge();
}
if( data[id]!=NULL && data[id]!=p ) {
dbg->fatal("quickstone<T>::quickstone_tpl(T*,uint16)","slot (%d) already taken", id);
}
entry = id;
data[entry] = p;
}
else {
if( id!=0 ) {
dbg->fatal("quickstone<T>::quickstone_tpl(T*,uint16)","wants to assign null pointer to non-null index");
}
assert(id==0);
// all NULL pointers are mapped to entry 0
entry = 0;
}
}
quickstone_tpl(const quickstone_tpl& r) : entry(r.entry) {}
// returns true, if no handles left
static bool is_exhausted()
{
if( size==65535 ) {
// scan array
for( uint16 i = 1; i<size; i++) {
if(data[i] == 0) {
// still empty handles left
return false;
}
}
// no handles left => cannot extent
return true;
}
// can extent in any case => ok
return false;
}
inline bool is_bound() const
{
return data[entry] != 0;
}
inline bool is_null() const
{
return entry == 0;
}
/**
* Removes the object from the tombstone table - this affects all
* handles to the object!
* @author Hj. Malthaner
*/
T* detach()
{
T* p = data[entry];
data[entry] = 0;
return p;
}
/**
* Danger - use with care.
* Useful to hand the underlying pointer to subsystems
* that don't know about quickstones - but take care that such pointers
* are never ever deleted or that by some means detach() is called
* upon deletion, i.e. from the ~T() destructor!!!
*
* @author Hj. Malthaner
*/
T* get_rep() const { return data[entry]; }
/**
* @return the index into the tombstone table. May be used as
* an ID for the referenced object.
*/
uint16 get_id() const { return entry; }
/**
* For read/write from/to any storage (file or memory) with the appropriate interface
* @author Knightly
*/
template <class STORAGE>
void rdwr(STORAGE *store) { store->rdwr_short(entry); }
/**
* Sets the current id: Needed to recreate stuff via network.
* ATTENTION: This may be harmful. DO not use unless really really needed!
*/
void set_id(uint16 e) { entry=e; }
/**
* Overloaded dereference operator. With this, quickstones can
* be used as if they were pointers.
*
* @author Hj. Malthaner
*/
T* operator->() const { return data[entry]; }
T& operator *() const { return *data[entry]; }
bool operator== (const quickstone_tpl<T> &other) const { return entry == other.entry; }
bool operator!= (const quickstone_tpl<T> &other) const { return entry != other.entry; }
// Added by : Knightly
// Purpose : For sorting of handles according to internal value of entry
bool operator<= (const quickstone_tpl<T> &other) const
{
return entry <= other.entry;
}
static uint16 get_size() { return size; }
/**
* For checking the consistency of handle allocation
* among the server and the clients in network mode
* @author Knightly
*/
static uint16 get_next_check() { return next; }
};
template <class T> T** quickstone_tpl<T>::data = 0;
template <class T> uint16 quickstone_tpl<T>::next = 1;
template <class T> uint16 quickstone_tpl<T>::size = 0;
#endif