/*============================================================================= LINKEDLIST.C: Support for linked lists Created June 1997 by Gary Shaw =============================================================================*/ #include "types.h" #include "debug.h" #include "linkedlist.h" #include "spaceobj.h" #include "memory.h" /*============================================================================= Private Macros: =============================================================================*/ #define CompareCback(obj1,obj2) ( ((SpaceObj *)obj1)->collOptimizeDist > ((SpaceObj *)obj2)->collOptimizeDist ) #define CompareCback2(obj1,obj2) ( ((SpaceObj *)obj1)->cameraDistanceSquared < ((SpaceObj *)obj2)->cameraDistanceSquared ) /*============================================================================= Private Functions: =============================================================================*/ /*----------------------------------------------------------------------------- Name : listDetachNode Description : detaches a node from a linked list, without deleting it or modifying its node members. Inputs : node to detach Outputs : Return : ----------------------------------------------------------------------------*/ void listDetachNode(Node *node) { LinkedList *owner = node->belongto; Node *nextnode; Node *prevnode; dbgAssert(owner != NULL); dbgAssert(owner->head != NULL); dbgAssert(owner->tail != NULL); nextnode = node->next; prevnode = node->prev; if (owner->head == node) { owner->head = nextnode; } if (owner->tail == node) { owner->tail = prevnode; } if (nextnode != NULL) { nextnode->prev = prevnode; } if (prevnode != NULL) { prevnode->next = nextnode; } owner->num--; } /*============================================================================= Functions: =============================================================================*/ /*----------------------------------------------------------------------------- Name : listInit Description : initializes a linked list Inputs : list Outputs : Return : ----------------------------------------------------------------------------*/ void listInit(LinkedList *list) { list->head = NULL; list->tail = NULL; list->num = 0; } /*----------------------------------------------------------------------------- Name : listRemoveAll Description : removes all nodes from a list, without deleting the nodes Inputs : list Outputs : Return : ----------------------------------------------------------------------------*/ void listRemoveAll(LinkedList *list) { Node *curnode = list->head; Node *nextnode; while (curnode != NULL) { nextnode = curnode->next; ClearNodePtr(curnode); curnode = nextnode; } list->head = list->tail = NULL; list->num = 0; } /*----------------------------------------------------------------------------- Name : listDeleteAll Description : deletes (frees memory) of all nodes in a list, and removes these nodes from the list. Inputs : list Outputs : Return : ----------------------------------------------------------------------------*/ void listDeleteAll(LinkedList *list) { Node *curnode = list->head; Node *nextnode; while (curnode != NULL) { nextnode = curnode->next; memFree(listGetStructOfNode(curnode)); curnode = nextnode; } list->head = list->tail = NULL; list->num = 0; } /*----------------------------------------------------------------------------- Name : listAddNode Description : adds a node to the end of a list Inputs : list, node toadd, structure which contains node toadd Outputs : Return : ----------------------------------------------------------------------------*/ void listAddNode(LinkedList *list,Node *toadd,void *structure) { if (list->head == NULL) { dbgAssert(list->tail == NULL); list->head = toadd; list->tail = toadd; toadd->next = NULL; toadd->prev = NULL; toadd->belongto = list; toadd->structptr = structure; } else { Node *oldtailnode = list->tail; dbgAssert(oldtailnode != NULL); dbgAssert(oldtailnode->next == NULL); oldtailnode->next = toadd; toadd->next = NULL; toadd->prev = oldtailnode; toadd->belongto = list; toadd->structptr = structure; list->tail = toadd; } list->num++; } /*----------------------------------------------------------------------------- Name : listAddNodeBeginning Description : adds a node to the beginning of a list Inputs : list, node toadd, structure which contains node toadd Outputs : Return : ----------------------------------------------------------------------------*/ void listAddNodeBeginning(LinkedList *list,Node *toadd,void *structure) { if (list->head == NULL) { dbgAssert(list->tail == NULL); list->head = toadd; list->tail = toadd; toadd->next = NULL; toadd->prev = NULL; toadd->belongto = list; toadd->structptr = structure; } else { Node *oldheadnode = list->head; dbgAssert(oldheadnode != NULL); dbgAssert(oldheadnode->prev == NULL); oldheadnode->prev = toadd; toadd->next = oldheadnode; toadd->prev = NULL; toadd->belongto = list; toadd->structptr = structure; list->head = toadd; } list->num++; } /*----------------------------------------------------------------------------- Name : listAddNodeAfter Description : inserts a node after another node Inputs : insertion point node, toadd node, structure which contains toadd Outputs : Return : ----------------------------------------------------------------------------*/ void listAddNodeAfter(Node *node,Node *toadd,void *structure) { Node *nextnode; dbgAssert(node != NULL); nextnode = node->next; dbgAssert(node != nextnode); dbgAssert(node != toadd); dbgAssert(nextnode != toadd); node->next = toadd; toadd->prev = node; toadd->next = nextnode; toadd->belongto = node->belongto; toadd->structptr = structure; if (nextnode != NULL) { nextnode->prev = toadd; } else { node->belongto->tail = toadd; } node->belongto->num++; } /*----------------------------------------------------------------------------- Name : listAddNodeBefore Description : inserts a node before another node Inputs : insertion point node, toadd node, structure which contains toadd Outputs : Return : ----------------------------------------------------------------------------*/ void listAddNodeBefore(Node *node,Node *toadd,void *structure) { Node *prevnode; dbgAssert(node != NULL); prevnode = node->prev; if (prevnode != NULL) { prevnode->next = toadd; } else { node->belongto->head = toadd; } toadd->prev = prevnode; toadd->next = node; toadd->belongto = node->belongto; toadd->structptr = structure; node->prev = toadd; node->belongto->num++; } /*----------------------------------------------------------------------------- Name : listMoveNodeToHead Description : Moves a linked list node to the beginning of the list it's in. Inputs : nodeToMove - node to move to the start of the list. Outputs : Return : void ----------------------------------------------------------------------------*/ void listMoveNodeToHead(Node *nodeToMove) { LinkedList *list; void *structure; dbgAssert(nodeToMove != NULL); list = nodeToMove->belongto; structure = listGetStructOfNode(nodeToMove); if (list->head == nodeToMove) { //if already at head of list return; //nothing to do } listDetachNode(nodeToMove); if (list->head == NULL) { listAddNode(list, nodeToMove, structure); } else { listAddNodeBefore(list->head, nodeToMove, structure); } } /*----------------------------------------------------------------------------- Name : listRemoveNode Description : removes a node from the list it belongs to, and clears the next,prev,etc pointers of that node Inputs : node Outputs : Return : ----------------------------------------------------------------------------*/ void listRemoveNode(Node *node) { listDetachNode(node); ClearNodePtr(node); } /*----------------------------------------------------------------------------- Name : listDeleteNode Description : removes a node from the list, and frees its memory Inputs : node Outputs : Return : ----------------------------------------------------------------------------*/ void listDeleteNode(Node *node) { listDetachNode(node); memFree(listGetStructOfNode(node)); } /*----------------------------------------------------------------------------- Name : listMoveContentsOfList Description : This function moves the entrie contents of the source list to the dest list. Inputs : destination, source Outputs : none Return : void ----------------------------------------------------------------------------*/ void listMoveContentsOfList(LinkedList *dest, LinkedList *source) { Node *walk; // copy list members to the new list dest->head = source->head; dest->tail = source->tail; dest->num = source->num; // walk through the list and fix up all of the belongto pointers walk = dest->head; while (walk != NULL) { walk->belongto = dest; walk = walk->next; } listInit(source); } /*----------------------------------------------------------------------------- Name : listMergeSort Description : sorts list from highest to lowest, using the mergesort algorithm (order n*log(n)) Inputs : list to sort, compare callback function which should return true if its second argument is > its first argument. Outputs : list is sorted Return : ----------------------------------------------------------------------------*/ void listMergeSort(LinkedList *list) { LinkedList leftlist; LinkedList rightlist; Node *node1; Node *node2; udword i,half; Node *firstrightnode; Node *lastleftnode; Node *leftnodeadd; Node *rightnodeadd; Node *newleftnodeadd; Node *newrightnodeadd; if (list->num <= 1) { return; } else if (list->num == 2) { node1 = list->head; node2 = list->tail; if ( CompareCback(listGetStructOfNode(node1),listGetStructOfNode(node2)) ) { node1->prev = node2; node1->next = NULL; node2->next = node1; node2->prev = NULL; list->head = node2; list->tail = node1; } return; } else { half = list->num >> 1; firstrightnode = list->head; for (i=0;inext; } lastleftnode = firstrightnode->prev; // break the list in half lastleftnode->next = NULL; firstrightnode->prev = NULL; leftlist.head = list->head; leftlist.tail = lastleftnode; leftlist.num = half; rightlist.head = firstrightnode; rightlist.tail = list->tail; rightlist.num = list->num - half; listMergeSort(&leftlist); listMergeSort(&rightlist); // Now merge the leftlist and rightlist into the list listInit(list); leftnodeadd = leftlist.head; rightnodeadd = rightlist.head; while ((leftnodeadd != NULL) || (rightnodeadd != NULL)) { if (leftnodeadd == NULL) { goto addrightnode; } if (rightnodeadd == NULL) { goto addleftnode; } if (CompareCback(listGetStructOfNode(leftnodeadd),listGetStructOfNode(rightnodeadd))) { addrightnode: newrightnodeadd = rightnodeadd->next; listAddNode(list,rightnodeadd,listGetStructOfNode(rightnodeadd)); rightnodeadd = newrightnodeadd; } else { addleftnode: newleftnodeadd = leftnodeadd->next; listAddNode(list,leftnodeadd,listGetStructOfNode(leftnodeadd)); leftnodeadd = newleftnodeadd; } } } } void listMergeSort2(LinkedList *list) { LinkedList leftlist; LinkedList rightlist; Node *node1; Node *node2; udword i,half; Node *firstrightnode; Node *lastleftnode; Node *leftnodeadd; Node *rightnodeadd; Node *newleftnodeadd; Node *newrightnodeadd; if (list->num <= 1) { return; } else if (list->num == 2) { node1 = list->head; node2 = list->tail; if ( CompareCback2(listGetStructOfNode(node1),listGetStructOfNode(node2)) ) { node1->prev = node2; node1->next = NULL; node2->next = node1; node2->prev = NULL; list->head = node2; list->tail = node1; } return; } else { half = list->num >> 1; firstrightnode = list->head; for (i=0;inext; } lastleftnode = firstrightnode->prev; // break the list in half lastleftnode->next = NULL; firstrightnode->prev = NULL; leftlist.head = list->head; leftlist.tail = lastleftnode; leftlist.num = half; rightlist.head = firstrightnode; rightlist.tail = list->tail; rightlist.num = list->num - half; listMergeSort2(&leftlist); listMergeSort2(&rightlist); // Now merge the leftlist and rightlist into the list listInit(list); leftnodeadd = leftlist.head; rightnodeadd = rightlist.head; while ((leftnodeadd != NULL) || (rightnodeadd != NULL)) { if (leftnodeadd == NULL) { goto addrightnode; } if (rightnodeadd == NULL) { goto addleftnode; } if (CompareCback2(listGetStructOfNode(leftnodeadd),listGetStructOfNode(rightnodeadd))) { addrightnode: newrightnodeadd = rightnodeadd->next; listAddNode(list,rightnodeadd,listGetStructOfNode(rightnodeadd)); rightnodeadd = newrightnodeadd; } else { addleftnode: newleftnodeadd = leftnodeadd->next; listAddNode(list,leftnodeadd,listGetStructOfNode(leftnodeadd)); leftnodeadd = newleftnodeadd; } } } } void listMergeSortGeneral(LinkedList *list, MergeSortCompareCb compare) { LinkedList leftlist; LinkedList rightlist; Node *node1; Node *node2; udword i,half; Node *firstrightnode; Node *lastleftnode; Node *leftnodeadd; Node *rightnodeadd; Node *newleftnodeadd; Node *newrightnodeadd; if (list->num <= 1) { return; } else if (list->num == 2) { node1 = list->head; node2 = list->tail; if ( compare(listGetStructOfNode(node1),listGetStructOfNode(node2)) ) { node1->prev = node2; node1->next = NULL; node2->next = node1; node2->prev = NULL; list->head = node2; list->tail = node1; } return; } else { half = list->num >> 1; firstrightnode = list->head; for (i=0;inext; } lastleftnode = firstrightnode->prev; // break the list in half lastleftnode->next = NULL; firstrightnode->prev = NULL; leftlist.head = list->head; leftlist.tail = lastleftnode; leftlist.num = half; rightlist.head = firstrightnode; rightlist.tail = list->tail; rightlist.num = list->num - half; listMergeSortGeneral(&leftlist, compare); listMergeSortGeneral(&rightlist, compare); // Now merge the leftlist and rightlist into the list listInit(list); leftnodeadd = leftlist.head; rightnodeadd = rightlist.head; while ((leftnodeadd != NULL) || (rightnodeadd != NULL)) { if (leftnodeadd == NULL) { goto addrightnode; } if (rightnodeadd == NULL) { goto addleftnode; } if (compare(listGetStructOfNode(leftnodeadd),listGetStructOfNode(rightnodeadd))) { addrightnode: newrightnodeadd = rightnodeadd->next; listAddNode(list,rightnodeadd,listGetStructOfNode(rightnodeadd)); rightnodeadd = newrightnodeadd; } else { addleftnode: newleftnodeadd = leftnodeadd->next; listAddNode(list,leftnodeadd,listGetStructOfNode(leftnodeadd)); leftnodeadd = newleftnodeadd; } } } } /*----------------------------------------------------------------------------- Name : listInsertSort Description : does a modified insert sort (finds out of place objects, sorts them, and then merges them into a final sorted list). Inputs : list to sort Outputs : Return : ----------------------------------------------------------------------------*/ void listInsertSort(LinkedList *list) { Node *prevprev = NULL; Node *prev = NULL; Node *cur = NULL; void *structprevprev; void *structprev; void *structcur; LinkedList outOfOrderList; Node *curNode; Node *outOfOrderNode; Node *outOfOrderNodeNext; void *structoutOfOrderNode; Node *node1; Node *node2; Node *curnext; if (list->num <= 1) { return; } else if (list->num == 2) { node1 = list->head; node2 = list->tail; if ( CompareCback(listGetStructOfNode(node1),listGetStructOfNode(node2)) ) { node1->prev = node2; node1->next = NULL; node2->next = node1; node2->prev = NULL; list->head = node2; list->tail = node1; } return; } else { listInit(&outOfOrderList); prevprev = list->head; prev = prevprev->next; cur = prev->next; structprevprev = listGetStructOfNode(prevprev); structprev = listGetStructOfNode(prev); // find out of order items in list, and put in outOfOrderList do { structcur = listGetStructOfNode(cur); if (CompareCback(structprev,structprevprev)) // prev > prevprev { if (CompareCback(structcur,structprev)) // cur > prev { // everything in order, so continue prevprev = prev; structprevprev = structprev; prev = cur; structprev = structcur; cur = cur->next; } else { if (CompareCback(structcur,structprevprev)) // cur > prevprev { // prev must be out of order, so remove it and put in outOfOrderList listRemoveNode(prev); listAddNode(&outOfOrderList,prev,structprev); prev = cur; structprev = structcur; cur = cur->next; } else { // cur must be out of order, so remove it and put in outOfOrderList curnext = cur->next; listRemoveNode(cur); listAddNode(&outOfOrderList,cur,structcur); cur = curnext; } } } else { if (CompareCback(structcur,structprev)) // cur > prev { // just prevprev is out of order listRemoveNode(prevprev); listAddNode(&outOfOrderList,prevprev,structprevprev); prevprev = prev; structprevprev = structprev; prev = cur; structprev = structcur; cur = cur->next; } else { // both prevprev and prev are out of order listRemoveNode(prev); listAddNode(&outOfOrderList,prev,structprev); listRemoveNode(prevprev); listAddNode(&outOfOrderList,prevprev,structprevprev); prevprev = cur; structprevprev = structcur; prev = prevprev->next; if (prev != NULL) { structprev = listGetStructOfNode(prev); cur = prev->next; } else { break; } } } } while (cur != NULL); // list is now in order, with out of order items in outOfOrderList // sort outOfOrderList: listMergeSort(&outOfOrderList); // now merge outOfOrderList into list (outOfOrderList is now in order) outOfOrderNode = outOfOrderList.head; curNode = list->head; while (outOfOrderNode != NULL) { // put outOfOrderNode into list structoutOfOrderNode = listGetStructOfNode(outOfOrderNode); outOfOrderNodeNext = outOfOrderNode->next; for (;;) { if (curNode == NULL) { listAddNode(list,outOfOrderNode,structoutOfOrderNode); break; } if (CompareCback(listGetStructOfNode(curNode),structoutOfOrderNode)) { listAddNodeBefore(curNode,outOfOrderNode,structoutOfOrderNode); break; } curNode = curNode->next; } outOfOrderNode = outOfOrderNodeNext; } // list is now sorted // don't bother doing a listRemoveAll on outOfOrderList because we are exiting return; } } #ifndef HW_Release void listCheckSort(LinkedList *list) { Node *node1; Node *node2; if (list->num <= 1) { return; } else if (list->num == 2) { node1 = list->head; node2 = list->tail; if ( CompareCback(listGetStructOfNode(node1),listGetStructOfNode(node2)) ) { dbgAssert(FALSE); } } else { node1 = list->head; node2 = node1->next; while (node2 != NULL) { if ( CompareCback(listGetStructOfNode(node1),listGetStructOfNode(node2)) ) { dbgAssert(FALSE); } node1 = node2; node2 = node2->next; } } } void listCheckSortGeneral(LinkedList *list, MergeSortCompareCb compare) { Node *node1; Node *node2; if (list->num <= 1) { return; } else if (list->num == 2) { node1 = list->head; node2 = list->tail; if ( compare(listGetStructOfNode(node1),listGetStructOfNode(node2)) ) { dbgAssert(FALSE); } } else { node1 = list->head; node2 = node1->next; while (node2 != NULL) { if ( compare(listGetStructOfNode(node1),listGetStructOfNode(node2)) ) { dbgAssert(FALSE); } node1 = node2; node2 = node2->next; } } } #endif /*----------------------------------------------------------------------------- Name : listVerifyAnal Description : Verify that a linked list is valid. Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ #if LL_ERROR_CHECKING void listVerifyAnal(LinkedList *list) { sdword count, diff, firstDiff; Node *node; for (count = 0, node = list->head; node != NULL; node = node->next, count++) { //verify prev/next pointers dbgAssert(node->prev != node); dbgAssert(node->next != node); if (node->prev != NULL || node->next != NULL) { dbgAssert(node->prev != node->next); } if (count > 0) { dbgAssert(node->prev->next == node); } if (count < list->num - 1) { dbgAssert(node->next->prev == node); } //check the belongto pointer dbgAssert(node->belongto == list); //check the structptrs if (count == 0) { firstDiff = (ubyte *)node - (ubyte *)node->structptr; dbgAssert(firstDiff >= 0); } else { diff = (ubyte *)node - (ubyte *)node->structptr; dbgAssert(diff >= 0); dbgAssert(diff == firstDiff); } //check if the head/tail pointers are valid if (count == 0) { dbgAssert(node == list->head); } if (count == list->num - 1) { dbgAssert(node == list->tail); } } dbgAssert(count == list->num); } #endif