You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kvirc/src/kvilib/core/kvi_pointerhashtable.h

1000 lines
25 KiB

#ifndef _KVI_POINTERHASHTABLE_H_
#define _KVI_POINTERHASHTABLE_H_
//=================================================================================================
//
// File : kvi_pointerhashtable.h
// Creation date : Sat Jan 12 2008 04:53 by Szymon Stefanek
//
// This file is part of the KVirc irc client distribution
// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net)
//
// This program 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 opinion) any later version.
//
// This program 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 this program. If not, write to the Free Software Foundation,
// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
//=================================================================================================
#include "kvi_settings.h"
#include "kvi_pointerlist.h"
#include "kvi_string.h"
#include "kvi_qstring.h"
#include "kvi_malloc.h"
#include "kvi_memmove.h"
#include <ctype.h>
///
/// Hash functions for various data types
///
inline unsigned int kvi_hash_hash(const char * szKey,bool bCaseSensitive)
{
unsigned int uResult = 0;
if(bCaseSensitive)
{
while(*szKey)
{
uResult += (unsigned char)(*(szKey));
szKey++;
}
} else {
while(*szKey)
{
uResult += (unsigned char)tolower(*(szKey));
szKey++;
}
}
return uResult;
}
inline bool kvi_hash_key_equal(const char * szKey1,const char * szKey2,bool bCaseSensitive)
{
if(bCaseSensitive)
{
while(*szKey1 && *szKey2)
{
if(*szKey1 != *szKey2)
return false;
szKey1++;
szKey2++;
}
} else {
while(*szKey1 && *szKey2)
{
if(tolower(*szKey1) != tolower(*szKey2))
return false;
szKey1++;
szKey2++;
}
}
return true;
}
inline void kvi_hash_key_copy(const char * const &szFrom,const char * &szTo,bool bDeepCopy)
{
if(bDeepCopy)
{
int len = kvi_strLen(szFrom);
char * dst = (char *)kvi_malloc(len+1);
kvi_fastmove(dst,szFrom,len+1);
szTo = dst;
} else {
szTo = szFrom; // we never modify it anyway
}
}
inline void kvi_hash_key_destroy(const char * &szKey,bool bDeepCopy)
{
if(bDeepCopy)
kvi_free(szKey);
}
inline const char * & kvi_hash_key_default(const char **)
{
static const char * static_null = NULL;
return static_null;
}
inline unsigned int kvi_hash_hash(const KviStr &szKey,bool bCaseSensitive)
{
unsigned int uResult = 0;
const char * p = szKey.ptr();
if(bCaseSensitive)
{
while(*p)
{
uResult += *((const unsigned char *)p);
p++;
}
} else {
while(*p)
{
uResult += tolower(*((const unsigned char *)p));
p++;
}
}
return uResult;
}
inline bool kvi_hash_key_equal(const KviStr &szKey1,const KviStr &szKey2)
{
return kvi_hash_key_equal(szKey1.ptr(),szKey2.ptr());
}
inline void kvi_hash_key_copy(const KviStr &szFrom,KviStr &szTo,bool)
{
szTo = szFrom;
}
inline void kvi_hash_key_destroy(KviStr &szKey,bool)
{
}
inline const KviStr & kvi_hash_key_default(KviStr *)
{
return KviStr::emptyString();
}
inline unsigned int kvi_hash_hash(const int &iKey,bool)
{
return (unsigned int)iKey;
}
inline bool kvi_hash_key_equal(const int &iKey1,const int &iKey2,bool)
{
return iKey1 == iKey2;
}
inline void kvi_hash_key_copy(const int &iKeyFrom,int &iKeyTo,bool)
{
iKeyTo = iKeyFrom;
}
inline void kvi_hash_key_destroy(int &iKey,bool)
{
}
inline const int & kvi_hash_key_default(int *)
{
static int static_default = 0;
return static_default;
}
inline unsigned int kvi_hash_hash(const unsigned short &iKey,bool)
{
return (unsigned int)iKey;
}
inline bool kvi_hash_key_equal(const unsigned short &iKey1,const unsigned short &iKey2,bool)
{
return iKey1 == iKey2;
}
inline void kvi_hash_key_copy(const unsigned short &iKeyFrom,unsigned short &iKeyTo,bool)
{
iKeyTo = iKeyFrom;
}
inline void kvi_hash_key_destroy(unsigned short &iKey,bool)
{
}
inline const unsigned short & kvi_hash_key_default(unsigned short *)
{
static unsigned short static_default = 0;
return static_default;
}
inline unsigned int kvi_hash_hash(void * pKey,bool)
{
unsigned char * pBytes = (unsigned char *)&(pKey);
unsigned char * pEnd = pBytes + sizeof(void *);
unsigned int uSum = 0;
while(pBytes < pEnd)
{
uSum += *pBytes;
pBytes++;
}
return uSum;
}
inline bool kvi_hash_key_equal(void *pKey1,void *pKey2,bool)
{
return pKey1 == pKey2;
}
inline void kvi_hash_key_copy(void * const &pKeyFrom,void *&pKeyTo,bool)
{
pKeyTo = pKeyFrom;
}
inline void kvi_hash_key_destroy(void *iKey,bool)
{
}
inline void * & kvi_hash_key_default(void *)
{
static void * static_default = NULL;
return static_default;
}
inline unsigned int kvi_hash_hash(const TQString &szKey,bool bCaseSensitive)
{
unsigned int uResult = 0;
const TQChar * p = KviTQString::nullTerminatedArray(szKey);
if(!p)return 0;
if(bCaseSensitive)
{
while(p->tqunicode())
{
uResult += p->tqunicode();
p++;
}
} else {
while(p->tqunicode())
{
#ifdef COMPILE_USE_QT4
uResult += p->toLower().tqunicode();
#else
uResult += p->lower().tqunicode();
#endif
p++;
}
}
return uResult;
}
inline bool kvi_hash_key_equal(const TQString &szKey1,const TQString &szKey2,bool bCaseSensitive)
{
if(bCaseSensitive)
return KviTQString::equalCS(szKey1,szKey2);
return KviTQString::equalCI(szKey1,szKey2);
}
inline void kvi_hash_key_copy(const TQString &szFrom,TQString &szTo,bool)
{
szTo = szFrom;
}
inline void kvi_hash_key_destroy(TQString &szKey,bool)
{
}
inline const TQString & kvi_hash_key_default(TQString *)
{
return KviTQString::empty;
}
template<typename Key,typename T> class KviPointerHashTable;
template<typename Key,typename T> class KviPointerHashTableIterator;
template<typename Key,typename T> class KviPointerHashTableEntry
{
friend class KviPointerHashTable<Key,T>;
protected:
T * pData;
Key hKey;
public:
Key & key(){ return hKey; };
T * data(){ return pData; };
};
///
///
/// \class KviPointerHashTable
/// \brief A fast pointer hash table implementation
///
/// A very cool, very fast hash table implementation :P
///
/// To use this hash table you need to provide implementations
/// for the following functions:
///
/// \verbatim
///
/// unsigned int kvi_hash_hash(const Key &hKey,bool bCaseSensitive);
/// bool kvi_hash_key_equal(const Key &hKey1,const Key &hKey2,bool bCaseSensitive);
/// void kvi_hash_key_copy(const Key &hKeyFrom,Key &hKeyTo,bool bDeepCopy);
/// void kvi_hash_key_destroy(Key &hKey,bool bIsDeepCopy);
/// const Key & kvi_hash_key_default(Key *);
///
/// \endverbatim
///
/// Implementations for the most likey Key data types are provided below.
/// KviPointerHashTable will automagically work with const char *,TQString,KviStr
/// and integer types as keys.
///
/// For string Key types, the hash table may or may not be case sensitive.
/// For other Key types the case sensitive flag has no meaning and will
/// (hopefully) be optimized out by the compiler.
///
/// For pointer based keys the hash table may or may not mantain deep copies
/// of Key data. For example, with char * keys, if deep copying is enabled
/// then a private copy of the string data will be mantained. With deep
/// copying disabled only char * pointers will be kept. For types
/// that do not have meaning of deep copy the deep copying code will
/// (hopefully) be optimized out by the compiler.
///
/// The hashtable mantains an array of KviPointerList based buckets.
/// The number of buckets may be specified by the application user
/// and does NOT need to be a prime number. Yet better to have it a power
/// of two so the memory allocation routines will feel better and are
/// less likely to waste space.
///
template<class Key,class T> class KviPointerHashTable
{
friend class KviPointerHashTableIterator<Key,T>;
protected:
KviPointerList<KviPointerHashTableEntry<Key,T> > ** m_pDataArray;
bool m_bAutoDelete;
unsigned int m_uSize;
unsigned int m_uCount;
bool m_bCaseSensitive;
bool m_bDeepCopyKeys;
unsigned int m_uIteratorIdx;
public:
///
/// Returns the item associated to the key hKey
/// or NULL if no such item exists in the hash table.
/// Places the hash table iterator at the position
/// of the item found.
///
T * tqfind(const Key & hKey)
{
m_uIteratorIdx = kvi_hash_hash(hKey,m_bCaseSensitive) % m_uSize;
if(!m_pDataArray[m_uIteratorIdx])return 0;
for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->first();e;e = m_pDataArray[m_uIteratorIdx]->next())
{
if(kvi_hash_key_equal(e->hKey,hKey,m_bCaseSensitive))return (T *)e->pData;
}
return 0;
}
///
/// Returns the item associated to the key hKey
/// or NULL if no such item exists in the hash table.
/// Places the hash table iterator at the position
/// of the item found. This is an alias to tqfind().
///
T * operator[](const Key & hKey)
{
return tqfind(hKey);
}
///
/// Returns the number of items in this hash table
///
unsigned int count() const
{
return m_uCount;
}
///
/// Returns true if the hash table is empty
///
bool isEmpty() const
{
return m_uCount == 0;
}
///
/// Inserts the item pData at the position specified by the key hKey.
/// Replaces any previous item with the same key
/// The replaced item is deleted if autodelete is enabled.
/// The hash table iterator is placed at the newly inserted item.
///
void insert(const Key & hKey,T * pData)
{
if(!pData)return;
unsigned int uEntry = kvi_hash_hash(hKey,m_bCaseSensitive) % m_uSize;
if(!m_pDataArray[uEntry])m_pDataArray[uEntry] = new KviPointerList<KviPointerHashTableEntry<Key,T> >(true);
for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[uEntry]->first();e;e = m_pDataArray[uEntry]->next())
{
if(kvi_hash_key_equal(e->hKey,hKey,m_bCaseSensitive))
{
if(!m_bCaseSensitive)
{
// must change the key too
kvi_hash_key_destroy(e->hKey,m_bDeepCopyKeys);
kvi_hash_key_copy(hKey,e->hKey,m_bDeepCopyKeys);
}
if(m_bAutoDelete)delete e->pData;
e->pData = pData;
return;
}
}
KviPointerHashTableEntry<Key,T> * n = new KviPointerHashTableEntry<Key,T>;
kvi_hash_key_copy(hKey,n->hKey,m_bDeepCopyKeys);
n->pData = pData;
m_pDataArray[uEntry]->append(n);
m_uCount++;
}
///
/// Inserts the item pData at the position specified by the key hKey.
/// Replaces any previous item with the same key
/// The replaced item is deleted if autodelete is enabled.
/// The hash table iterator is placed at the newly inserted item.
/// This is just an alias to insert() with a different name.
///
void tqreplace(const Key & hKey,T * pData)
{
insert(hKey,pData);
}
///
/// Removes the item pointer associated to the key hKey, if such an item
/// exists in the hash table. The item is deleted if autodeletion
/// is enabled. Returns true if the item was found and removed and false if it wasn't found.
/// Invalidates the hash table iterator.
///
bool remove(const Key & hKey)
{
unsigned int uEntry = kvi_hash_hash(hKey,m_bCaseSensitive) % m_uSize;
if(!m_pDataArray[uEntry])return false;
for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[uEntry]->first();e;e = m_pDataArray[uEntry]->next())
{
if(kvi_hash_key_equal(e->hKey,hKey,m_bCaseSensitive))
{
kvi_hash_key_destroy(e->hKey,m_bDeepCopyKeys);
if(m_bAutoDelete)delete ((T *)(e->pData));
m_pDataArray[uEntry]->removeRef(e);
if(m_pDataArray[uEntry]->isEmpty())
{
delete m_pDataArray[uEntry];
m_pDataArray[uEntry] = 0;
}
m_uCount--;
return true;
}
}
return false;
}
///
/// Removes the first occurence of the item pointer pRef. The item is deleted if autodeletion
/// is enabled. Returns true if the pointer was found and false otherwise
/// Invalidates the hash table iterator.
///
bool removeRef(const T * pRef)
{
for(unsigned int i=0;i<m_uSize;i++)
{
if(m_pDataArray[i])
{
for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[i]->first();e;e = m_pDataArray[i]->next())
{
if(e->pData == pRef)
{
kvi_hash_key_destroy(e->hKey,m_bDeepCopyKeys);
if(m_bAutoDelete)delete ((T *)(e->pData));
m_pDataArray[i]->removeRef(e);
if(m_pDataArray[i]->isEmpty())
{
delete m_pDataArray[i];
m_pDataArray[i] = 0;
}
m_uCount--;
return true;
}
}
}
}
return false;
}
///
/// Removes all the items from the hash table.
/// The items are deleted if autodeletion is enabled.
/// Invalidates the hash table iterator.
///
void clear()
{
for(unsigned int i=0;i<m_uSize;i++)
{
if(m_pDataArray[i])
{
for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[i]->first();e;e = m_pDataArray[i]->next())
{
kvi_hash_key_destroy(e->hKey,m_bDeepCopyKeys);
if(m_bAutoDelete)
delete ((T *)(e->pData));
}
delete m_pDataArray[i];
m_pDataArray[i] = 0;
}
}
m_uCount = 0;
}
///
/// Searches for the item pointer pRef and returns
/// it's hash table entry, if found, and NULL otherwise.
/// The hash table iterator is placed at the item found.
///
KviPointerHashTableEntry<Key,T> * tqfindRef(const T * pRef)
{
for(m_uIteratorIdx = 0;m_uIteratorIdx<m_uSize;m_uIteratorIdx++)
{
if(m_pDataArray[m_uIteratorIdx])
{
for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->first();e;e = m_pDataArray[m_uIteratorIdx]->next())
{
if(e->pData == pRef)return e;
}
}
}
return 0;
}
///
/// Returns the entry pointed by the hash table iterator.
/// This function must be preceeded by a call to firstEntry(), first()
/// or tqfindRef().
///
KviPointerHashTableEntry<Key,T> * currentEntry()
{
if(m_uIteratorIdx >= m_uSize)return 0;
if(m_pDataArray[m_uIteratorIdx])return m_pDataArray[m_uIteratorIdx]->current();
return 0;
}
///
/// Places the hash table iterator at the first entry
/// and returns it.
///
KviPointerHashTableEntry<Key,T> * firstEntry()
{
m_uIteratorIdx = 0;
while(m_uIteratorIdx < m_uSize && (!m_pDataArray[m_uIteratorIdx]))
{
m_uIteratorIdx++;
}
if(m_uIteratorIdx == m_uSize)return 0;
return m_pDataArray[m_uIteratorIdx]->first();
}
///
/// Places the hash table iterator at the next entry
/// and returns it.
/// This function must be preceeded by a call to firstEntry(), first()
/// or tqfindRef().
///
KviPointerHashTableEntry<Key,T> * nextEntry()
{
if(m_uIteratorIdx >= m_uSize)return 0;
if(m_uIteratorIdx < m_uSize)
{
KviPointerHashTableEntry<Key,T> * t = m_pDataArray[m_uIteratorIdx]->next();
if(t)return t;
}
m_uIteratorIdx++;
while(m_uIteratorIdx < m_uSize && (!m_pDataArray[m_uIteratorIdx]))
{
m_uIteratorIdx++;
}
if(m_uIteratorIdx == m_uSize)return 0;
return m_pDataArray[m_uIteratorIdx]->first();
}
///
/// Returns the data value pointer pointed by the hash table iterator.
/// This function must be preceeded by a call to firstEntry(), first()
/// or tqfindRef().
///
T * current()
{
if(m_uIteratorIdx >= m_uSize)return 0;
if(m_pDataArray[m_uIteratorIdx])
{
KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->current();
if(!e)return 0;
return e->data();
}
return 0;
}
///
/// Returns the key pointed by the hash table iterator.
/// This function must be preceeded by a call to firstEntry(), first()
/// or tqfindRef().
///
const Key & currentKey()
{
if(m_uIteratorIdx >= m_uSize)return kvi_hash_key_default(((Key *)NULL));
if(m_pDataArray[m_uIteratorIdx])
{
KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->current();
if(!e)return kvi_hash_key_default(((Key *)NULL));
return e->key();
}
return kvi_hash_key_default(((Key *)NULL));
}
///
/// Places the hash table iterator at the first entry
/// and returns the associated data value pointer.
///
T * first()
{
m_uIteratorIdx = 0;
while(m_uIteratorIdx < m_uSize && (!m_pDataArray[m_uIteratorIdx]))
{
m_uIteratorIdx++;
}
if(m_uIteratorIdx == m_uSize)return 0;
KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->first();
if(!e)return 0;
return e->data();
}
///
/// Places the hash table iterator at the next entry
/// and returns the associated data value pointer.
/// This function must be preceeded by a call to firstEntry(), first()
/// or tqfindRef().
///
T * next()
{
if(m_uIteratorIdx >= m_uSize)return 0;
if(m_uIteratorIdx < m_uSize)
{
KviPointerHashTableEntry<Key,T> * t = m_pDataArray[m_uIteratorIdx]->next();
if(t)
{
return t->data();
}
}
m_uIteratorIdx++;
while(m_uIteratorIdx < m_uSize && (!m_pDataArray[m_uIteratorIdx]))
{
m_uIteratorIdx++;
}
if(m_uIteratorIdx == m_uSize)return 0;
KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->first();
if(!e)return 0;
return e->data();
}
///
/// Removes all items in the hash table and then
/// makes a complete shallow copy of the data contained in t.
/// The removed items are deleted if autodeletion is enabled.
/// The hash table iterator is tqinvalidated.
/// Does not change autodelete flag: make sure you not delete the items twice :)
///
void copyFrom(KviPointerHashTable<Key,T> &t)
{
clear();
for(KviPointerHashTableEntry<Key,T> * e = t.firstEntry();e;e = t.nextEntry())
insert(e->key(),e->data());
}
///
/// Inserts a complete shallow copy of the data contained in t.
/// The hash table iterator is tqinvalidated.
///
void insert(KviPointerHashTable<Key,T> &t)
{
for(KviPointerHashTableEntry<Key,T> * e = t.firstEntry();e;e = t.nextEntry())
insert(e->key(),e->data());
}
///
/// Enables or disabled the autodeletion feature.
/// Items are deleted upon removal when the feature is enabled.
///
void setAutoDelete(bool bAutoDelete)
{
m_bAutoDelete = bAutoDelete;
}
///
/// Creates an empty hash table.
/// Automatic deletion is enabled.
///
/// \param uSize The number of hash buckets: does NOT necesairly need to be prime
/// \param bCaseSensitive Are the key comparisons case sensitive ?
/// \param Do we need to mantain deep copies of keys ?
///
KviPointerHashTable(unsigned int uSize = 32,bool bCaseSensitive = true,bool bDeepCopyKeys = true)
{
m_uCount = 0;
m_bCaseSensitive = bCaseSensitive;
m_bAutoDelete = true;
m_bDeepCopyKeys = bDeepCopyKeys;
m_uSize = uSize > 0 ? uSize : 32;
m_pDataArray = new KviPointerList<KviPointerHashTableEntry<Key,T> > *[m_uSize];
for(unsigned int i=0;i<m_uSize;i++)m_pDataArray[i] = NULL;
}
///
/// First creates an empty hash table
/// and then inserts a copy of all the item pointers present in t.
/// The autodelete feature is automatically disabled (take care!).
///
KviPointerHashTable(KviPointerHashTable<Key,T> &t)
{
m_uCount = 0;
m_bAutoDelete = false;
m_bCaseSensitive = t.m_bCaseSensitive;
m_bDeepCopyKeys = t.m_bDeepCopyKeys;
m_uSize = t.m_uSize;
m_pDataArray = new KviPointerList<KviPointerHashTableEntry<Key,T> > *[m_uSize];
for(unsigned int i=0;i<m_uSize;i++)m_pDataArray[i] = NULL;
copyFrom(t);
}
///
/// Destroys the hash table and all the items contained within.
/// Items are deleted if autodeletion is enabled.
///
~KviPointerHashTable()
{
clear();
delete [] m_pDataArray;
}
};
template<typename Key,typename T> class KviPointerHashTableIterator
{
protected:
const KviPointerHashTable<Key,T> * m_pHashTable;
unsigned int m_uEntryIndex;
KviPointerListIterator<KviPointerHashTableEntry<Key,T> > * m_pIterator;
public:
///
/// Creates an iterator copy.
/// The new iterator points exactly to the item pointed by src.
///
void operator = (const KviPointerHashTableIterator<Key,T> &src)
{
m_pHashTable = src.m_pHashTable;
m_uEntryIndex = src.m_uEntryIndex;
if(src.m_pIterator)
m_pIterator = new KviPointerListIterator<KviPointerHashTableEntry<Key,T> >(*(src.m_pIterator));
else
m_pIterator = NULL;
}
///
/// Moves the iterator to the first element of the hash table.
/// Returns true in case of success or false if the hash table is empty.
///
bool moveFirst()
{
if(m_pIterator)
{
delete m_pIterator;
m_pIterator = NULL;
}
m_uEntryIndex = 0;
while((m_uEntryIndex < m_pHashTable->m_uSize) && (!(m_pHashTable->m_pDataArray[m_uEntryIndex])))
{
m_uEntryIndex++;
}
if(m_uEntryIndex == m_pHashTable->m_uSize)
return false;
m_pIterator = new KviPointerListIterator<KviPointerHashTableEntry<Key,T> >(*(m_pHashTable->m_pDataArray[m_uEntryIndex]));
bool bRet = m_pIterator->moveFirst();
if(!bRet)
{
delete m_pIterator;
m_pIterator = NULL;
}
return bRet;
}
///
/// Moves the iterator to the last element of the hash table.
/// Returns true in case of success or false if the hash table is empty.
///
bool moveLast()
{
if(m_pIterator)
{
delete m_pIterator;
m_pIterator = NULL;
}
m_uEntryIndex = m_pHashTable->m_uSize;
while(m_uEntryIndex > 0)
{
m_uEntryIndex--;
if(m_pHashTable->m_pDataArray[m_uEntryIndex])
{
m_pIterator = new KviPointerListIterator<KviPointerHashTableEntry<Key,T> >(*(m_pHashTable->m_pDataArray[m_uEntryIndex]));
bool bRet = m_pIterator->moveLast();
if(!bRet)
{
delete m_pIterator;
m_pIterator = NULL;
}
return bRet;
}
}
return false;
}
///
/// Moves the iterator to the next element of the hash table.
/// The iterator must be actually valid for this function to work.
/// Returns true in case of success or false if there is no next item.
///
bool moveNext()
{
if(!m_pIterator)
return false;
if(m_pIterator->moveNext())
return true;
if(m_pIterator)
{
delete m_pIterator;
m_pIterator = NULL;
}
m_uEntryIndex++;
while((m_uEntryIndex < m_pHashTable->m_uSize) && (!(m_pHashTable->m_pDataArray[m_uEntryIndex])))
{
m_uEntryIndex++;
}
if(m_uEntryIndex == m_pHashTable->m_uSize)
return false;
m_pIterator = new KviPointerListIterator<KviPointerHashTableEntry<Key,T> >(*(m_pHashTable->m_pDataArray[m_uEntryIndex]));
bool bRet = m_pIterator->moveFirst();
if(!bRet)
{
delete m_pIterator;
m_pIterator = NULL;
}
return bRet;
}
///
/// Moves the iterator to the next element of the hash table.
/// The iterator must be actually valid for this function to work.
/// Returns true in case of success or false if there is no next item.
/// This is just an alias to moveNext().
///
bool operator ++()
{
return moveNext();
}
///
/// Moves the iterator to the previous element of the hash table.
/// The iterator must be actually valid for this function to work.
/// Returns true in case of success or false if there is no previous item.
///
bool movePrev()
{
if(!m_pIterator)
return false;
if(m_pIterator->movePrev())
return true;
if(m_pIterator)
{
delete m_pIterator;
m_pIterator = NULL;
}
if(m_uEntryIndex >= m_pHashTable->m_uSize)
return false;
while(m_uEntryIndex > 0)
{
m_uEntryIndex--;
if(m_pHashTable->m_pDataArray[m_uEntryIndex])
{
m_pIterator = new KviPointerListIterator<KviPointerHashTableEntry<Key,T> >(*(m_pHashTable->m_pDataArray[m_uEntryIndex]));
bool bRet = m_pIterator->moveLast();
if(!bRet)
{
delete m_pIterator;
m_pIterator = NULL;
}
return bRet;
}
}
return false;
}
///
/// Moves the iterator to the previous element of the hash table.
/// The iterator must be actually valid for this function to work.
/// Returns true in case of success or false if there is no previous item.
/// This is just an alias to movePrev() with a different name.
///
bool operator --()
{
return movePrev();
}
///
/// Returs the value pointed by the iterator
/// or a default constructed value if the iterator is not valid.
/// This is an alias to operator *() with just a different name.
///
T * current() const
{
return m_pIterator ? m_pIterator->current()->data() : NULL;
}
///
/// Returs the value pointed by the iterator
/// or a default constructed value if the iterator is not valid.
/// This is an alias to current() with just a different name.
///
T * operator *() const
{
return m_pIterator ? m_pIterator->current()->data() : NULL;
}
///
/// Returs the key pointed by the iterator
/// or a default constructed key if the iterator is not valid.
///
const Key & currentKey() const
{
return m_pIterator ? m_pIterator->current()->key() : kvi_hash_key_default(((Key *)NULL));
}
///
/// Moves the iterator to the first element of the hash table.
/// Returns the first item found or NULL if the hash table is empty.
///
T * toFirst()
{
if(!moveFirst())
return NULL;
return current();
}
public:
///
/// Creates an iterator pointing to the first item in the hash table, if any.
///
KviPointerHashTableIterator(const KviPointerHashTable<Key,T> &hTable)
{
m_pHashTable = &hTable;
m_uEntryIndex = 0;
m_pIterator = NULL;
moveFirst();
}
///
/// Destroys the iterator
///
~KviPointerHashTableIterator()
{
if(m_pIterator)
delete m_pIterator;
}
};
#endif //_KVI_POINTERHASHTABLE_H_