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