2007-01-15 12:09:25 -08:00
|
|
|
/*
|
|
|
|
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
|
|
|
|
*/
|
2007-06-28 10:47:08 -07:00
|
|
|
/***************************************************************************/
|
|
|
|
/*
|
|
|
|
* Priority queue implementation
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
/***************************************************************************/
|
|
|
|
|
2006-06-02 12:34:58 -07:00
|
|
|
#include "lib/framework/frame.h"
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
#include "priority.h"
|
|
|
|
#include "pqueue.h"
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
#define QUEUE_INSERTION_TEST 1
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
BOOL
|
|
|
|
queue_Init( QUEUE ** ppQueue, int iMaxElements, int iElementSize,
|
|
|
|
QUEUE_CLEAR_FUNC pfClearFunc )
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
QUEUE_NODE *psNode;
|
|
|
|
|
|
|
|
/* allocate queue */
|
|
|
|
(*ppQueue) = (QUEUE *) MALLOC( sizeof(QUEUE) );
|
2006-06-02 12:34:58 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
if ( (*ppQueue) == NULL )
|
|
|
|
{
|
2006-08-22 07:28:49 -07:00
|
|
|
debug( LOG_ERROR, "queue_Init: couldn't allocate memory for queue" );
|
|
|
|
abort();
|
2007-06-28 10:47:08 -07:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set up free node list */
|
|
|
|
(*ppQueue)->psFreeNodeList = NULL;
|
|
|
|
for ( i=0; i<iMaxElements; i++ )
|
|
|
|
{
|
|
|
|
/* allocate node */
|
|
|
|
psNode = (QUEUE_NODE *) MALLOC( sizeof(QUEUE_NODE) );
|
|
|
|
|
|
|
|
if ( (*ppQueue) == NULL )
|
|
|
|
{
|
2006-08-22 07:28:49 -07:00
|
|
|
debug( LOG_ERROR, "queue_Init: couldn't allocate memory for queue node" );
|
|
|
|
abort();
|
2007-06-28 10:47:08 -07:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* init node */
|
|
|
|
psNode->psElement = NULL;
|
|
|
|
psNode->iPriority = LOW_PRIORITY;
|
|
|
|
|
|
|
|
/* add to head of list */
|
|
|
|
psNode->psPrev = NULL;
|
|
|
|
psNode->psNext = (*ppQueue)->psFreeNodeList;
|
|
|
|
(*ppQueue)->psFreeNodeList = psNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* init node counts */
|
|
|
|
(*ppQueue)->iFreeNodes = iMaxElements;
|
|
|
|
(*ppQueue)->iQueueNodes = 0;
|
|
|
|
|
|
|
|
/* init queue list */
|
|
|
|
(*ppQueue)->psNodeQHead = NULL;
|
|
|
|
(*ppQueue)->psCurNode = NULL;
|
|
|
|
|
|
|
|
/* init other queue struct members */
|
|
|
|
(*ppQueue)->iElementSize = iElementSize;
|
|
|
|
(*ppQueue)->iMaxElements = iMaxElements;
|
|
|
|
(*ppQueue)->pfClearFunc = pfClearFunc;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
void
|
|
|
|
queue_Destroy( QUEUE * pQueue )
|
|
|
|
{
|
|
|
|
QUEUE_NODE *psNode;
|
|
|
|
|
|
|
|
/* free up free node list */
|
|
|
|
while ( pQueue->psFreeNodeList != NULL )
|
|
|
|
{
|
|
|
|
psNode = pQueue->psFreeNodeList;
|
|
|
|
pQueue->psFreeNodeList = pQueue->psFreeNodeList->psNext;
|
|
|
|
FREE( psNode );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free up node queue */
|
|
|
|
while ( pQueue->psNodeQHead != NULL )
|
|
|
|
{
|
|
|
|
psNode = pQueue->psNodeQHead;
|
|
|
|
pQueue->psNodeQHead = pQueue->psNodeQHead->psNext;
|
|
|
|
FREE( psNode );
|
|
|
|
}
|
|
|
|
FREE( pQueue );
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
void queue_Clear( QUEUE * pQueue )
|
|
|
|
{
|
|
|
|
QUEUE_NODE *psNode;
|
|
|
|
|
|
|
|
while ( pQueue->psNodeQHead != NULL )
|
|
|
|
{
|
|
|
|
psNode = pQueue->psNodeQHead;
|
|
|
|
pQueue->psNodeQHead = pQueue->psNodeQHead->psNext;
|
|
|
|
|
|
|
|
/* do element callback */
|
|
|
|
(pQueue->pfClearFunc)(psNode->psElement);
|
|
|
|
|
|
|
|
/* return node to free node list */
|
|
|
|
psNode->psNext = pQueue->psFreeNodeList;
|
|
|
|
pQueue->psFreeNodeList = psNode;
|
|
|
|
|
|
|
|
/* update node counts */
|
|
|
|
pQueue->iFreeNodes++;
|
|
|
|
pQueue->iQueueNodes--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
/*
|
|
|
|
* queue_Enqueue
|
|
|
|
*
|
|
|
|
* Add element to queue in priority order
|
|
|
|
*/
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
void
|
|
|
|
queue_Enqueue( QUEUE * pQueue, void * psElement, int iPriority )
|
|
|
|
{
|
|
|
|
QUEUE_NODE *psFreeNode, *psNode, *psNodePrev;
|
|
|
|
|
|
|
|
/* check input */
|
2006-08-23 05:58:48 -07:00
|
|
|
ASSERT( PTRVALID(pQueue,sizeof(QUEUE)),
|
|
|
|
"queue_Enqueue: queue pointer invalid\n" );
|
|
|
|
ASSERT( PTRVALID(psElement,pQueue->iElementSize),
|
|
|
|
"queue_Enqueue: element pointer invalid\n" );
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
#if QUEUE_INSERTION_TEST
|
|
|
|
psNode = pQueue->psNodeQHead;
|
|
|
|
while ( psNode != NULL )
|
|
|
|
{
|
2006-08-23 05:58:48 -07:00
|
|
|
ASSERT( psNode->psElement != psElement,
|
|
|
|
"duplicate element found\n" );
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
psNode = psNode->psNext;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* check list not empty */
|
|
|
|
if ( pQueue->psFreeNodeList == NULL )
|
|
|
|
{
|
2006-08-22 07:28:49 -07:00
|
|
|
debug( LOG_NEVER, "queue_GetFreeElement: all nodes allocated: flushing queue.\n" );
|
2007-06-28 10:47:08 -07:00
|
|
|
queue_Clear( pQueue );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get free node from head of list */
|
|
|
|
psFreeNode = pQueue->psFreeNodeList;
|
|
|
|
pQueue->psFreeNodeList = pQueue->psFreeNodeList->psNext;
|
|
|
|
|
|
|
|
/* update node counts */
|
|
|
|
pQueue->iFreeNodes--;
|
|
|
|
pQueue->iQueueNodes++;
|
|
|
|
|
|
|
|
/* attach element to node */
|
|
|
|
psFreeNode->psElement = psElement;
|
|
|
|
|
|
|
|
/* init pointer to head of queue */
|
|
|
|
psNode = pQueue->psNodeQHead;
|
|
|
|
psNodePrev = NULL;
|
2006-06-02 12:34:58 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
/* init node priority */
|
|
|
|
psFreeNode->iPriority = iPriority;
|
|
|
|
|
|
|
|
/* find correct place in queue according to priority */
|
|
|
|
while ( psNode != NULL )
|
|
|
|
{
|
|
|
|
/* break if priority slot found */
|
|
|
|
if ( psNode->iPriority < iPriority )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update pointers */
|
|
|
|
psNodePrev = psNode;
|
|
|
|
psNode = psNode->psNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* insert new node */
|
|
|
|
psFreeNode->psPrev = psNodePrev;
|
|
|
|
psFreeNode->psNext = psNode;
|
|
|
|
|
|
|
|
/* update previous queue node pointer */
|
|
|
|
if ( psNodePrev == NULL )
|
|
|
|
{
|
|
|
|
pQueue->psNodeQHead = psFreeNode;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
psNodePrev->psNext = psFreeNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update next queue node pointer */
|
|
|
|
if ( psNode != NULL )
|
|
|
|
{
|
|
|
|
psNode->psPrev = psFreeNode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
/*
|
|
|
|
* queue_Dequeue
|
|
|
|
*
|
|
|
|
* Remove head of queue
|
|
|
|
*/
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
void *
|
|
|
|
queue_Dequeue( QUEUE * pQueue )
|
|
|
|
{
|
|
|
|
void * psElement = NULL;
|
|
|
|
QUEUE_NODE * psNode;
|
|
|
|
|
|
|
|
/* check input */
|
2006-08-23 05:58:48 -07:00
|
|
|
ASSERT( PTRVALID(pQueue,sizeof(QUEUE)),
|
|
|
|
"queue_Dequeue: queue pointer invalid\n" );
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
if ( pQueue->psNodeQHead != NULL )
|
|
|
|
{
|
|
|
|
/* remove node at head of queue */
|
|
|
|
psNode = pQueue->psNodeQHead;
|
|
|
|
pQueue->psNodeQHead = pQueue->psNodeQHead->psNext;
|
|
|
|
|
|
|
|
/* copy element from node for return */
|
|
|
|
psElement = psNode->psElement;
|
|
|
|
|
|
|
|
/* return node to free node list */
|
|
|
|
psNode->psNext = pQueue->psFreeNodeList;
|
|
|
|
pQueue->psFreeNodeList = psNode;
|
|
|
|
|
|
|
|
/* update node counts */
|
|
|
|
pQueue->iFreeNodes++;
|
|
|
|
pQueue->iQueueNodes--;
|
|
|
|
|
2006-08-23 05:58:48 -07:00
|
|
|
ASSERT( pQueue->iQueueNodes >= 0, "queue_Dequeue: queue nodes < 0" );
|
2007-06-28 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return psElement;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
/*
|
|
|
|
* queue_FindElement
|
|
|
|
*
|
|
|
|
* Find specific element in queue and return node pointer
|
|
|
|
*/
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
QUEUE_NODE *
|
|
|
|
queue_FindElement( QUEUE * pQueue, void * psElement )
|
|
|
|
{
|
|
|
|
QUEUE_NODE *psNode, *psNodePrev;
|
|
|
|
|
|
|
|
/* check input */
|
2006-08-23 05:58:48 -07:00
|
|
|
ASSERT( PTRVALID(pQueue,sizeof(QUEUE)),
|
|
|
|
"queue_FindElement: queue pointer invalid\n" );
|
|
|
|
ASSERT( PTRVALID(psElement,pQueue->iElementSize),
|
|
|
|
"queue_FindElement: element pointer invalid\n" );
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
/* init pointers to head of queue */
|
|
|
|
psNodePrev = psNode = pQueue->psNodeQHead;
|
2006-06-02 12:34:58 -07:00
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
/* find node in queue */
|
|
|
|
while ( psNodePrev != NULL && psNode != NULL )
|
|
|
|
{
|
|
|
|
/* return TRUE if match found */
|
|
|
|
if ( psNode->psElement == psElement )
|
|
|
|
{
|
|
|
|
return psNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update pointers */
|
|
|
|
psNodePrev = psNode;
|
|
|
|
psNode = psNode->psNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
/*
|
|
|
|
* queue_GetHead
|
|
|
|
*
|
|
|
|
* Get element at head of queue
|
|
|
|
*/
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
void *
|
|
|
|
queue_GetHead( QUEUE * pQueue )
|
|
|
|
{
|
|
|
|
/* set current node to head of queue */
|
|
|
|
pQueue->psCurNode = pQueue->psNodeQHead;
|
|
|
|
|
|
|
|
if ( pQueue->psCurNode != NULL )
|
|
|
|
{
|
|
|
|
return pQueue->psCurNode->psElement;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
/*
|
|
|
|
* queue_GetNext
|
|
|
|
*
|
|
|
|
* Get next element in queue
|
|
|
|
*/
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
void *
|
|
|
|
queue_GetNext( QUEUE * pQueue )
|
|
|
|
{
|
|
|
|
/* move to next node */
|
|
|
|
if ( pQueue->psCurNode != NULL )
|
|
|
|
{
|
|
|
|
pQueue->psCurNode = pQueue->psCurNode->psNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return node element */
|
|
|
|
if ( pQueue->psCurNode == NULL )
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return pQueue->psCurNode->psElement;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
/*
|
|
|
|
* queue_RemoveCurrent
|
|
|
|
*
|
|
|
|
* Remove current node from queue
|
|
|
|
*/
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
BOOL
|
|
|
|
queue_RemoveCurrent( QUEUE * pQueue )
|
|
|
|
{
|
|
|
|
return queue_RemoveNode( pQueue, pQueue->psCurNode );
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
/*
|
|
|
|
* queue_RemoveNode
|
|
|
|
*
|
|
|
|
* Remove node from queue
|
|
|
|
*/
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
BOOL
|
|
|
|
queue_RemoveNode( QUEUE * pQueue, QUEUE_NODE *psNode )
|
|
|
|
{
|
|
|
|
/* check input */
|
2006-08-23 05:58:48 -07:00
|
|
|
ASSERT( PTRVALID(pQueue,sizeof(QUEUE)),
|
|
|
|
"queue_RemoveNode: queue pointer invalid\n" );
|
|
|
|
ASSERT( PTRVALID(psNode,sizeof(QUEUE_NODE)),
|
|
|
|
"queue_RemoveNode: node pointer invalid\n" );
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
/* if node valid, remove from queue and return to free node list */
|
|
|
|
if ( psNode == NULL )
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* remove node from queue */
|
|
|
|
if ( psNode->psPrev == NULL && psNode->psNext == NULL )
|
|
|
|
{
|
|
|
|
pQueue->psCurNode = NULL;
|
|
|
|
pQueue->psNodeQHead = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* make previous node point to next */
|
|
|
|
if ( psNode->psPrev != NULL )
|
|
|
|
{
|
|
|
|
psNode->psPrev->psNext = psNode->psNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make next node point to previous */
|
|
|
|
if ( psNode->psNext != NULL )
|
|
|
|
{
|
|
|
|
psNode->psNext->psPrev = psNode->psPrev;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set current queue node if necessary */
|
|
|
|
if ( pQueue->psCurNode == psNode )
|
|
|
|
{
|
|
|
|
if ( psNode->psPrev != NULL )
|
|
|
|
{
|
|
|
|
pQueue->psCurNode = psNode->psPrev;
|
|
|
|
}
|
|
|
|
else if ( psNode->psNext != NULL )
|
|
|
|
{
|
|
|
|
pQueue->psCurNode = psNode->psNext;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pQueue->psCurNode = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update queue pointer if neccessary */
|
|
|
|
if ( pQueue->psNodeQHead == psNode )
|
|
|
|
{
|
|
|
|
pQueue->psNodeQHead = psNode->psNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return node to free node list */
|
|
|
|
psNode->psNext = pQueue->psFreeNodeList;
|
|
|
|
pQueue->psFreeNodeList = psNode;
|
|
|
|
|
|
|
|
/* update node counts */
|
|
|
|
pQueue->iFreeNodes++;
|
|
|
|
pQueue->iQueueNodes--;
|
|
|
|
|
2006-08-23 05:58:48 -07:00
|
|
|
ASSERT( pQueue->iQueueNodes >= 0, "queue_RemoveNode: queue nodes < 0" );
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
/*
|
|
|
|
* queue_RemoveElement
|
|
|
|
*
|
|
|
|
* Remove specific element from queue
|
|
|
|
*/
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
BOOL
|
|
|
|
queue_RemoveElement( QUEUE * pQueue, void * psElement )
|
|
|
|
{
|
|
|
|
QUEUE_NODE *psNode;
|
|
|
|
|
|
|
|
/* check input */
|
2006-08-23 05:58:48 -07:00
|
|
|
ASSERT( PTRVALID(pQueue,sizeof(QUEUE)),
|
|
|
|
"queue_Dequeue: queue pointer invalid\n" );
|
|
|
|
ASSERT( PTRVALID(psElement,pQueue->iElementSize),
|
|
|
|
"queue_RemoveElement: element pointer invalid\n" );
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
if ( (psNode = queue_FindElement( pQueue, psElement )) != NULL )
|
|
|
|
{
|
|
|
|
queue_RemoveNode( pQueue, psNode );
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************/
|