| #include <common.h> | |
| #include <malloc.h> | |
| #include <lists.h> | |
| #define MAX(a,b) (((a)>(b)) ? (a) : (b)) | |
| #define MIN(a,b) (((a)<(b)) ? (a) : (b)) | |
| #define CAT4CHARS(a,b,c,d) ((a<<24) | (b<<16) | (c<<8) | d) | |
| /* increase list size by 10% every time it is full */ | |
| #define kDefaultAllocationPercentIncrease 10 | |
| /* always increase list size by 4 items when it is full */ | |
| #define kDefaultAllocationminNumItemsIncrease 4 | |
| /* | |
| * how many items to expand the list by when it becomes full | |
| * = current listSize (in items) + (hiword percent of list size) + loword | |
| */ | |
| #define NUMITEMSPERALLOC(list) MAX(((*list)->listSize * \ | |
| ((*list)->percentIncrease + 100)) / 100, \ | |
| (*list)->minNumItemsIncrease ) | |
| #define ITEMPTR(list,item) &(((char *)&(*list)->itemList)[(*(list))->itemSize * (item)]) | |
| #define LIST_SIGNATURE CAT4CHARS('L', 'I', 'S', 'T'); | |
| #define calloc(size,num) malloc(size*num) | |
| /********************************************************************/ | |
| Handle NewHandle (unsigned int numBytes) | |
| { | |
| void *memPtr; | |
| HandleRecord *hanPtr; | |
| memPtr = calloc (numBytes, 1); | |
| hanPtr = (HandleRecord *) calloc (sizeof (HandleRecord), 1); | |
| if (hanPtr && (memPtr || numBytes == 0)) { | |
| hanPtr->ptr = memPtr; | |
| hanPtr->size = numBytes; | |
| return (Handle) hanPtr; | |
| } else { | |
| free (memPtr); | |
| free (hanPtr); | |
| return NULL; | |
| } | |
| } | |
| /********************************************************************/ | |
| void DisposeHandle (Handle handle) | |
| { | |
| if (handle) { | |
| free (*handle); | |
| free ((void *) handle); | |
| } | |
| } | |
| /********************************************************************/ | |
| unsigned int GetHandleSize (Handle handle) | |
| { | |
| return ((HandleRecord *) handle)->size; | |
| } | |
| /********************************************************************/ | |
| int SetHandleSize (Handle handle, unsigned int newSize) | |
| { | |
| HandleRecord *hanRecPtr = (HandleRecord *) handle; | |
| void *newPtr, *oldPtr; | |
| unsigned int oldSize; | |
| oldPtr = hanRecPtr->ptr; | |
| oldSize = hanRecPtr->size; | |
| if (oldSize == newSize) | |
| return 1; | |
| if (oldPtr == NULL) { | |
| newPtr = malloc (newSize); | |
| } else { | |
| newPtr = realloc (oldPtr, newSize); | |
| } | |
| if (newPtr || (newSize == 0)) { | |
| hanRecPtr->ptr = newPtr; | |
| hanRecPtr->size = newSize; | |
| if (newSize > oldSize) | |
| memset ((char *) newPtr + oldSize, 0, newSize - oldSize); | |
| return 1; | |
| } else | |
| return 0; | |
| } | |
| #ifdef CFG_ALL_LIST_FUNCTIONS | |
| /* Used to compare list elements by their raw data contents */ | |
| static int ListMemBlockCmp (void *a, void *b, int size) | |
| { | |
| return memcmp (a, b, size); | |
| } | |
| /***************************************************************************/ | |
| /* | |
| * Binary search numElements of size elementSize in array for a match | |
| * to the. item. Return the index of the element that matches | |
| * (0 - numElements - 1). If no match is found return the -i-1 where | |
| * i is the index (0 - numElements) where the item should be placed. | |
| * (*theCmp)(a,b) should return <0 if a<b, 0 if a==b, >0 if a>b. | |
| * | |
| * This function is like the C-Library function bsearch() except that | |
| * this function returns the index where the item should be placed if | |
| * it is not found. | |
| */ | |
| int BinSearch ( void *array, int numElements, int elementSize, | |
| void *itemPtr, CompareFunction compareFunction) | |
| { | |
| int low, high, mid, cmp; | |
| void *arrayItemPtr; | |
| for (low = 0, high = numElements - 1, mid = 0, cmp = -1; low <= high;) { | |
| mid = (low + high) >> 1; | |
| arrayItemPtr = (void *) (((char *) array) + (mid * elementSize)); | |
| cmp = compareFunction | |
| ? compareFunction (itemPtr, arrayItemPtr) | |
| : ListMemBlockCmp (itemPtr, arrayItemPtr, elementSize); | |
| if (cmp == 0) { | |
| return mid; | |
| } else if (cmp < 0) { | |
| high = mid - 1; | |
| } else { | |
| low = mid + 1; | |
| } | |
| } | |
| if (cmp > 0) | |
| mid++; | |
| return -mid - 1; | |
| } | |
| #endif /* CFG_ALL_LIST_FUNCTIONS */ | |
| /*******************************************************************************/ | |
| /* | |
| * If numNewItems == 0 then expand the list by the number of items | |
| * indicated by its allocation policy. | |
| * If numNewItems > 0 then expand the list by exactly the number of | |
| * items indicated. | |
| * If numNewItems < 0 then expand the list by the absolute value of | |
| * numNewItems plus the number of items indicated by its allocation | |
| * policy. | |
| * Returns 1 for success, 0 if out of memory | |
| */ | |
| static int ExpandListSpace (list_t list, int numNewItems) | |
| { | |
| if (numNewItems == 0) { | |
| numNewItems = NUMITEMSPERALLOC (list); | |
| } else if (numNewItems < 0) { | |
| numNewItems = (-numNewItems) + NUMITEMSPERALLOC (list); | |
| } | |
| if (SetHandleSize ((Handle) list, | |
| sizeof (ListStruct) + | |
| ((*list)->listSize + | |
| numNewItems) * (*list)->itemSize)) { | |
| (*list)->listSize += numNewItems; | |
| return 1; | |
| } else { | |
| return 0; | |
| } | |
| } | |
| /*******************************/ | |
| #ifdef CFG_ALL_LIST_FUNCTIONS | |
| /* | |
| * This function reallocate the list, minus any currently unused | |
| * portion of its allotted memory. | |
| */ | |
| void ListCompact (list_t list) | |
| { | |
| if (!SetHandleSize ((Handle) list, | |
| sizeof (ListStruct) + | |
| (*list)->numItems * (*list)->itemSize)) { | |
| return; | |
| } | |
| (*list)->listSize = (*list)->numItems; | |
| } | |
| #endif /* CFG_ALL_LIST_FUNCTIONS */ | |
| /*******************************/ | |
| list_t ListCreate (int elementSize) | |
| { | |
| list_t list; | |
| list = (list_t) (NewHandle (sizeof (ListStruct))); /* create empty list */ | |
| if (list) { | |
| (*list)->signature = LIST_SIGNATURE; | |
| (*list)->numItems = 0; | |
| (*list)->listSize = 0; | |
| (*list)->itemSize = elementSize; | |
| (*list)->percentIncrease = kDefaultAllocationPercentIncrease; | |
| (*list)->minNumItemsIncrease = | |
| kDefaultAllocationminNumItemsIncrease; | |
| } | |
| return list; | |
| } | |
| /*******************************/ | |
| void ListSetAllocationPolicy (list_t list, int minItemsPerAlloc, | |
| int percentIncreasePerAlloc) | |
| { | |
| (*list)->percentIncrease = percentIncreasePerAlloc; | |
| (*list)->minNumItemsIncrease = minItemsPerAlloc; | |
| } | |
| /*******************************/ | |
| void ListDispose (list_t list) | |
| { | |
| DisposeHandle ((Handle) list); | |
| } | |
| /*******************************/ | |
| #ifdef CFG_ALL_LIST_FUNCTIONS | |
| void ListDisposePtrList (list_t list) | |
| { | |
| int index; | |
| int numItems; | |
| if (list) { | |
| numItems = ListNumItems (list); | |
| for (index = 1; index <= numItems; index++) | |
| free (*(void **) ListGetPtrToItem (list, index)); | |
| ListDispose (list); | |
| } | |
| } | |
| /*******************************/ | |
| /* | |
| * keeps memory, resets the number of items to 0 | |
| */ | |
| void ListClear (list_t list) | |
| { | |
| if (!list) | |
| return; | |
| (*list)->numItems = 0; | |
| } | |
| /*******************************/ | |
| /* | |
| * copy is only as large as necessary | |
| */ | |
| list_t ListCopy (list_t originalList) | |
| { | |
| list_t tempList = NULL; | |
| int numItems; | |
| if (!originalList) | |
| return NULL; | |
| tempList = ListCreate ((*originalList)->itemSize); | |
| if (tempList) { | |
| numItems = ListNumItems (originalList); | |
| if (!SetHandleSize ((Handle) tempList, | |
| sizeof (ListStruct) + | |
| numItems * (*tempList)->itemSize)) { | |
| ListDispose (tempList); | |
| return NULL; | |
| } | |
| (*tempList)->numItems = (*originalList)->numItems; | |
| (*tempList)->listSize = (*originalList)->numItems; | |
| (*tempList)->itemSize = (*originalList)->itemSize; | |
| (*tempList)->percentIncrease = (*originalList)->percentIncrease; | |
| (*tempList)->minNumItemsIncrease = | |
| (*originalList)->minNumItemsIncrease; | |
| memcpy (ITEMPTR (tempList, 0), ITEMPTR (originalList, 0), | |
| numItems * (*tempList)->itemSize); | |
| } | |
| return tempList; | |
| } | |
| /********************************/ | |
| /* | |
| * list1 = list1 + list2 | |
| */ | |
| int ListAppend (list_t list1, list_t list2) | |
| { | |
| int numItemsL1, numItemsL2; | |
| if (!list2) | |
| return 1; | |
| if (!list1) | |
| return 0; | |
| if ((*list1)->itemSize != (*list2)->itemSize) | |
| return 0; | |
| numItemsL1 = ListNumItems (list1); | |
| numItemsL2 = ListNumItems (list2); | |
| if (numItemsL2 == 0) | |
| return 1; | |
| if (!SetHandleSize ((Handle) list1, | |
| sizeof (ListStruct) + (numItemsL1 + numItemsL2) * | |
| (*list1)->itemSize)) { | |
| return 0; | |
| } | |
| (*list1)->numItems = numItemsL1 + numItemsL2; | |
| (*list1)->listSize = numItemsL1 + numItemsL2; | |
| memmove (ITEMPTR (list1, numItemsL1), | |
| ITEMPTR (list2, 0), | |
| numItemsL2 * (*list2)->itemSize); | |
| return 1; | |
| } | |
| #endif /* CFG_ALL_LIST_FUNCTIONS */ | |
| /*******************************/ | |
| /* | |
| * returns 1 if the item is inserted, returns 0 if out of memory or | |
| * bad arguments were passed. | |
| */ | |
| int ListInsertItem (list_t list, void *ptrToItem, int itemPosition) | |
| { | |
| return ListInsertItems (list, ptrToItem, itemPosition, 1); | |
| } | |
| /*******************************/ | |
| int ListInsertItems (list_t list, void *ptrToItems, int firstItemPosition, | |
| int numItemsToInsert) | |
| { | |
| int numItems = (*list)->numItems; | |
| if (firstItemPosition == numItems + 1) | |
| firstItemPosition = LIST_END; | |
| else if (firstItemPosition > numItems) | |
| return 0; | |
| if ((*list)->numItems >= (*list)->listSize) { | |
| if (!ExpandListSpace (list, -numItemsToInsert)) | |
| return 0; | |
| } | |
| if (firstItemPosition == LIST_START) { | |
| if (numItems == 0) { | |
| /* special case for empty list */ | |
| firstItemPosition = LIST_END; | |
| } else { | |
| firstItemPosition = 1; | |
| } | |
| } | |
| if (firstItemPosition == LIST_END) { /* add at the end of the list */ | |
| if (ptrToItems) | |
| memcpy (ITEMPTR (list, numItems), ptrToItems, | |
| (*list)->itemSize * numItemsToInsert); | |
| else | |
| memset (ITEMPTR (list, numItems), 0, | |
| (*list)->itemSize * numItemsToInsert); | |
| (*list)->numItems += numItemsToInsert; | |
| } else { /* move part of list up to make room for new item */ | |
| memmove (ITEMPTR (list, firstItemPosition - 1 + numItemsToInsert), | |
| ITEMPTR (list, firstItemPosition - 1), | |
| (numItems + 1 - firstItemPosition) * (*list)->itemSize); | |
| if (ptrToItems) | |
| memmove (ITEMPTR (list, firstItemPosition - 1), ptrToItems, | |
| (*list)->itemSize * numItemsToInsert); | |
| else | |
| memset (ITEMPTR (list, firstItemPosition - 1), 0, | |
| (*list)->itemSize * numItemsToInsert); | |
| (*list)->numItems += numItemsToInsert; | |
| } | |
| return 1; | |
| } | |
| #ifdef CFG_ALL_LIST_FUNCTIONS | |
| /*******************************/ | |
| int ListEqual (list_t list1, list_t list2) | |
| { | |
| if (list1 == list2) | |
| return 1; | |
| if (list1 == NULL || list2 == NULL) | |
| return 0; | |
| if ((*list1)->itemSize == (*list1)->itemSize) { | |
| if ((*list1)->numItems == (*list2)->numItems) { | |
| return (memcmp (ITEMPTR (list1, 0), ITEMPTR (list2, 0), | |
| (*list1)->itemSize * (*list1)->numItems) == 0); | |
| } | |
| } | |
| return 0; | |
| } | |
| /*******************************/ | |
| /* | |
| * The item pointed to by ptrToItem is copied over the current item | |
| * at itemPosition | |
| */ | |
| void ListReplaceItem (list_t list, void *ptrToItem, int itemPosition) | |
| { | |
| ListReplaceItems (list, ptrToItem, itemPosition, 1); | |
| } | |
| /*******************************/ | |
| /* | |
| * The item pointed to by ptrToItems is copied over the current item | |
| * at itemPosition | |
| */ | |
| void ListReplaceItems ( list_t list, void *ptrToItems, | |
| int firstItemPosition, int numItemsToReplace) | |
| { | |
| if (firstItemPosition == LIST_END) | |
| firstItemPosition = (*list)->numItems; | |
| else if (firstItemPosition == LIST_START) | |
| firstItemPosition = 1; | |
| memmove (ITEMPTR (list, firstItemPosition - 1), ptrToItems, | |
| (*list)->itemSize * numItemsToReplace); | |
| } | |
| /*******************************/ | |
| void ListGetItem (list_t list, void *itemDestination, int itemPosition) | |
| { | |
| ListGetItems (list, itemDestination, itemPosition, 1); | |
| } | |
| #endif /* CFG_ALL_LIST_FUNCTIONS */ | |
| /*******************************/ | |
| #if defined(CFG_ALL_LIST_FUNCTIONS) || defined(CFG_DEVICE_DEREGISTER) | |
| void ListRemoveItem (list_t list, void *itemDestination, int itemPosition) | |
| { | |
| ListRemoveItems (list, itemDestination, itemPosition, 1); | |
| } | |
| /*******************************/ | |
| void ListRemoveItems (list_t list, void *itemsDestination, | |
| int firstItemPosition, int numItemsToRemove) | |
| { | |
| int firstItemAfterChunk, numToMove; | |
| if (firstItemPosition == LIST_START) | |
| firstItemPosition = 1; | |
| else if (firstItemPosition == LIST_END) | |
| firstItemPosition = (*list)->numItems; | |
| if (itemsDestination != NULL) | |
| memcpy (itemsDestination, ITEMPTR (list, firstItemPosition - 1), | |
| (*list)->itemSize * numItemsToRemove); | |
| firstItemAfterChunk = firstItemPosition + numItemsToRemove; | |
| numToMove = (*list)->numItems - (firstItemAfterChunk - 1); | |
| if (numToMove > 0) { | |
| /* | |
| * move part of list down to cover hole left by removed item | |
| */ | |
| memmove (ITEMPTR (list, firstItemPosition - 1), | |
| ITEMPTR (list, firstItemAfterChunk - 1), | |
| (*list)->itemSize * numToMove); | |
| } | |
| (*list)->numItems -= numItemsToRemove; | |
| } | |
| #endif /* CFG_ALL_LIST_FUNCTIONS || CFG_DEVICE_DEREGISTER */ | |
| /*******************************/ | |
| void ListGetItems (list_t list, void *itemsDestination, | |
| int firstItemPosition, int numItemsToGet) | |
| { | |
| if (firstItemPosition == LIST_START) | |
| firstItemPosition = 1; | |
| else if (firstItemPosition == LIST_END) | |
| firstItemPosition = (*list)->numItems; | |
| memcpy (itemsDestination, | |
| ITEMPTR (list, firstItemPosition - 1), | |
| (*list)->itemSize * numItemsToGet); | |
| } | |
| /*******************************/ | |
| /* | |
| * Returns a pointer to the item at itemPosition. returns null if an | |
| * errors occurred. | |
| */ | |
| void *ListGetPtrToItem (list_t list, int itemPosition) | |
| { | |
| if (itemPosition == LIST_START) | |
| itemPosition = 1; | |
| else if (itemPosition == LIST_END) | |
| itemPosition = (*list)->numItems; | |
| return ITEMPTR (list, itemPosition - 1); | |
| } | |
| /*******************************/ | |
| /* | |
| * returns a pointer the lists data (abstraction violation for | |
| * optimization) | |
| */ | |
| void *ListGetDataPtr (list_t list) | |
| { | |
| return &((*list)->itemList[0]); | |
| } | |
| /********************************/ | |
| #ifdef CFG_ALL_LIST_FUNCTIONS | |
| int ListApplyToEach (list_t list, int ascending, | |
| ListApplicationFunc funcToApply, | |
| void *callbackData) | |
| { | |
| int result = 0, index; | |
| if (!list || !funcToApply) | |
| goto Error; | |
| if (ascending) { | |
| for (index = 1; index <= ListNumItems (list); index++) { | |
| result = funcToApply (index, | |
| ListGetPtrToItem (list, index), | |
| callbackData); | |
| if (result < 0) | |
| goto Error; | |
| } | |
| } else { | |
| for (index = ListNumItems (list); | |
| index > 0 && index <= ListNumItems (list); | |
| index--) { | |
| result = funcToApply (index, | |
| ListGetPtrToItem (list, index), | |
| callbackData); | |
| if (result < 0) | |
| goto Error; | |
| } | |
| } | |
| Error: | |
| return result; | |
| } | |
| #endif /* CFG_ALL_LIST_FUNCTIONS */ | |
| /********************************/ | |
| int ListGetItemSize (list_t list) | |
| { | |
| return (*list)->itemSize; | |
| } | |
| /********************************/ | |
| int ListNumItems (list_t list) | |
| { | |
| return (*list)->numItems; | |
| } | |
| /*******************************/ | |
| #ifdef CFG_ALL_LIST_FUNCTIONS | |
| void ListRemoveDuplicates (list_t list, CompareFunction compareFunction) | |
| { | |
| int numItems, index, startIndexForFind, duplicatesIndex; | |
| numItems = ListNumItems (list); | |
| for (index = 1; index < numItems; index++) { | |
| startIndexForFind = index + 1; | |
| while (startIndexForFind <= numItems) { | |
| duplicatesIndex = | |
| ListFindItem (list, | |
| ListGetPtrToItem (list, index), | |
| startIndexForFind, | |
| compareFunction); | |
| if (duplicatesIndex > 0) { | |
| ListRemoveItem (list, NULL, duplicatesIndex); | |
| numItems--; | |
| startIndexForFind = duplicatesIndex; | |
| } else { | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| /*******************************/ | |
| /*******************************/ | |
| int ListFindItem (list_t list, void *ptrToItem, int startingPosition, | |
| CompareFunction compareFunction) | |
| { | |
| int numItems, size, index, cmp; | |
| void *listItemPtr; | |
| if ((numItems = (*list)->numItems) == 0) | |
| return 0; | |
| size = (*list)->itemSize; | |
| if (startingPosition == LIST_START) | |
| startingPosition = 1; | |
| else if (startingPosition == LIST_END) | |
| startingPosition = numItems; | |
| for (index = startingPosition; index <= numItems; index++) { | |
| listItemPtr = ITEMPTR (list, index - 1); | |
| cmp = compareFunction | |
| ? compareFunction (ptrToItem, listItemPtr) | |
| : ListMemBlockCmp (ptrToItem, listItemPtr, size); | |
| if (cmp == 0) | |
| return index; | |
| } | |
| return 0; | |
| } | |
| /*******************************/ | |
| int ShortCompare (void *a, void *b) | |
| { | |
| if (*(short *) a < *(short *) b) | |
| return -1; | |
| if (*(short *) a > *(short *) b) | |
| return 1; | |
| return 0; | |
| } | |
| /*******************************/ | |
| int IntCompare (void *a, void *b) | |
| { | |
| if (*(int *) a < *(int *) b) | |
| return -1; | |
| if (*(int *) a > *(int *) b) | |
| return 1; | |
| return 0; | |
| } | |
| /*******************************/ | |
| int CStringCompare (void *a, void *b) | |
| { | |
| return strcmp (*(char **) a, *(char **) b); | |
| } | |
| /*******************************/ | |
| int ListBinSearch (list_t list, void *ptrToItem, | |
| CompareFunction compareFunction) | |
| { | |
| int index; | |
| index = BinSearch (ITEMPTR (list, 0), | |
| (int) (*list)->numItems, | |
| (int) (*list)->itemSize, ptrToItem, | |
| compareFunction); | |
| if (index >= 0) | |
| index++; /* lists start from 1 */ | |
| else | |
| index = 0; /* item not found */ | |
| return index; | |
| } | |
| /**************************************************************************/ | |
| /* | |
| * Reserves memory for numItems in the list. If it succeeds then | |
| * numItems items can be inserted without possibility of an out of | |
| * memory error (useful to simplify error recovery in complex | |
| * functions). Returns 1 if success, 0 if out of memory. | |
| */ | |
| int ListPreAllocate (list_t list, int numItems) | |
| { | |
| if ((*list)->listSize - (*list)->numItems < numItems) { | |
| return ExpandListSpace (list, | |
| numItems - ((*list)->listSize - | |
| (*list)->numItems)); | |
| } else { | |
| return 1; /* enough items are already pre-allocated */ | |
| } | |
| } | |
| #endif /* CFG_ALL_LIST_FUNCTIONS */ |