/* This file is part of Warzone 2100. Copyright (C) 1999-2004 Eidos Interactive Copyright (C) 2005-2007 Warzone Resurrection Project Warzone 2100 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Warzone 2100 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Warzone 2100; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /***************************************************************************/ #include #include #include "lib/framework/frame.h" #include "ptrlist.h" /***************************************************************************/ extern void *g_ElementToBeRemoved; /***************************************************************************/ static void ptrList_Init( PTRLIST *ptrList ); /***************************************************************************/ BOOL ptrList_Create( PTRLIST **ppsList, UDWORD udwInitElements, UDWORD udwExtElements, UDWORD udwElementSize ) { /* create ptr list struct */ (*ppsList) = (PTRLIST*)MALLOC( sizeof(PTRLIST) ); /* allocate heaps */ if ( !HEAP_CREATE( &(*ppsList)->psNodeHeap, sizeof(LISTNODE), udwInitElements, udwExtElements) ) { return FALSE; } if ( !HEAP_CREATE( &(*ppsList)->psElementHeap, udwElementSize, udwInitElements, udwExtElements) ) { return FALSE; } /* init members */ (*ppsList)->udwElements = udwInitElements; (*ppsList)->udwExtElements = udwExtElements; (*ppsList)->udwElementSize = udwElementSize; ptrList_Init( *ppsList ); return TRUE; } /***************************************************************************/ void ptrList_Destroy( PTRLIST *ptrList ) { ASSERT( PTRVALID(ptrList, sizeof(PTRLIST)), "ptrList_Destroy: list pointer invalid\n" ); ptrList_Clear( ptrList ); /* destroy heaps */ HEAP_DESTROY( ptrList->psNodeHeap ); HEAP_DESTROY( ptrList->psElementHeap ); /* free struct */ FREE( ptrList ); } /***************************************************************************/ static void ptrList_Init( PTRLIST *ptrList ) { ptrList->sdwCurIndex = 0; ptrList->psCurNode = NULL; ptrList->psNode = NULL; ptrList->bDontGetNext = FALSE; } /***************************************************************************/ /* * ptrList_Clear * * Returns all nodes from hash table to free node list */ /***************************************************************************/ void ptrList_Clear( PTRLIST *ptrList ) { LISTNODE *psNode, *psNodeTmp; ASSERT( PTRVALID(ptrList, sizeof(PTRLIST)), "ptrList_Destroy: table pointer invalid\n" ); /* free nodes */ psNode = ptrList->psNode; while ( psNode != NULL ) { /* return node element to heap */ ASSERT( PTRVALID(psNode->psElement, ptrList->udwElementSize), "ptrList_Destroy: element pointer invalid\n" ); HEAP_FREE( ptrList->psElementHeap, psNode->psElement ); /* return node to heap */ ASSERT( PTRVALID(psNode, sizeof(LISTNODE)), "ptrList_Destroy: node pointer invalid\n" ); psNodeTmp = psNode->psNext; HEAP_FREE( ptrList->psNodeHeap, psNode ); psNode = psNodeTmp; } ptrList_Init( ptrList ); } /***************************************************************************/ /* * ptrList_GetElement * * Gets free node from heap and returns element pointer */ /***************************************************************************/ void * ptrList_GetElement( PTRLIST *ptrList ) { void *psElement; ASSERT( PTRVALID(ptrList, sizeof(PTRLIST)), "ptrList_GetElement: table pointer invalid\n" ); HEAP_ALLOC( ptrList->psElementHeap, &psElement ); return psElement; } /***************************************************************************/ /* * ptrList_FreeElement * * Free element that was allocated using ptrList_GetElement without * inserting in list: will fail if element not allocated from ptrList */ /***************************************************************************/ void ptrList_FreeElement( PTRLIST *ptrList, void *psElement ) { ASSERT( PTRVALID(ptrList, sizeof(PTRLIST)), "ptrList_FreeElement: table pointer invalid\n" ); if ( HEAP_FREE( ptrList->psElementHeap, psElement ) == FALSE ) { debug( LOG_NEVER, "ptrList_FreeElement: couldn't free element\n" ); } } /***************************************************************************/ void ptrList_InsertElement( PTRLIST *ptrList, void *psElement, SDWORD sdwKey ) { LISTNODE *psNode, *psCurNode, *psPrevNode; ASSERT( PTRVALID(ptrList, sizeof(PTRLIST)), "ptrList_InsertElement: table pointer invalid\n" ); ASSERT( PTRVALID(psElement, ptrList->udwElementSize), "ptrList_InsertElement: element pointer invalid\n" ); /* get node from heap */ HEAP_ALLOC( ptrList->psNodeHeap, (void**) &psNode ); /* set node elements */ psNode->sdwKey = sdwKey; psNode->psElement = psElement; psNode->psNext = NULL; psPrevNode = NULL; psCurNode = ptrList->psNode; /* find correct position to insert node */ while ( psCurNode != NULL ) { if ( psCurNode->sdwKey < sdwKey ) { break; } psPrevNode = psCurNode; psCurNode = psCurNode->psNext; } /* insert node */ if ( psPrevNode == NULL ) { ptrList->psNode = psNode; if ( psCurNode != NULL ) { psNode->psNext = psCurNode; } } else { psPrevNode->psNext = psNode; psNode->psNext = psCurNode; } } /***************************************************************************/ BOOL ptrList_RemoveElement( PTRLIST *ptrList, void *psElement, SDWORD sdwKey ) { LISTNODE *psCurNode, *psPrevNode; BOOL bOK; ASSERT( PTRVALID(ptrList, sizeof(PTRLIST)), "ptrList_RemoveElement: table pointer invalid\n" ); psPrevNode = NULL; psCurNode = ptrList->psNode; /* find correct position to insert node */ while ( psCurNode != NULL && !(psCurNode->sdwKey == sdwKey && psCurNode->psElement == psElement) ) { psPrevNode = psCurNode; psCurNode = psCurNode->psNext; } /* remove node from hash table and return to heap */ if ( psCurNode == NULL ) { bOK = FALSE; } else { ASSERT( psCurNode->psElement == psElement, "ptrList_RemoveElement: removing wrong element!\n" ); /* remove from list */ if ( psPrevNode == NULL ) { ptrList->psNode = psCurNode->psNext; } else { psPrevNode->psNext = psCurNode->psNext; } /* check whether table current node pointer is this node */ if ( ptrList->psCurNode == psCurNode ) { /* point it to the previous node if valid */ if ( psPrevNode == NULL ) { /* set next node and set flag */ ptrList->psCurNode = psCurNode->psNext; ptrList->bDontGetNext = TRUE; } else { ptrList->psCurNode = psPrevNode; } } /* return element to heap */ ASSERT( PTRVALID(psCurNode->psElement, ptrList->udwElementSize), "ptrList_RemoveElement: element pointer invalid\n" ); ASSERT( psCurNode->psElement == psElement, "ptrList_RemoveElement: removing wrong element!\n" ); HEAP_FREE( ptrList->psElementHeap, psCurNode->psElement ); /* return node to heap */ ASSERT( PTRVALID(psCurNode, sizeof(LISTNODE)), "ptrList_RemoveElement: node pointer invalid\n" ); HEAP_FREE( ptrList->psNodeHeap, psCurNode ); bOK = TRUE; } return bOK; } /***************************************************************************/ void * ptrList_GetNext( PTRLIST *ptrList ) { void *pElement = NULL; if ( ptrList == NULL ) { pElement = NULL; } if ( ptrList->psCurNode == NULL ) { pElement = NULL; } else { if ( ptrList->bDontGetNext == TRUE ) { ptrList->bDontGetNext = FALSE; } else { ptrList->psCurNode = ptrList->psCurNode->psNext; } if ( ptrList->psCurNode == NULL ) { pElement = NULL; } else { pElement = ptrList->psCurNode->psElement; } } return pElement; } /***************************************************************************/ void * ptrList_GetFirst( PTRLIST *ptrList ) { void *pElement = NULL; ptrList->bDontGetNext = FALSE; ptrList->psCurNode = ptrList->psNode; if ( ptrList->psCurNode == NULL ) { pElement = NULL; } else { pElement = ptrList->psCurNode->psElement; } return pElement; } /***************************************************************************/