5 #define MAX(a,b) (((a)>(b)) ? (a) : (b))
6 #define MIN(a,b) (((a)<(b)) ? (a) : (b))
7 #define CAT4CHARS(a,b,c,d) ((a<<24) | (b<<16) | (c<<8) | d)
9 /* increase list size by 10% every time it is full */
10 #define kDefaultAllocationPercentIncrease 10
12 /* always increase list size by 4 items when it is full */
13 #define kDefaultAllocationminNumItemsIncrease 4
16 * how many items to expand the list by when it becomes full
17 * = current listSize (in items) + (hiword percent of list size) + loword
19 #define NUMITEMSPERALLOC(list) MAX(((*list)->listSize * \
20 ((*list)->percentIncrease + 100)) / 100, \
21 (*list)->minNumItemsIncrease )
23 #define ITEMPTR(list,item) &(((char *)&(*list)->itemList)[(*(list))->itemSize * (item)])
25 #define LIST_SIGNATURE CAT4CHARS('L', 'I', 'S', 'T');
27 #define calloc(size,num) malloc(size*num)
29 /********************************************************************/
31 Handle
NewHandle (unsigned int numBytes
)
36 memPtr
= calloc (numBytes
, 1);
37 hanPtr
= (HandleRecord
*) calloc (sizeof (HandleRecord
), 1);
38 if (hanPtr
&& (memPtr
|| numBytes
== 0)) {
40 hanPtr
->size
= numBytes
;
41 return (Handle
) hanPtr
;
48 /********************************************************************/
50 void DisposeHandle (Handle handle
)
54 free ((void *) handle
);
57 /********************************************************************/
59 unsigned int GetHandleSize (Handle handle
)
61 return ((HandleRecord
*) handle
)->size
;
63 /********************************************************************/
65 int SetHandleSize (Handle handle
, unsigned int newSize
)
67 HandleRecord
*hanRecPtr
= (HandleRecord
*) handle
;
68 void *newPtr
, *oldPtr
;
72 oldPtr
= hanRecPtr
->ptr
;
73 oldSize
= hanRecPtr
->size
;
75 if (oldSize
== newSize
)
79 newPtr
= malloc (newSize
);
81 newPtr
= realloc (oldPtr
, newSize
);
83 if (newPtr
|| (newSize
== 0)) {
84 hanRecPtr
->ptr
= newPtr
;
85 hanRecPtr
->size
= newSize
;
86 if (newSize
> oldSize
)
87 memset ((char *) newPtr
+ oldSize
, 0, newSize
- oldSize
);
93 #ifdef CFG_ALL_LIST_FUNCTIONS
95 /* Used to compare list elements by their raw data contents */
96 static int ListMemBlockCmp (void *a
, void *b
, int size
)
98 return memcmp (a
, b
, size
);
101 /***************************************************************************/
104 * Binary search numElements of size elementSize in array for a match
105 * to the. item. Return the index of the element that matches
106 * (0 - numElements - 1). If no match is found return the -i-1 where
107 * i is the index (0 - numElements) where the item should be placed.
108 * (*theCmp)(a,b) should return <0 if a<b, 0 if a==b, >0 if a>b.
110 * This function is like the C-Library function bsearch() except that
111 * this function returns the index where the item should be placed if
114 int BinSearch ( void *array
, int numElements
, int elementSize
,
115 void *itemPtr
, CompareFunction compareFunction
)
117 int low
, high
, mid
, cmp
;
120 for (low
= 0, high
= numElements
- 1, mid
= 0, cmp
= -1; low
<= high
;) {
121 mid
= (low
+ high
) >> 1;
123 arrayItemPtr
= (void *) (((char *) array
) + (mid
* elementSize
));
124 cmp
= compareFunction
125 ? compareFunction (itemPtr
, arrayItemPtr
)
126 : ListMemBlockCmp (itemPtr
, arrayItemPtr
, elementSize
);
129 } else if (cmp
< 0) {
141 #endif /* CFG_ALL_LIST_FUNCTIONS */
143 /*******************************************************************************/
146 * If numNewItems == 0 then expand the list by the number of items
147 * indicated by its allocation policy.
148 * If numNewItems > 0 then expand the list by exactly the number of
150 * If numNewItems < 0 then expand the list by the absolute value of
151 * numNewItems plus the number of items indicated by its allocation
153 * Returns 1 for success, 0 if out of memory
155 static int ExpandListSpace (list_t list
, int numNewItems
)
157 if (numNewItems
== 0) {
158 numNewItems
= NUMITEMSPERALLOC (list
);
159 } else if (numNewItems
< 0) {
160 numNewItems
= (-numNewItems
) + NUMITEMSPERALLOC (list
);
163 if (SetHandleSize ((Handle
) list
,
164 sizeof (ListStruct
) +
166 numNewItems
) * (*list
)->itemSize
)) {
167 (*list
)->listSize
+= numNewItems
;
174 /*******************************/
176 #ifdef CFG_ALL_LIST_FUNCTIONS
179 * This function reallocate the list, minus any currently unused
180 * portion of its allotted memory.
182 void ListCompact (list_t list
)
185 if (!SetHandleSize ((Handle
) list
,
186 sizeof (ListStruct
) +
187 (*list
)->numItems
* (*list
)->itemSize
)) {
191 (*list
)->listSize
= (*list
)->numItems
;
194 #endif /* CFG_ALL_LIST_FUNCTIONS */
196 /*******************************/
198 list_t
ListCreate (int elementSize
)
202 list
= (list_t
) (NewHandle (sizeof (ListStruct
))); /* create empty list */
204 (*list
)->signature
= LIST_SIGNATURE
;
205 (*list
)->numItems
= 0;
206 (*list
)->listSize
= 0;
207 (*list
)->itemSize
= elementSize
;
208 (*list
)->percentIncrease
= kDefaultAllocationPercentIncrease
;
209 (*list
)->minNumItemsIncrease
=
210 kDefaultAllocationminNumItemsIncrease
;
216 /*******************************/
218 void ListSetAllocationPolicy (list_t list
, int minItemsPerAlloc
,
219 int percentIncreasePerAlloc
)
221 (*list
)->percentIncrease
= percentIncreasePerAlloc
;
222 (*list
)->minNumItemsIncrease
= minItemsPerAlloc
;
225 /*******************************/
227 void ListDispose (list_t list
)
229 DisposeHandle ((Handle
) list
);
231 /*******************************/
233 #ifdef CFG_ALL_LIST_FUNCTIONS
235 void ListDisposePtrList (list_t list
)
241 numItems
= ListNumItems (list
);
243 for (index
= 1; index
<= numItems
; index
++)
244 free (*(void **) ListGetPtrToItem (list
, index
));
250 /*******************************/
253 * keeps memory, resets the number of items to 0
255 void ListClear (list_t list
)
259 (*list
)->numItems
= 0;
262 /*******************************/
265 * copy is only as large as necessary
267 list_t
ListCopy (list_t originalList
)
269 list_t tempList
= NULL
;
275 tempList
= ListCreate ((*originalList
)->itemSize
);
277 numItems
= ListNumItems (originalList
);
279 if (!SetHandleSize ((Handle
) tempList
,
280 sizeof (ListStruct
) +
281 numItems
* (*tempList
)->itemSize
)) {
282 ListDispose (tempList
);
286 (*tempList
)->numItems
= (*originalList
)->numItems
;
287 (*tempList
)->listSize
= (*originalList
)->numItems
;
288 (*tempList
)->itemSize
= (*originalList
)->itemSize
;
289 (*tempList
)->percentIncrease
= (*originalList
)->percentIncrease
;
290 (*tempList
)->minNumItemsIncrease
=
291 (*originalList
)->minNumItemsIncrease
;
293 memcpy (ITEMPTR (tempList
, 0), ITEMPTR (originalList
, 0),
294 numItems
* (*tempList
)->itemSize
);
300 /********************************/
303 * list1 = list1 + list2
305 int ListAppend (list_t list1
, list_t list2
)
307 int numItemsL1
, numItemsL2
;
314 if ((*list1
)->itemSize
!= (*list2
)->itemSize
)
317 numItemsL1
= ListNumItems (list1
);
318 numItemsL2
= ListNumItems (list2
);
323 if (!SetHandleSize ((Handle
) list1
,
324 sizeof (ListStruct
) + (numItemsL1
+ numItemsL2
) *
325 (*list1
)->itemSize
)) {
329 (*list1
)->numItems
= numItemsL1
+ numItemsL2
;
330 (*list1
)->listSize
= numItemsL1
+ numItemsL2
;
332 memmove (ITEMPTR (list1
, numItemsL1
),
334 numItemsL2
* (*list2
)->itemSize
);
339 #endif /* CFG_ALL_LIST_FUNCTIONS */
341 /*******************************/
344 * returns 1 if the item is inserted, returns 0 if out of memory or
345 * bad arguments were passed.
347 int ListInsertItem (list_t list
, void *ptrToItem
, int itemPosition
)
349 return ListInsertItems (list
, ptrToItem
, itemPosition
, 1);
352 /*******************************/
354 int ListInsertItems (list_t list
, void *ptrToItems
, int firstItemPosition
,
355 int numItemsToInsert
)
357 int numItems
= (*list
)->numItems
;
359 if (firstItemPosition
== numItems
+ 1)
360 firstItemPosition
= LIST_END
;
361 else if (firstItemPosition
> numItems
)
364 if ((*list
)->numItems
>= (*list
)->listSize
) {
365 if (!ExpandListSpace (list
, -numItemsToInsert
))
369 if (firstItemPosition
== LIST_START
) {
371 /* special case for empty list */
372 firstItemPosition
= LIST_END
;
374 firstItemPosition
= 1;
378 if (firstItemPosition
== LIST_END
) { /* add at the end of the list */
380 memcpy (ITEMPTR (list
, numItems
), ptrToItems
,
381 (*list
)->itemSize
* numItemsToInsert
);
383 memset (ITEMPTR (list
, numItems
), 0,
384 (*list
)->itemSize
* numItemsToInsert
);
386 (*list
)->numItems
+= numItemsToInsert
;
387 } else { /* move part of list up to make room for new item */
388 memmove (ITEMPTR (list
, firstItemPosition
- 1 + numItemsToInsert
),
389 ITEMPTR (list
, firstItemPosition
- 1),
390 (numItems
+ 1 - firstItemPosition
) * (*list
)->itemSize
);
393 memmove (ITEMPTR (list
, firstItemPosition
- 1), ptrToItems
,
394 (*list
)->itemSize
* numItemsToInsert
);
396 memset (ITEMPTR (list
, firstItemPosition
- 1), 0,
397 (*list
)->itemSize
* numItemsToInsert
);
399 (*list
)->numItems
+= numItemsToInsert
;
405 #ifdef CFG_ALL_LIST_FUNCTIONS
407 /*******************************/
409 int ListEqual (list_t list1
, list_t list2
)
414 if (list1
== NULL
|| list2
== NULL
)
417 if ((*list1
)->itemSize
== (*list1
)->itemSize
) {
418 if ((*list1
)->numItems
== (*list2
)->numItems
) {
419 return (memcmp (ITEMPTR (list1
, 0), ITEMPTR (list2
, 0),
420 (*list1
)->itemSize
* (*list1
)->numItems
) == 0);
427 /*******************************/
430 * The item pointed to by ptrToItem is copied over the current item
433 void ListReplaceItem (list_t list
, void *ptrToItem
, int itemPosition
)
435 ListReplaceItems (list
, ptrToItem
, itemPosition
, 1);
438 /*******************************/
441 * The item pointed to by ptrToItems is copied over the current item
444 void ListReplaceItems ( list_t list
, void *ptrToItems
,
445 int firstItemPosition
, int numItemsToReplace
)
448 if (firstItemPosition
== LIST_END
)
449 firstItemPosition
= (*list
)->numItems
;
450 else if (firstItemPosition
== LIST_START
)
451 firstItemPosition
= 1;
453 memmove (ITEMPTR (list
, firstItemPosition
- 1), ptrToItems
,
454 (*list
)->itemSize
* numItemsToReplace
);
457 /*******************************/
459 void ListGetItem (list_t list
, void *itemDestination
, int itemPosition
)
461 ListGetItems (list
, itemDestination
, itemPosition
, 1);
464 #endif /* CFG_ALL_LIST_FUNCTIONS */
466 /*******************************/
468 #if defined(CFG_ALL_LIST_FUNCTIONS) || defined(CFG_DEVICE_DEREGISTER)
470 void ListRemoveItem (list_t list
, void *itemDestination
, int itemPosition
)
472 ListRemoveItems (list
, itemDestination
, itemPosition
, 1);
475 /*******************************/
477 void ListRemoveItems (list_t list
, void *itemsDestination
,
478 int firstItemPosition
, int numItemsToRemove
)
480 int firstItemAfterChunk
, numToMove
;
482 if (firstItemPosition
== LIST_START
)
483 firstItemPosition
= 1;
484 else if (firstItemPosition
== LIST_END
)
485 firstItemPosition
= (*list
)->numItems
;
487 if (itemsDestination
!= NULL
)
488 memcpy (itemsDestination
, ITEMPTR (list
, firstItemPosition
- 1),
489 (*list
)->itemSize
* numItemsToRemove
);
491 firstItemAfterChunk
= firstItemPosition
+ numItemsToRemove
;
492 numToMove
= (*list
)->numItems
- (firstItemAfterChunk
- 1);
496 * move part of list down to cover hole left by removed item
498 memmove (ITEMPTR (list
, firstItemPosition
- 1),
499 ITEMPTR (list
, firstItemAfterChunk
- 1),
500 (*list
)->itemSize
* numToMove
);
503 (*list
)->numItems
-= numItemsToRemove
;
505 #endif /* CFG_ALL_LIST_FUNCTIONS || CFG_DEVICE_DEREGISTER */
507 /*******************************/
509 void ListGetItems (list_t list
, void *itemsDestination
,
510 int firstItemPosition
, int numItemsToGet
)
513 if (firstItemPosition
== LIST_START
)
514 firstItemPosition
= 1;
515 else if (firstItemPosition
== LIST_END
)
516 firstItemPosition
= (*list
)->numItems
;
518 memcpy (itemsDestination
,
519 ITEMPTR (list
, firstItemPosition
- 1),
520 (*list
)->itemSize
* numItemsToGet
);
523 /*******************************/
526 * Returns a pointer to the item at itemPosition. returns null if an
529 void *ListGetPtrToItem (list_t list
, int itemPosition
)
531 if (itemPosition
== LIST_START
)
533 else if (itemPosition
== LIST_END
)
534 itemPosition
= (*list
)->numItems
;
536 return ITEMPTR (list
, itemPosition
- 1);
539 /*******************************/
542 * returns a pointer the lists data (abstraction violation for
545 void *ListGetDataPtr (list_t list
)
547 return &((*list
)->itemList
[0]);
550 /********************************/
552 #ifdef CFG_ALL_LIST_FUNCTIONS
554 int ListApplyToEach (list_t list
, int ascending
,
555 ListApplicationFunc funcToApply
,
558 int result
= 0, index
;
560 if (!list
|| !funcToApply
)
564 for (index
= 1; index
<= ListNumItems (list
); index
++) {
565 result
= funcToApply (index
,
566 ListGetPtrToItem (list
, index
),
572 for (index
= ListNumItems (list
);
573 index
> 0 && index
<= ListNumItems (list
);
575 result
= funcToApply (index
,
576 ListGetPtrToItem (list
, index
),
587 #endif /* CFG_ALL_LIST_FUNCTIONS */
589 /********************************/
591 int ListGetItemSize (list_t list
)
593 return (*list
)->itemSize
;
596 /********************************/
598 int ListNumItems (list_t list
)
600 return (*list
)->numItems
;
603 /*******************************/
605 #ifdef CFG_ALL_LIST_FUNCTIONS
607 void ListRemoveDuplicates (list_t list
, CompareFunction compareFunction
)
609 int numItems
, index
, startIndexForFind
, duplicatesIndex
;
611 numItems
= ListNumItems (list
);
613 for (index
= 1; index
< numItems
; index
++) {
614 startIndexForFind
= index
+ 1;
615 while (startIndexForFind
<= numItems
) {
618 ListGetPtrToItem (list
, index
),
621 if (duplicatesIndex
> 0) {
622 ListRemoveItem (list
, NULL
, duplicatesIndex
);
624 startIndexForFind
= duplicatesIndex
;
632 /*******************************/
635 /*******************************/
637 int ListFindItem (list_t list
, void *ptrToItem
, int startingPosition
,
638 CompareFunction compareFunction
)
640 int numItems
, size
, index
, cmp
;
643 if ((numItems
= (*list
)->numItems
) == 0)
646 size
= (*list
)->itemSize
;
648 if (startingPosition
== LIST_START
)
649 startingPosition
= 1;
650 else if (startingPosition
== LIST_END
)
651 startingPosition
= numItems
;
653 for (index
= startingPosition
; index
<= numItems
; index
++) {
654 listItemPtr
= ITEMPTR (list
, index
- 1);
655 cmp
= compareFunction
656 ? compareFunction (ptrToItem
, listItemPtr
)
657 : ListMemBlockCmp (ptrToItem
, listItemPtr
, size
);
665 /*******************************/
667 int ShortCompare (void *a
, void *b
)
669 if (*(short *) a
< *(short *) b
)
671 if (*(short *) a
> *(short *) b
)
676 /*******************************/
678 int IntCompare (void *a
, void *b
)
680 if (*(int *) a
< *(int *) b
)
682 if (*(int *) a
> *(int *) b
)
687 /*******************************/
689 int CStringCompare (void *a
, void *b
)
691 return strcmp (*(char **) a
, *(char **) b
);
694 /*******************************/
697 int ListBinSearch (list_t list
, void *ptrToItem
,
698 CompareFunction compareFunction
)
702 index
= BinSearch (ITEMPTR (list
, 0),
703 (int) (*list
)->numItems
,
704 (int) (*list
)->itemSize
, ptrToItem
,
708 index
++; /* lists start from 1 */
710 index
= 0; /* item not found */
715 /**************************************************************************/
718 * Reserves memory for numItems in the list. If it succeeds then
719 * numItems items can be inserted without possibility of an out of
720 * memory error (useful to simplify error recovery in complex
721 * functions). Returns 1 if success, 0 if out of memory.
723 int ListPreAllocate (list_t list
, int numItems
)
725 if ((*list
)->listSize
- (*list
)->numItems
< numItems
) {
726 return ExpandListSpace (list
,
727 numItems
- ((*list
)->listSize
-
730 return 1; /* enough items are already pre-allocated */
734 #endif /* CFG_ALL_LIST_FUNCTIONS */