f8/stlstarfsa.h
2019-10-09 14:17:08 +08:00

253 lines
5.6 KiB
C++

/*
A* Algorithm Implementation using STL is
Copyright (C)2001-2005 Justin Heyes-Jones
Permission is given by the author to freely redistribute and
include this code in any program as long as this credit is
given where due.
COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE
IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND
PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED
CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL
DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF
WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE
OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
THIS DISCLAIMER.
Use at your own risk!
FixedSizeAllocator class
Copyright 2001 Justin Heyes-Jones
This class is a constant time O(1) memory manager for objects of
a specified type. The type is specified using a template class.
Memory is allocated from a fixed size buffer which you can specify in the
class constructor or use the default.
Using GetFirst and GetNext it is possible to iterate through the elements
one by one, and this would be the most common use for the class.
I would suggest using this class when you want O(1) add and delete
and you don't do much searching, which would be O(n). Structures such as binary
trees can be used instead to get O(logn) access time.
*/
#ifndef STLSTARFSA_H
#define STLSTARFSA_H
#include <string.h>
#include <stdio.h>
template <class USER_TYPE> class FixedSizeAllocator
{
public:
// Constants
enum
{
FSA_DEFAULT_SIZE = 100
};
// This class enables us to transparently manage the extra data
// needed to enable the user class to form part of the double-linked
// list class
struct FSA_ELEMENT
{
USER_TYPE UserType;
FSA_ELEMENT *pPrev;
FSA_ELEMENT *pNext;
};
public: // methods
FixedSizeAllocator( unsigned int MaxElements = FSA_DEFAULT_SIZE ) :
m_pFirstUsed( NULL ),
m_MaxElements( MaxElements )
{
// Allocate enough memory for the maximum number of elements
char *pMem = new char[ m_MaxElements * sizeof(FSA_ELEMENT) ];
m_pMemory = (FSA_ELEMENT *) pMem;
// Set the free list first pointer
m_pFirstFree = m_pMemory;
// Clear the memory
memset( (void*)m_pMemory, 0, sizeof( FSA_ELEMENT ) * m_MaxElements );
// Point at first element
FSA_ELEMENT *pElement = m_pFirstFree;
// Set the double linked free list
for( unsigned int i=0; i<m_MaxElements; i++ )
{
pElement->pPrev = pElement-1;
pElement->pNext = pElement+1;
pElement++;
}
// first element should have a null prev
m_pFirstFree->pPrev = NULL;
// last element should have a null next
(pElement-1)->pNext = NULL;
}
~FixedSizeAllocator()
{
// Free up the memory
delete [] (char *) m_pMemory;
}
// Allocate a new USER_TYPE and return a pointer to it
USER_TYPE *alloc()
{
FSA_ELEMENT *pNewNode = NULL;
if( !m_pFirstFree )
{
return NULL;
}
else
{
pNewNode = m_pFirstFree;
m_pFirstFree = pNewNode->pNext;
// if the new node points to another free node then
// change that nodes prev free pointer...
if( pNewNode->pNext )
{
pNewNode->pNext->pPrev = NULL;
}
// node is now on the used list
pNewNode->pPrev = NULL; // the allocated node is always first in the list
if( m_pFirstUsed == NULL )
{
pNewNode->pNext = NULL; // no other nodes
}
else
{
m_pFirstUsed->pPrev = pNewNode; // insert this at the head of the used list
pNewNode->pNext = m_pFirstUsed;
}
m_pFirstUsed = pNewNode;
}
return reinterpret_cast<USER_TYPE*>(pNewNode);
}
// Free the given user type
// For efficiency I don't check whether the user_data is a valid
// pointer that was allocated. I may add some debug only checking
// (To add the debug check you'd need to make sure the pointer is in
// the m_pMemory area and is pointing at the start of a node)
void free( USER_TYPE *user_data )
{
FSA_ELEMENT *pNode = reinterpret_cast<FSA_ELEMENT*>(user_data);
// manage used list, remove this node from it
if( pNode->pPrev )
{
pNode->pPrev->pNext = pNode->pNext;
}
else
{
// this handles the case that we delete the first node in the used list
m_pFirstUsed = pNode->pNext;
}
if( pNode->pNext )
{
pNode->pNext->pPrev = pNode->pPrev;
}
// add to free list
if( m_pFirstFree == NULL )
{
// free list was empty
m_pFirstFree = pNode;
pNode->pPrev = NULL;
pNode->pNext = NULL;
}
else
{
// Add this node at the start of the free list
m_pFirstFree->pPrev = pNode;
pNode->pNext = m_pFirstFree;
m_pFirstFree = pNode;
}
}
// For debugging this displays both lists (using the prev/next list pointers)
void Debug()
{
printf( "free list " );
FSA_ELEMENT *p = m_pFirstFree;
while( p )
{
printf( "%x!%x ", p->pPrev, p->pNext );
p = p->pNext;
}
printf( "\n" );
printf( "used list " );
p = m_pFirstUsed;
while( p )
{
printf( "%x!%x ", p->pPrev, p->pNext );
p = p->pNext;
}
printf( "\n" );
}
// Iterators
USER_TYPE *GetFirst()
{
return reinterpret_cast<USER_TYPE *>(m_pFirstUsed);
}
USER_TYPE *GetNext( USER_TYPE *node )
{
return reinterpret_cast<USER_TYPE *>
(
(reinterpret_cast<FSA_ELEMENT *>(node))->pNext
);
}
public: // data
private: // methods
private: // data
FSA_ELEMENT *m_pFirstFree;
FSA_ELEMENT *m_pFirstUsed;
unsigned int m_MaxElements;
FSA_ELEMENT *m_pMemory;
};
#endif // defined STLSTARFSA_H