1 /*****************************************************************************/
2 /* */
3 /* COLL.H */
4 /* */
5 /* (C) 1993-95 Ullrich von Bassewitz */
6 /* Zwehrenbuehlstrasse 33 */
7 /* D-72070 Tuebingen */
8 /* EMail: uz@ibb.schwaben.com */
9 /* */
10 /*****************************************************************************/
11
12
13
14 // $Id$
15 //
16 // $Log$
17 //
18 //
19
20
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <iostream>
25
26 #include "machine.h"
27 #include "check.h"
28 #include "object.h"
29 #include "stream.h"
30 #include "coll.h"
31
32
33
34
35 // Pointer to error routine
36 void (*CollectionError) (int) = NULL;
37
38
39
40 /*****************************************************************************/
41 /* class _Collection */
42 /*****************************************************************************/
43
44
45
46 // This is a base class for the template class Collection that has full
47 // functionality but uses void pointers instead of typed pointers. The
48 // implementation of class Collection consists merely of inline functions
49 // calling the derived member functions and casting when necessary. This will
50 // hopefully help to decrease program size.
51
52
53
_Collection(StreamableInit)54 _Collection::_Collection (StreamableInit):
55 Items (0)
56 {
57 }
58
59
60
_Collection(int aLimit,int aDelta,int aShouldDelete)61 _Collection::_Collection (int aLimit, int aDelta, int aShouldDelete):
62 ShouldDelete (aShouldDelete)
63 {
64 // check parameters
65 if (aLimit < 0 || aDelta < 0 || (aLimit + aDelta) == 0 ||
66 aLimit > MaxCollectionSize || aDelta > MaxCollectionSize) {
67 FAIL ("_Collection::_Collection: Overflow error");
68 return;
69 }
70
71 // get values - one of <aLimit, aDelta> is != 0
72 Limit = aLimit ? aLimit : aDelta;
73 Delta = aDelta;
74 Count = 0;
75
76 // allocate memory
77 Items = AllocItemSpace (Limit);
78 }
79
80
81
~_Collection()82 _Collection::~_Collection ()
83 {
84 // Release allocated memory but do not try to call DeleteAll (this calls
85 // FreeItem, but _Collection::FreeItem will call ABSTRACT)
86 FreeItemSpace (Items);
87 }
88
89
90
At(int Index)91 void* _Collection::At (int Index)
92 {
93 // Check range
94 if (Index < 0 || Index >= Count) {
95 FAIL ("_Collection::At: Index out of bounds");
96 return NULL;
97 }
98
99 return Items [Index];
100 }
101
102
103
At(int Index) const104 const void* _Collection::At (int Index) const
105 {
106 // Check range
107 if (Index < 0 || Index >= Count) {
108 FAIL ("_Collection::At: Index out of bounds");
109 return NULL;
110 }
111
112 return Items [Index];
113 }
114
115
116
AtDelete(int Index)117 void _Collection::AtDelete (int Index)
118 {
119 // Check range
120 if (Index < 0 || Index >= Count) {
121 FAIL ("_Collection::AtDelete: Index out of bounds");
122 return;
123 }
124
125 // Free entry if necessary
126 if (ShouldDelete) {
127 FreeItem (Items [Index]);
128 }
129
130 // Delete entry
131 Count--;
132 memmove (Items + Index, Items + Index + 1, (Count - Index) * sizeof (void*));
133 }
134
135
136
AtInsert(int Index,void * Item)137 void _Collection::AtInsert (int Index, void* Item)
138 {
139 // Check range, Index may be one more than the index of the last element
140 if (Index < 0 || Index > Count) {
141 FAIL ("_Collection::AtInsert: Index out of bounds");
142 return;
143 }
144
145 // Check if the collection must grow
146 if (Count == Limit) {
147 // Increase size, check if possible
148 if (Delta == 0 || (Limit + Delta) > MaxCollectionSize) {
149 // Cannot grow
150 FAIL ("_Collection::AtInsert: Overflow error");
151 return;
152 }
153
154 // Change the size
155 SetLimit (Limit + Delta);
156 }
157
158 // We can insert the element. If the item is not inserted at the end
159 // of the collection, we must create a "hole"
160 if (Count != Index) {
161 memmove (Items + Index + 1, Items + Index, (Count - Index) * sizeof (void*));
162 }
163 Count++;
164
165 // store the new item
166 Items [Index] = Item;
167 }
168
169
170
AtReplace(int Index,void * Item)171 void _Collection::AtReplace (int Index, void* Item)
172 {
173 // check range
174 if (Index < 0 || Index >= Count) {
175 FAIL ("_Collection::AtReplace: Index out of bounds");
176 return;
177 }
178
179 // Free item if necessary
180 if (ShouldDelete) {
181 FreeItem (Items [Index]);
182 }
183
184 // Store item
185 Items [Index] = Item;
186 }
187
188
189
Delete(void * Item)190 void _Collection::Delete (void* Item)
191 {
192 int Index = IndexOf (Item);
193
194 if (Index != -1) {
195 if (ShouldDelete) {
196 FreeItem (Items [Index]);
197 }
198 Items [Index] = NULL;
199 }
200 }
201
202
203
DeleteAll()204 void _Collection::DeleteAll ()
205 {
206 if (ShouldDelete) {
207 while (Count) {
208 FreeItem (Items [--Count]);
209 }
210 } else {
211 Count = 0;
212 }
213 }
214
215
216
Traverse(int Forward,int (* Func)(void *,void *),void * UserData)217 void* _Collection::Traverse (int Forward, int (*Func) (void*, void*),
218 void* UserData)
219 {
220 int I;
221 void** P;
222
223 if (Forward) {
224 for (I = 0, P = Items; I < Count; I++, P++) {
225 if (Func (*P, UserData) != 0) {
226 // stop and return current
227 return *P;
228 }
229 }
230 } else {
231 for (I = Count-1, P = Items + I; I >= 0; I--, P--) {
232 if (Func (*P, UserData) != 0) {
233 // stop and return current
234 return *P;
235 }
236 }
237 }
238 // Not found
239 return NULL;
240
241 }
242
243
244
FreeItem(void *)245 void _Collection::FreeItem (void*)
246 {
247 ABSTRACT ();
248 }
249
250
251
GetItem(Stream & S)252 void* _Collection::GetItem (Stream& S)
253 {
254 // Assume it's some sort of object
255 return S.Get ();
256 }
257
258
259
AllocItemSpace(int ItemCount)260 void** _Collection::AllocItemSpace (int ItemCount)
261 // Allocate item space
262 {
263 return new void* [ItemCount];
264 }
265
266
267
FreeItemSpace(void ** Space)268 void _Collection::FreeItemSpace (void** Space)
269 // Deallocate item space
270 {
271 delete [] Space;
272 }
273
274
275
IndexOf(const void * Item)276 int _Collection::IndexOf (const void* Item)
277 {
278 int C;
279 void** I;
280
281 // generic collection "features" a linear search
282 for (C = 0, I = Items; C < Count; C++, I++) {
283 if (*I == Item) {
284 return C;
285 }
286 }
287
288 // Not found
289 return -1;
290 }
291
292
293
Insert(void * Item)294 void _Collection::Insert (void* Item)
295 {
296 // Default is to add the item at the end
297 AtInsert (Count, Item);
298 }
299
300
301
Pack()302 void _Collection::Pack ()
303 {
304 int I, J;
305
306 for (I = 0; I < Count; I++) {
307
308 // Try to find a NULL pointer
309 if (Items [I] == NULL) {
310
311 // Count the number of NULL pointers in a row
312 J = I+1;
313 while (J < Count && Items [J] == NULL) {
314 J++;
315 }
316
317 // Delete those NULL pointers
318 memmove (Items + I, Items + J, (Count - J) * sizeof (void*));
319
320 // Update Count
321 Count -= J - I;
322
323 }
324
325 }
326
327 }
328
329
330
PutItem(Stream & S,void * Item) const331 void _Collection::PutItem (Stream& S, void* Item) const
332 {
333 // Assume it's a streamable object
334 S.Put ((Streamable*) Item);
335 }
336
337
338
SetLimit(int aLimit)339 void _Collection::SetLimit (int aLimit)
340 {
341 // Limit the new limit
342 if (aLimit < Count) {
343 aLimit = Count;
344 } else if (aLimit > MaxCollectionSize) {
345 aLimit = MaxCollectionSize;
346 }
347
348 // allocate memory
349 void** P = AllocItemSpace (aLimit);
350
351 // Copy old data into new array
352 memcpy (P, Items, Count * sizeof (void*));
353
354 // Release old memory
355 FreeItemSpace (Items);
356
357 // Remember new array and limit
358 Items = P;
359 Limit = aLimit;
360 }
361
362
363
Load(Stream & S)364 void _Collection::Load (Stream& S)
365 {
366 // The build constructor sets Items to 0. So, if Items is *not* 0 now,
367 // someone is calling Load (or operator <<) with existing data. Do the
368 // best we can to imitate builtin data types in this case and delete the
369 // existing stuff before reloading.
370 if (Items) {
371 // Delete all items, then delete the item space
372 DeleteAll ();
373 FreeItemSpace (Items);
374 }
375
376 // Read correct size
377 u32 aCount, aDelta, aLimit;
378 u16 aShouldDelete;
379 S >> aCount;
380 S >> aDelta; Delta = aDelta;
381 S >> aLimit; Limit = aLimit;
382 S >> aShouldDelete; ShouldDelete = aShouldDelete;
383
384 // allocate memory
385 Items = AllocItemSpace (Limit);
386
387 // Read items. Do not insert them directly but use Insert. This causes
388 // nearly no spead penalty on collections and only little on
389 // SortedCollections, but does a re-sort if the sort order of a
390 // SortedColl has changed (String ordering according to national
391 // conventions for example).
392 Count = 0;
393 while (aCount--) {
394 Insert (GetItem (S));
395 }
396
397 }
398
399
400
Store(Stream & S) const401 void _Collection::Store (Stream& S) const
402 {
403 // Write correct size
404 u32 aCount = (u32) Count;
405 u32 aDelta = (u32) Delta;
406 u32 aLimit = (u32) Limit;
407 u16 aShouldDelete = (u16) ShouldDelete;
408
409 // Write data
410 S << aCount << aDelta << aLimit << aShouldDelete;
411
412 // Write items
413 for (int I = 0; I < Count; I++) {
414 PutItem (S, Items [I]);
415 }
416
417 }
418
419
420
421
422