1 /*****************************************************************************/
5 /* Collection (dynamic array) */
9 /* (C) 2000-2001 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
48 /*****************************************************************************/
50 /*****************************************************************************/
54 /* An empty collection */
55 const Collection EmptyCollection = STATIC_COLLECTION_INITIALIZER;
59 /*****************************************************************************/
61 /*****************************************************************************/
65 Collection* InitCollection (Collection* C)
66 /* Initialize a collection and return it. */
68 /* Intialize the fields. */
73 /* Return the new struct */
79 void DoneCollection (Collection* C)
80 /* Free the data for a collection. This will not free the data contained in
84 /* Free the pointer array */
90 Collection* NewCollection (void)
91 /* Create and return a new collection with the given initial size */
93 /* Allocate memory, intialize the collection and return it */
94 return InitCollection (xmalloc (sizeof (Collection)));
99 void FreeCollection (Collection* C)
100 /* Free a collection */
105 /* Free the structure itself */
111 void CollInsert (Collection* C, void* Item, unsigned Index)
112 /* Insert the data at the given position in the collection */
114 /* Check for invalid indices */
115 PRECONDITION (Index <= C->Count);
117 /* Grow the array if necessary */
118 if (C->Count >= C->Size) {
126 NewItems = xmalloc (C->Size * sizeof (void*));
127 memcpy (NewItems, C->Items, C->Count * sizeof (void*));
132 /* Move the existing elements if needed */
133 if (C->Count != Index) {
134 memmove (C->Items+Index+1, C->Items+Index, (C->Count-Index) * sizeof (void*));
138 /* Store the new item */
139 C->Items[Index] = Item;
144 int CollIndex (Collection* C, const void* Item)
145 /* Return the index of the given item in the collection. Return -1 if the
146 * item was not found in the collection.
151 for (I = 0; I < C->Count; ++I) {
152 if (Item == C->Items[I]) {
164 void CollDelete (Collection* C, unsigned Index)
165 /* Remove the item with the given index from the collection. This will not
166 * free the item itself, just the pointer. All items with higher indices
167 * will get moved to a lower position.
170 /* Check the index */
171 PRECONDITION (Index < C->Count);
173 /* Remove the item pointer */
175 memmove (C->Items+Index, C->Items+Index+1, (C->Count-Index) * sizeof (void*));
180 void CollDeleteItem (Collection* C, const void* Item)
181 /* Delete the item pointer from the collection. The item must be in the
182 * collection, otherwise FAIL will be called.
185 /* Get the index of the entry */
186 int Index = CollIndex (C, Item);
189 /* Delete the item with this index */
191 memmove (C->Items+Index, C->Items+Index+1, (C->Count-Index) * sizeof (void*));
196 void CollMove (Collection* C, unsigned OldIndex, unsigned NewIndex)
197 /* Move an item from one position in the collection to another. OldIndex
198 * is the current position of the item, NewIndex is the new index after
199 * the function has done it's work. Existing entries with indices NewIndex
200 * and up are moved one position upwards.
203 /* Get the item and remove it from the collection */
204 void* Item = CollAt (C, OldIndex);
205 CollDelete (C, OldIndex);
207 /* Correct NewIndex if needed */
208 if (NewIndex >= OldIndex) {
209 /* Position has changed with removal */
213 /* Now insert it at the new position */
214 CollInsert (C, Item, NewIndex);
219 void CollMoveMultiple (Collection* C, unsigned Start, unsigned Count, unsigned Target)
220 /* Move a range of items from one position to another. Start is the index
221 * of the first item to move, Count is the number of items and Target is
222 * the index of the target item. The item with the index Start will later
223 * have the index Target. All items with indices Target and above are moved
230 /* Check the range */
231 PRECONDITION (Start < C->Count && Start + Count <= C->Count && Target <= C->Count);
233 /* Check for trivial parameters */
234 if (Count == 0 || Start == Target) {
238 /* Calculate the raw memory space used by the items to move */
239 Bytes = Count * sizeof (void*);
241 /* Allocate temporary storage for the items */
242 TmpItems = xmalloc (Bytes);
244 /* Copy the items we have to move to the temporary storage */
245 memcpy (TmpItems, C->Items + Start, Bytes);
247 /* Check if the range has to be moved upwards or downwards. Move the
248 * existing items to their final location, so that the space needed
249 * for the items now in temporary storage is unoccupied.
251 if (Target < Start) {
254 unsigned BytesToMove = (Start - Target) * sizeof (void*);
255 memmove (C->Items+Target+Count, C->Items+Target, BytesToMove);
257 } else if (Target < Start + Count) {
259 /* Target is inside range */
260 FAIL ("Not supported");
265 unsigned ItemsToMove = (Target - Start - Count);
266 unsigned BytesToMove = ItemsToMove * sizeof (void*);
267 memmove (C->Items+Start, C->Items+Target-ItemsToMove, BytesToMove);
269 /* Adjust the target index */
273 /* Move the old items to their final location */
274 memcpy (C->Items + Target, TmpItems, Bytes);
276 /* Delete the temporary item space */
282 static void QuickSort (Collection* C, int Lo, int Hi,
283 int (*Compare) (void*, const void*, const void*),
285 /* Internal recursive sort function. */
287 /* Get a pointer to the items */
288 void** Items = C->Items;
295 while (I <= J && Compare (Data, Items[Lo], Items[I]) >= 0) {
298 while (I <= J && Compare (Data, Items[Lo], Items[J]) < 0) {
303 void* Tmp = Items[I];
312 void* Tmp = Items[J];
313 Items[J] = Items[Lo];
316 if (J > (Hi + Lo) / 2) {
317 QuickSort (C, J + 1, Hi, Compare, Data);
320 QuickSort (C, Lo, J - 1, Compare, Data);
328 void CollSort (Collection* C,
329 int (*Compare) (void*, const void*, const void*),
331 /* Sort the collection using the given compare function. The data pointer is
332 * passed as *first* element to the compare function, it's not used by the
333 * sort function itself. The other two pointer passed to the Compare function
334 * are pointers to objects.
338 QuickSort (C, 0, C->Count-1, Compare, Data);