883 lines
30 KiB
C++
883 lines
30 KiB
C++
![]() |
/********************************************************/
|
||
|
/* Hash Table template class - v1.2 */
|
||
|
/* */
|
||
|
/* Author: Jake Hotson */
|
||
|
/* */
|
||
|
/* construct a hash table for objects of type TYPE */
|
||
|
/* */
|
||
|
/* HashTable<TYPE>(unsigned initialTableSizeShift */
|
||
|
/* = HT_DEFAULTTABLESIZESHIFT); */
|
||
|
/* */
|
||
|
/* TYPE must have boolean operator == defined, and */
|
||
|
/* there must be an overload of the function */
|
||
|
/* HashFunction() which acts as a hash */
|
||
|
/* function for the TYPE, taking an argument of type */
|
||
|
/* TYPE or a suitable conversion thereof, and returning */
|
||
|
/* unsigned */
|
||
|
/* Also, if a==b then HashFunction(a)==HashFunction(b) */
|
||
|
/* Additionally, TYPE must have valid assignment */
|
||
|
/* operator and copy constructor */
|
||
|
/****************************************************Jake*/
|
||
|
|
||
|
/************************************************************/
|
||
|
/* */
|
||
|
/* v1.0 public classes and functions and macros */
|
||
|
/* */
|
||
|
/* HASH_TEMPLATE_VERSION */
|
||
|
/* */
|
||
|
/* major version * 100 + minor version */
|
||
|
/* in this version (1.0) the value is 100 */
|
||
|
/* */
|
||
|
/* HT_NODEFAULTFNS */
|
||
|
/* */
|
||
|
/* #define to not compile default hash functions */
|
||
|
/* */
|
||
|
/* HT_DEFAULTABLESIZESHIFT */
|
||
|
/* */
|
||
|
/* #define to override default table size shift */
|
||
|
/* of 6 (which gives a default table size of 64) */
|
||
|
/* */
|
||
|
/* HT_FAIL(sP) */
|
||
|
/* */
|
||
|
/* this macro should expand to a function (which */
|
||
|
/* takes a char const * parameter) to be called */
|
||
|
/* in the event of an error */
|
||
|
/* */
|
||
|
/* HashFunction(unsigned) */
|
||
|
/* */
|
||
|
/* default hash function for integers */
|
||
|
/* */
|
||
|
/* HashFunction(void const *) */
|
||
|
/* */
|
||
|
/* default hash function for pointers */
|
||
|
/* */
|
||
|
/* HashFunction(char const *) */
|
||
|
/* */
|
||
|
/* default hash function for strings */
|
||
|
/* */
|
||
|
/* class HashTable<TYPE> */
|
||
|
/* */
|
||
|
/* hash table template class */
|
||
|
/* TYPE should have == operator defined and an */
|
||
|
/* overloaded HashFunction() defined which can */
|
||
|
/* take an argument type TYPE or suitable */
|
||
|
/* conversion thereof */
|
||
|
/* */
|
||
|
/* HashTable::HashTable() */
|
||
|
/* */
|
||
|
/* constructs an empty table with default table */
|
||
|
/* size */
|
||
|
/* */
|
||
|
/* HashTable::HashTable(unsigned) */
|
||
|
/* */
|
||
|
/* constructs an empty table with specific */
|
||
|
/* table size determined by 2^arg */
|
||
|
/* */
|
||
|
/* bool HashTable::AddChecked(TYPE) */
|
||
|
/* */
|
||
|
/* adds object to hash table unless it already */
|
||
|
/* contains it. Returns non-zero if object was */
|
||
|
/* added, and zero if it was already contained */
|
||
|
/* */
|
||
|
/* void HashTable::AddRegardless(TYPE) */
|
||
|
/* */
|
||
|
/* adds object to hash table but does not check */
|
||
|
/* if it already exists, so duplicates could */
|
||
|
/* occur */
|
||
|
/* */
|
||
|
/* void HashTable::AddAsserted(TYPE) */
|
||
|
/* */
|
||
|
/* adds object to hash table but throws a failure if it */
|
||
|
/* already exists unless NDEBUG is defined in which case */
|
||
|
/* this function is identical to AddRegardless */
|
||
|
/* */
|
||
|
/* TYPE const * HashTable::Contains(TYPE) const */
|
||
|
/* */
|
||
|
/* returns pointer to equivalent entry in table, */
|
||
|
/* or NULL, if none exists */
|
||
|
/* */
|
||
|
/* bool HashTable::Remove(TYPE) */
|
||
|
/* */
|
||
|
/* removes object from table if it exists. */
|
||
|
/* Returns non-zero if object was removed, or */
|
||
|
/* zero if object was not contained */
|
||
|
/* */
|
||
|
/* void HashTable::RemoveAll() */
|
||
|
/* */
|
||
|
/* empties the table */
|
||
|
/* */
|
||
|
/* void HashTable::RemoveAsserted(TYPE) */
|
||
|
/* */
|
||
|
/* removes object from table, but throws a */
|
||
|
/* failure if object was not contained */
|
||
|
/* */
|
||
|
/* unsigned HashTable::Size() const */
|
||
|
/* */
|
||
|
/* returns number of objects in table */
|
||
|
/* */
|
||
|
/* class HashTable<TYPE>::ConstIterator */
|
||
|
/* */
|
||
|
/* class for iterating through objects contained */
|
||
|
/* in hash table, without modifying the contents */
|
||
|
/* of the table */
|
||
|
/* */
|
||
|
/* HashTable::ConstIterator::ConstIterator(HashTable const) */
|
||
|
/* */
|
||
|
/* constructs an iterator linked to a table, */
|
||
|
/* ready for a Get() */
|
||
|
/* */
|
||
|
/* TYPE const & HashTable::ConstIterator::Get() const */
|
||
|
/* HashTable::ConstIterator::operator TYPE const & () const */
|
||
|
/* */
|
||
|
/* gets a constant reference to the object in */
|
||
|
/* the table pointed to by the iterator object */
|
||
|
/* */
|
||
|
/* bool HashTable::ConstIterator::Done() const */
|
||
|
/* */
|
||
|
/* returns non-zero only if there is no more */
|
||
|
/* iterating to do */
|
||
|
/* */
|
||
|
/* void HashTable::ConstIterator::Next() */
|
||
|
/* */
|
||
|
/* moves iterator to a fresh entry in the table */
|
||
|
/* */
|
||
|
/* class HashTable<TYPE>::Iterator */
|
||
|
/* */
|
||
|
/* class for iterating through objects contained */
|
||
|
/* in hash table, allowing their removal */
|
||
|
/* */
|
||
|
/* HashTable::Iterator::Iterator(HashTable) */
|
||
|
/* */
|
||
|
/* constructs an iterator linked to a table, */
|
||
|
/* ready for a Get() */
|
||
|
/* */
|
||
|
/* HashTable::Iterator::Remove() */
|
||
|
/* */
|
||
|
/* removes the current object pointed to by the */
|
||
|
/* iterator from the table, and advances the */
|
||
|
/* iterator to the next entry */
|
||
|
/* */
|
||
|
/*******************************************************Jake*/
|
||
|
|
||
|
/************************************************************/
|
||
|
/* */
|
||
|
/* v1.1 - v1.11 extended functionality */
|
||
|
/* */
|
||
|
/* class HashTable<TYPE>::Node */
|
||
|
/* */
|
||
|
/* this is the internal class for nodes in the table */
|
||
|
/* */
|
||
|
/* TYPE HashTable::Node::d */
|
||
|
/* */
|
||
|
/* this is the value of a node's data */
|
||
|
/* */
|
||
|
/* Node * HashTable::NewNode() */
|
||
|
/* */
|
||
|
/* allocates a node without inserting it into the table; */
|
||
|
/* you are expected to set Node::d to the required value */
|
||
|
/* to be added to the table, and call one of these methods */
|
||
|
/* to link the node into the table */
|
||
|
/* */
|
||
|
/* void HashTable::AddAsserted(Node *) */
|
||
|
/* */
|
||
|
/* like AddAsserted(TYPE const &) but takes a Node * */
|
||
|
/* created with NewNode(); do not use the Node * pointer */
|
||
|
/* after calling this method */
|
||
|
/* */
|
||
|
/* void HashTable::AddRegardless(Node *) */
|
||
|
/* */
|
||
|
/* like AddRegardless(TYPE const &) but takes a Node * */
|
||
|
/* created with NewNode(); do not use the Node * pointer */
|
||
|
/* after calling this method */
|
||
|
/* */
|
||
|
/* bool HashTable::AddChecked(Node *) */
|
||
|
/* */
|
||
|
/* like AddChecked(TYPE const &) but takes a Node * */
|
||
|
/* created with NewNode(); do not use the Node * pointer */
|
||
|
/* after calling this method if it returns true, but if it */
|
||
|
/* returns false (i.e. the Node was not added, then you */
|
||
|
/* can re-use the Node or use the following function to */
|
||
|
/* delete it. */
|
||
|
/* */
|
||
|
/* void HashTable::DeleteNode(Node *) */
|
||
|
/* */
|
||
|
/* destroys a Node created with NewNode. Use this only if */
|
||
|
/* the node created was not added to the hash table */
|
||
|
/* */
|
||
|
/*******************************************************Jake*/
|
||
|
|
||
|
/************************************************************/
|
||
|
/* */
|
||
|
/* v1.2 */
|
||
|
/* */
|
||
|
/* HashTable::Iterator::Restart() */
|
||
|
/* restarts the iterator */
|
||
|
/* */
|
||
|
/* HashTable::HashTable(HashTable<TYPE>) */
|
||
|
/* copy constructor */
|
||
|
/* */
|
||
|
/* HashTable::ValueIterator(unsigned) */
|
||
|
/* iterate through all entries of a specific hashvalue */
|
||
|
/* */
|
||
|
/*******************************************************Alex*/
|
||
|
|
||
|
#ifndef HASH_TEMPLATE_VERSION
|
||
|
#define HASH_TEMPLATE_VERSION 12 // v1.2
|
||
|
|
||
|
#include <stddef.h>
|
||
|
#include <ctype.h>// for toupper
|
||
|
|
||
|
// v1,0 Default Hash Functions defined:
|
||
|
// HashFunction(unsigned), HashFunction(void const *), HashFunction(char const *)
|
||
|
// you can disable the default hash functions by defining HT_NODEFAULTFNS
|
||
|
|
||
|
#ifndef HT_NODEFAULTFNS
|
||
|
// a hash function for integral (unsigned) values
|
||
|
inline unsigned HashFunction(unsigned const _i)
|
||
|
{
|
||
|
return _i ^ _i>>4 ^ _i>>9 ^ _i>>15 ^ _i>>22;
|
||
|
}
|
||
|
|
||
|
// a hash function for pointers
|
||
|
inline unsigned HashFunction(void const * const _vP)
|
||
|
{
|
||
|
// treat as integer
|
||
|
return HashFunction(reinterpret_cast<unsigned>(_vP));
|
||
|
}
|
||
|
|
||
|
// a hash function for strings
|
||
|
inline unsigned HashFunction(char const * _sP)
|
||
|
{
|
||
|
unsigned rv = 0;
|
||
|
while (*_sP) rv += toupper(*_sP++);
|
||
|
return rv;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// v1,0 Default (initial) table size (log2 of)
|
||
|
// Define this to another value if you like,
|
||
|
// or just override in the constructor.
|
||
|
// in v1.0, the table is not self-expanding,
|
||
|
// but if this feature is implememted, then
|
||
|
// this value will become the log2(initial table size),
|
||
|
// and if table becomes is self-contracting,
|
||
|
// this value will also give the minimum table size
|
||
|
|
||
|
#ifndef HT_DEFAULTTABLESIZESHIFT
|
||
|
#define HT_DEFAULTTABLESIZESHIFT 6
|
||
|
#endif
|
||
|
|
||
|
// for asserted functions, define HT_FAIL to be your function
|
||
|
// to be triggered upon a failure, eg.
|
||
|
// #define HT_FAIL(strP) fprintf(stderr,"%s\n",strP)
|
||
|
#ifndef HT_FAIL
|
||
|
#define HT_FAIL(strP) ((void)0)
|
||
|
#endif
|
||
|
|
||
|
template <class TYPE, class ARG_TYPE, class CMP_ARG_TYPE>
|
||
|
class _base_HashTable
|
||
|
{
|
||
|
public:
|
||
|
class Iterator;
|
||
|
class ConstIterator;
|
||
|
class ValueIterator;
|
||
|
class Node;
|
||
|
|
||
|
public:
|
||
|
// V1.0 Functionality
|
||
|
|
||
|
// empty constructor, with argument specifying initial table size (log2 of)
|
||
|
_base_HashTable(unsigned = HT_DEFAULTTABLESIZESHIFT);
|
||
|
|
||
|
// destructor
|
||
|
~_base_HashTable();
|
||
|
|
||
|
// copy constructor and assignment not provided in v1.0
|
||
|
_base_HashTable(_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> const &);
|
||
|
_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> & operator = (_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> const &);
|
||
|
|
||
|
// add, checking that an equivalent entry does not already exist
|
||
|
// returns non-zero if entry was added
|
||
|
bool AddChecked(ARG_TYPE);
|
||
|
|
||
|
// add, regardless of whether an equivalent entry already exists
|
||
|
void AddRegardless(ARG_TYPE);
|
||
|
|
||
|
// add, checking that an equivalent entry does not already exist
|
||
|
// triggering fail function if one does
|
||
|
void AddAsserted(ARG_TYPE);
|
||
|
|
||
|
// see if entry exists, get pointer to it if it does
|
||
|
TYPE const * Contains(CMP_ARG_TYPE) const;
|
||
|
|
||
|
// remove an entry (once only in the case of equivalent entries listed multiple times)
|
||
|
// returns non-zero if entry existed and was removed
|
||
|
bool Remove(CMP_ARG_TYPE);
|
||
|
|
||
|
// remove an entry (once only in the case of equivalent entries listed multiple times)
|
||
|
// triggers fail function if no entry existed to remove
|
||
|
void RemoveAsserted(CMP_ARG_TYPE);
|
||
|
|
||
|
// empty the table
|
||
|
void RemoveAll();
|
||
|
|
||
|
// return num entries in table
|
||
|
unsigned Size() const;
|
||
|
|
||
|
// a _base_HashTable const iterator
|
||
|
class ConstIterator
|
||
|
{
|
||
|
// Nested class functions apparently have to be declared here for MSVC compatability
|
||
|
public:
|
||
|
// construct from const hash table
|
||
|
ConstIterator(_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> const & tableR)
|
||
|
: chainPP(tableR.chainPA)
|
||
|
, nChainsRemaining(tableR.tableSize)
|
||
|
, nEntriesRemaining(tableR.nEntries)
|
||
|
{
|
||
|
if (nEntriesRemaining)
|
||
|
{
|
||
|
while (!*chainPP)
|
||
|
{
|
||
|
++ chainPP;
|
||
|
-- nChainsRemaining;
|
||
|
}
|
||
|
nodePP = chainPP;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// returns non-zero if there are no more entries to get
|
||
|
inline bool Done() const
|
||
|
{
|
||
|
return ! nEntriesRemaining;
|
||
|
}
|
||
|
|
||
|
inline void Restart(_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> const & tableR)
|
||
|
{
|
||
|
chainPP = tableR.chainPA;
|
||
|
nChainsRemaining = tableR.tableSize;
|
||
|
nEntriesRemaining = tableR.nEntries;
|
||
|
|
||
|
if (nEntriesRemaining)
|
||
|
{
|
||
|
while (!*chainPP)
|
||
|
{
|
||
|
++ chainPP;
|
||
|
-- nChainsRemaining;
|
||
|
}
|
||
|
nodePP = chainPP;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// get the current entry pointed to, either with Get() or cast operator
|
||
|
inline operator ARG_TYPE () const
|
||
|
{
|
||
|
return Get();
|
||
|
}
|
||
|
inline ARG_TYPE Get() const
|
||
|
{
|
||
|
if( Done() )
|
||
|
{
|
||
|
HT_FAIL("HTT: Tried to Get() from an iterator which was Done()");
|
||
|
}
|
||
|
return (*nodePP)->d;
|
||
|
}
|
||
|
|
||
|
// advance to the next entry
|
||
|
void Next()
|
||
|
{
|
||
|
if (!nEntriesRemaining)
|
||
|
{
|
||
|
HT_FAIL("HTT: Tried to do Next() on an iterator which was Done()");
|
||
|
}
|
||
|
if ((*nodePP)->nextP)
|
||
|
{
|
||
|
nodePP = &(*nodePP)->nextP;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
++ chainPP;
|
||
|
-- nChainsRemaining;
|
||
|
}
|
||
|
while (nChainsRemaining && !*chainPP);
|
||
|
nodePP = chainPP;
|
||
|
}
|
||
|
-- nEntriesRemaining;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
|
||
|
Node * * chainPP;
|
||
|
Node * * nodePP;
|
||
|
unsigned nChainsRemaining;
|
||
|
unsigned nEntriesRemaining;
|
||
|
|
||
|
friend class Iterator;
|
||
|
};
|
||
|
|
||
|
// a _base_HashTable non-const iterator - can remove entry pointed to
|
||
|
class Iterator : public ConstIterator
|
||
|
{
|
||
|
// Nested class functions apparently have to be declared here for MSVC compatability
|
||
|
public:
|
||
|
// construct from hash table
|
||
|
inline Iterator(_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> & tableR)
|
||
|
: ConstIterator(tableR)
|
||
|
, tableNEntriesP(&tableR.nEntries)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// remove the current entry pointed to, advancing to the next
|
||
|
void Remove()
|
||
|
{
|
||
|
if (!nEntriesRemaining)
|
||
|
{
|
||
|
HT_FAIL("HTT: Tried to Remove() via an iterator which was Done()");
|
||
|
}
|
||
|
Node * oldP = *nodePP;
|
||
|
*nodePP = oldP->nextP;
|
||
|
delete oldP;
|
||
|
if (!*nodePP)
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
++ chainPP;
|
||
|
-- nChainsRemaining;
|
||
|
}
|
||
|
while (nChainsRemaining && !*chainPP);
|
||
|
nodePP = chainPP;
|
||
|
}
|
||
|
-- nEntriesRemaining;
|
||
|
-- *tableNEntriesP;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
unsigned * tableNEntriesP;
|
||
|
};
|
||
|
|
||
|
// v1.2 extended functionality
|
||
|
// a _base_HashTable iterator through a specific hash value
|
||
|
class ValueIterator
|
||
|
{
|
||
|
// Nested class functions apparently have to be declared here for MSVC compatability
|
||
|
public:
|
||
|
// construct from const hash table
|
||
|
ValueIterator(_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> & tableR, unsigned value)
|
||
|
: chainPP(tableR.chainPA)
|
||
|
, value(value)
|
||
|
, tableNEntriesP(&tableR.nEntries)
|
||
|
{
|
||
|
chainPP += (value & tableR.tableSizeMask);
|
||
|
nodePP = chainPP;
|
||
|
}
|
||
|
|
||
|
// returns non-zero if there are no more entries to get
|
||
|
inline bool Done() const
|
||
|
{
|
||
|
return( !(*nodePP) );
|
||
|
}
|
||
|
|
||
|
inline operator ARG_TYPE () const
|
||
|
{
|
||
|
return Get();
|
||
|
}
|
||
|
inline ARG_TYPE Get() const
|
||
|
{
|
||
|
if( Done() )
|
||
|
{
|
||
|
HT_FAIL("HTT: Tried to Get() from an iterator which was Done()");
|
||
|
}
|
||
|
return (*nodePP)->d;
|
||
|
}
|
||
|
|
||
|
inline void Restart(_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> const & tableR)
|
||
|
{
|
||
|
chainPP = tableR.chainPA + (value & tableR.tableSizeMask);
|
||
|
nodePP = chainPP;
|
||
|
}
|
||
|
|
||
|
// advance to the next entry
|
||
|
void Next()
|
||
|
{
|
||
|
if( *nodePP )
|
||
|
{
|
||
|
nodePP = &(*nodePP)->nextP; // even if it's NULL for ValueIterator
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
HT_FAIL("HTT: Tried to do Next() on a Value iterator which was Done()");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// remove the current entry pointed to, advancing to the next
|
||
|
void Remove()
|
||
|
{
|
||
|
if( *nodePP )
|
||
|
{
|
||
|
Node * oldP = *nodePP;
|
||
|
*nodePP = oldP->nextP;
|
||
|
delete oldP;
|
||
|
-- *tableNEntriesP;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
HT_FAIL("HTT: Tried to Remove() via an iterator which was Done()");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
|
||
|
Node * * chainPP;
|
||
|
Node * * nodePP;
|
||
|
|
||
|
unsigned value;
|
||
|
unsigned * tableNEntriesP;
|
||
|
};
|
||
|
|
||
|
// V1.1 extended functionality
|
||
|
// allow user to create nodes, change
|
||
|
// the data using this pointer,
|
||
|
// then insert the node into the
|
||
|
// correct chain, without having
|
||
|
// to create a copy of the data to
|
||
|
// be added on the stack
|
||
|
virtual Node * NewNode();
|
||
|
// add, checking that an equivalent entry does not already exist
|
||
|
// triggering fail function if one does
|
||
|
void AddAsserted(Node *);
|
||
|
// add, regardless of whether an equivalent entry already exists
|
||
|
void AddRegardless(Node *);
|
||
|
// V1.11 allows AddChecked for the Node-adding interface
|
||
|
bool AddChecked(Node *);
|
||
|
// if add checked fails, you should avoid the memory leak with this function
|
||
|
virtual void DeleteNode(Node *);
|
||
|
|
||
|
class Node
|
||
|
{
|
||
|
public:
|
||
|
TYPE d;
|
||
|
private:
|
||
|
Node * nextP;
|
||
|
// Nested class functions apparently have to be declared here for MSVC compatability
|
||
|
inline Node(ARG_TYPE _dataR,Node * _nextP)
|
||
|
: d(_dataR)
|
||
|
, nextP(_nextP)
|
||
|
{
|
||
|
}
|
||
|
inline Node()
|
||
|
{
|
||
|
}
|
||
|
inline ~Node()
|
||
|
{
|
||
|
}
|
||
|
void DeleteChain()
|
||
|
{
|
||
|
if (nextP) nextP->DeleteChain();
|
||
|
delete this;
|
||
|
}
|
||
|
|
||
|
friend class ConstIterator;
|
||
|
friend class Iterator;
|
||
|
friend class ValueIterator;
|
||
|
friend class _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>;
|
||
|
};
|
||
|
|
||
|
private:
|
||
|
// virtual functions for future expansion
|
||
|
virtual Node * NewNode(ARG_TYPE,Node *);
|
||
|
|
||
|
unsigned nEntries;
|
||
|
unsigned tableSize;
|
||
|
unsigned tableSizeMask;
|
||
|
Node * * chainPA;
|
||
|
|
||
|
friend class ConstIterator;
|
||
|
friend class Iterator;
|
||
|
friend class ValueIterator;
|
||
|
|
||
|
inline void Xx(){}
|
||
|
};
|
||
|
|
||
|
/*******************/
|
||
|
/* Defined to Fail */
|
||
|
/**************Jake*/
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
inline _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> & _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::operator = (_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> const &)
|
||
|
{
|
||
|
HT_FAIL("HTT: assignment operator not allowed in this version");
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
/*******************************/
|
||
|
/* Inline Function Definitions */
|
||
|
/**************************Jake*/
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
inline void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::AddRegardless(ARG_TYPE _dataR)
|
||
|
{
|
||
|
Node * & chainPR = chainPA[HashFunction(_dataR) & tableSizeMask];
|
||
|
chainPR = new Node(_dataR,chainPR);
|
||
|
++ nEntries;
|
||
|
}
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
inline void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::AddRegardless(Node * _nodeP)
|
||
|
{
|
||
|
Node * & chainPR = chainPA[HashFunction(_nodeP->d) & tableSizeMask];
|
||
|
_nodeP->nextP = chainPR;
|
||
|
chainPR = _nodeP;
|
||
|
++ nEntries;
|
||
|
}
|
||
|
|
||
|
// with NDEBUG on these functions evaluate to be identical to AddRegardless
|
||
|
#ifdef NDEBUG
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
inline void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::AddAsserted(ARG_TYPE _dataR)
|
||
|
{
|
||
|
AddRegardless(_dataR);
|
||
|
}
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
inline void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::AddAsserted(Node * _nodeP)
|
||
|
{
|
||
|
AddRegardless(_nodeP);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
inline TYPE const * _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::Contains(CMP_ARG_TYPE _dataR) const
|
||
|
{
|
||
|
for (Node const * nodeP = chainPA[HashFunction(_dataR) & tableSizeMask]; nodeP; nodeP = nodeP->nextP)
|
||
|
{
|
||
|
if (nodeP->d == _dataR) return &nodeP->d;
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
inline unsigned _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::Size() const
|
||
|
{
|
||
|
return nEntries;
|
||
|
}
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
inline void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::RemoveAll()
|
||
|
{
|
||
|
for (unsigned i=0; i<tableSize; ++i)
|
||
|
if (chainPA[i])
|
||
|
{
|
||
|
chainPA[i]->DeleteChain();
|
||
|
chainPA[i] = NULL;
|
||
|
}
|
||
|
nEntries = 0;
|
||
|
}
|
||
|
|
||
|
/*************************************************************/
|
||
|
/* Non inlines declared here since neither Watcom nor */
|
||
|
/* MS Visual C will link if they're in their own source file */
|
||
|
/********************************************************Jake*/
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::_base_HashTable(unsigned _initialTableSizeShift)
|
||
|
: nEntries(0)
|
||
|
, tableSize(1<<_initialTableSizeShift)
|
||
|
, tableSizeMask(tableSize-1)
|
||
|
, chainPA(new Node * [tableSize])
|
||
|
{
|
||
|
for (unsigned i=0; i<tableSize; ++i)
|
||
|
chainPA[i] = NULL;
|
||
|
}
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
inline _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::_base_HashTable(_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> const & ht)
|
||
|
: nEntries(0)
|
||
|
, tableSize(ht.tableSize)
|
||
|
, tableSizeMask(tableSize-1)
|
||
|
, chainPA(new Node * [tableSize])
|
||
|
{
|
||
|
for (unsigned i=0; i<tableSize; ++i) { chainPA[i] = NULL; }
|
||
|
|
||
|
for( HashTable<TYPE>::ConstIterator it(ht); !it.Done(); it.Next() )
|
||
|
{
|
||
|
AddRegardless( it.Get() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::~_base_HashTable()
|
||
|
{
|
||
|
for (unsigned i=0; i<tableSize; ++i)
|
||
|
if (chainPA[i])
|
||
|
chainPA[i]->DeleteChain();
|
||
|
delete[] chainPA;
|
||
|
}
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
bool _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::AddChecked(ARG_TYPE _dataR)
|
||
|
{
|
||
|
Node * & chainPR = chainPA[HashFunction(_dataR) & tableSizeMask];
|
||
|
for (Node const * nodeP = chainPR; nodeP; nodeP = nodeP->nextP)
|
||
|
{
|
||
|
if (nodeP->d == _dataR) return false;
|
||
|
}
|
||
|
chainPR = new Node(_dataR,chainPR);
|
||
|
++ nEntries;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
bool _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::AddChecked(Node * _nodeP)
|
||
|
{
|
||
|
Node * & chainPR = chainPA[HashFunction(_nodeP->d) & tableSizeMask];
|
||
|
for (Node const * nodeP = chainPR; nodeP; nodeP = nodeP->nextP)
|
||
|
{
|
||
|
if (nodeP->d == _nodeP->d) return false;
|
||
|
}
|
||
|
_nodeP->nextP = chainPR;
|
||
|
chainPR = _nodeP;
|
||
|
++ nEntries;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// with NDEBUG on these functions evaluate to be identical to AddRegardless
|
||
|
#ifndef NDEBUG
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::AddAsserted(ARG_TYPE _dataR)
|
||
|
{
|
||
|
Node * & chainPR = chainPA[HashFunction(_dataR) & tableSizeMask];
|
||
|
for (Node const * nodeP = chainPR; nodeP; nodeP = nodeP->nextP)
|
||
|
{
|
||
|
if (nodeP->d == _dataR)
|
||
|
{
|
||
|
HT_FAIL("HTT: Tried to add entry which was already contained in table");
|
||
|
}
|
||
|
}
|
||
|
chainPR = new Node(_dataR,chainPR);
|
||
|
++ nEntries;
|
||
|
}
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::AddAsserted(Node * _nodeP)
|
||
|
{
|
||
|
Node * & chainPR = chainPA[HashFunction(_nodeP->d) & tableSizeMask];
|
||
|
for (Node const * nodeP = chainPR; nodeP; nodeP = nodeP->nextP)
|
||
|
{
|
||
|
if (nodeP->d == _nodeP->d)
|
||
|
{
|
||
|
HT_FAIL("HTT: Tried to add entry which was already contained in table");
|
||
|
}
|
||
|
}
|
||
|
_nodeP->nextP = chainPR;
|
||
|
chainPR = _nodeP;
|
||
|
++ nEntries;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
bool _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::Remove(CMP_ARG_TYPE _dataR)
|
||
|
{
|
||
|
for (Node * * nodePP = &chainPA[HashFunction(_dataR) & tableSizeMask]; (*nodePP); nodePP = &(*nodePP)->nextP)
|
||
|
{
|
||
|
if ((*nodePP)->d == _dataR)
|
||
|
{
|
||
|
Node * oldP = *nodePP;
|
||
|
*nodePP = oldP->nextP;
|
||
|
delete oldP;
|
||
|
-- nEntries;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::RemoveAsserted(CMP_ARG_TYPE _dataR)
|
||
|
{
|
||
|
for (Node * * nodePP = &chainPA[HashFunction(_dataR) & tableSizeMask]; (*nodePP); nodePP = &(*nodePP)->nextP)
|
||
|
{
|
||
|
if ((*nodePP)->d == _dataR)
|
||
|
{
|
||
|
Node * oldP = *nodePP;
|
||
|
*nodePP = oldP->nextP;
|
||
|
delete oldP;
|
||
|
-- nEntries;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
HT_FAIL("HTT: Tried to remove entry which was not contained in table");
|
||
|
}
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::Node * _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::NewNode(ARG_TYPE _dataR,Node * _nextP)
|
||
|
{
|
||
|
return new Node(_dataR,_nextP);
|
||
|
}
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::Node * _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::NewNode()
|
||
|
{
|
||
|
return new Node;
|
||
|
}
|
||
|
|
||
|
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
|
||
|
void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::DeleteNode(Node * _nodeP)
|
||
|
{
|
||
|
delete _nodeP;
|
||
|
}
|
||
|
|
||
|
template <class TYPE> class HashTable;
|
||
|
|
||
|
#define HT_DEFINITION(T1,T2,T3) \
|
||
|
: public _base_HashTable<T1,T2,T3> { public: HashTable(unsigned _initialTableSizeShift = HT_DEFAULTTABLESIZESHIFT) : _base_HashTable<T1,T2,T3>(_initialTableSizeShift){} };
|
||
|
|
||
|
// for simple types
|
||
|
#define HT_WATCOM_DEFINE_FOR_SIMPLE_TYPE(TYPE) \
|
||
|
class HashTable<TYPE> HT_DEFINITION(TYPE,TYPE,TYPE)
|
||
|
|
||
|
#ifdef __WATCOMC__
|
||
|
|
||
|
//watcom generartes errors if template<> is added to the start of the line - Richard.
|
||
|
#define HT_DEFINE_FOR_SIMPLE_TYPE(SIMPLE_TYPE) HT_WATCOM_DEFINE_FOR_SIMPLE_TYPE(SIMPLE_TYPE)
|
||
|
|
||
|
#else
|
||
|
|
||
|
#define HT_DEFINE_FOR_SIMPLE_TYPE(SIMPLE_TYPE) template<> HT_WATCOM_DEFINE_FOR_SIMPLE_TYPE(SIMPLE_TYPE)
|
||
|
|
||
|
#endif
|
||
|
|
||
|
HT_DEFINE_FOR_SIMPLE_TYPE(unsigned long)
|
||
|
HT_DEFINE_FOR_SIMPLE_TYPE(signed long)
|
||
|
HT_DEFINE_FOR_SIMPLE_TYPE(unsigned)
|
||
|
HT_DEFINE_FOR_SIMPLE_TYPE(signed)
|
||
|
HT_DEFINE_FOR_SIMPLE_TYPE(unsigned short)
|
||
|
HT_DEFINE_FOR_SIMPLE_TYPE(signed short)
|
||
|
HT_DEFINE_FOR_SIMPLE_TYPE(unsigned char)
|
||
|
HT_DEFINE_FOR_SIMPLE_TYPE(signed char)
|
||
|
HT_DEFINE_FOR_SIMPLE_TYPE(char)
|
||
|
HT_DEFINE_FOR_SIMPLE_TYPE(float)
|
||
|
|
||
|
#undef HT_DEFINE_FOR_SIMPLE_TYPE
|
||
|
#undef HT_WATCOM_DEFINE_FOR_SIMPLE_TYPE
|
||
|
|
||
|
// for pointer types
|
||
|
#if 0 // doesnt't compile!!
|
||
|
template <class TYPE>
|
||
|
class HashTable<TYPE *> HT_DEFINITION(TYPE *, TYPE *, TYPE const *)
|
||
|
|
||
|
template <class TYPE>
|
||
|
class HashTable<TYPE const *> HT_DEFINITION(TYPE const *, TYPE const *, TYPE const *)
|
||
|
#endif
|
||
|
|
||
|
// for other types
|
||
|
template <class TYPE>
|
||
|
class HashTable HT_DEFINITION(TYPE,TYPE const &, TYPE const &)
|
||
|
|
||
|
//template <class TYPE *> class HashTable : public _base_HashTable<TYPE *,TYPE *,TYPE const *> {};
|
||
|
|
||
|
#undef HT_DEFINITION
|
||
|
|
||
|
#endif // ! HASH_TEMPLATE_VERSION
|