mirror of https://github.com/qt/qtdatavis3d.git
668 lines
14 KiB
C++
668 lines
14 KiB
C++
#ifndef _XN_HASH_T_H_
|
|
#define _XN_HASH_T_H_
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Includes
|
|
//---------------------------------------------------------------------------
|
|
#include <XnOS.h>
|
|
#include <XnListT.h>
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Defines
|
|
//---------------------------------------------------------------------------
|
|
typedef XnUInt8 XnHashCode;
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Code
|
|
//---------------------------------------------------------------------------
|
|
template<class _TKey, class _TValue>
|
|
struct XnKeyValuePair
|
|
{
|
|
typedef _TKey TKey;
|
|
typedef _TValue TValue;
|
|
|
|
XnKeyValuePair() : key(TKey()), value(TValue()) {}
|
|
XnKeyValuePair(TKey key, TValue value) : key(key), value(value) {}
|
|
XnKeyValuePair(const XnKeyValuePair& other) : key(other.key), value(other.value) {}
|
|
|
|
public:
|
|
TKey const& Key() const { return key; }
|
|
TValue const& Value() const { return value; }
|
|
TValue& Value() { return value; }
|
|
|
|
private:
|
|
TKey key;
|
|
TValue value;
|
|
};
|
|
|
|
template<class TKey>
|
|
class XnDefaultKeyManagerT
|
|
{
|
|
public:
|
|
static XnHashCode Hash(TKey const& key)
|
|
{
|
|
return (((XnSizeT)key) & 0xff);
|
|
}
|
|
|
|
static XnInt32 Compare(TKey const& key1, TKey const& key2)
|
|
{
|
|
return XnInt32(XnSizeT(key1)-XnSizeT(key2));
|
|
}
|
|
};
|
|
|
|
template<class TKey,
|
|
class TValue,
|
|
class TKeyManager = XnDefaultKeyManagerT<TKey>,
|
|
class TAlloc = XnLinkedNodeDefaultAllocatorT<XnKeyValuePair<TKey, TValue> > >
|
|
class XnHashT
|
|
{
|
|
public:
|
|
typedef XnKeyValuePair<TKey, TValue> TPair;
|
|
typedef XnListT<TPair, TAlloc> TPairList;
|
|
|
|
enum
|
|
{
|
|
LAST_BIN = (1 << (sizeof(XnHashCode)*8)),
|
|
NUM_BINS = LAST_BIN + 1,
|
|
};
|
|
|
|
class ConstIterator
|
|
{
|
|
public:
|
|
ConstIterator() : m_ppBins(NULL), m_nCurrBin(0)
|
|
{}
|
|
|
|
ConstIterator(TPairList* const* apBins, XnUInt32 nCurrBin, typename TPairList::ConstIterator currIt)
|
|
: m_ppBins(apBins), m_nCurrBin(nCurrBin), m_currIt(currIt)
|
|
{
|
|
if (nCurrBin != LAST_BIN && m_currIt == m_ppBins[m_nCurrBin]->End())
|
|
{
|
|
// this does not point to an actual entry. run to next one.
|
|
++*this;
|
|
}
|
|
}
|
|
|
|
ConstIterator(const ConstIterator& other)
|
|
: m_ppBins(other.m_ppBins), m_nCurrBin(other.m_nCurrBin), m_currIt(other.m_currIt)
|
|
{}
|
|
|
|
/**
|
|
* Support ++iterator, go to the next object in the list
|
|
*/
|
|
ConstIterator& operator++()
|
|
{
|
|
XN_ASSERT(m_nCurrBin != LAST_BIN);
|
|
|
|
// increment internal bin iterator
|
|
if (m_currIt != m_ppBins[m_nCurrBin]->End())
|
|
{
|
|
++m_currIt;
|
|
}
|
|
|
|
// check if we need to move to next bin
|
|
if (m_currIt == m_ppBins[m_nCurrBin]->End())
|
|
{
|
|
// go forward through bins, until we either reach the end or a non-empty bin
|
|
do
|
|
{
|
|
++m_nCurrBin;
|
|
} while (m_nCurrBin < LAST_BIN &&
|
|
(m_ppBins[m_nCurrBin] == NULL || m_ppBins[m_nCurrBin]->IsEmpty()));
|
|
|
|
m_currIt = m_ppBins[m_nCurrBin]->Begin();
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* Support iterator++, go to the next object in the list, returning the old value
|
|
*/
|
|
ConstIterator operator++(int)
|
|
{
|
|
ConstIterator retVal(*this);
|
|
++*this;
|
|
return retVal;
|
|
}
|
|
|
|
/**
|
|
* Support --iterator, go to the previous object in the hash
|
|
*/
|
|
ConstIterator& operator--()
|
|
{
|
|
XN_ASSERT(m_nCurrBin != LAST_BIN);
|
|
|
|
// decrement internal bin iterator
|
|
if (m_currIt != m_ppBins[m_nCurrBin]->ReverseEnd())
|
|
{
|
|
--m_currIt;
|
|
}
|
|
|
|
// check if we need to move to previous bin
|
|
if (m_currIt == m_ppBins[m_nCurrBin]->ReverseEnd())
|
|
{
|
|
// go backwards through bins, until we either reach the end or a non-empty bin
|
|
do
|
|
{
|
|
if (m_nCurrBin == 0)
|
|
{
|
|
m_nCurrBin = LAST_BIN;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
--m_nCurrBin;
|
|
}
|
|
} while (m_ppBins[m_nCurrBin] == NULL || m_ppBins[m_nCurrBin]->IsEmpty());
|
|
|
|
m_currIt = m_ppBins[m_nCurrBin]->Begin();
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* Support iterator--, go to the previous object in the hash, returning the old value
|
|
*/
|
|
ConstIterator operator--(int)
|
|
{
|
|
ConstIterator retVal(*this);
|
|
--*this;
|
|
return retVal;
|
|
}
|
|
|
|
/**
|
|
* Operator to check if two iterators point to the same object
|
|
*
|
|
* @param other [in] instance to compare with
|
|
*/
|
|
inline XnBool operator==(const ConstIterator& other) const
|
|
{
|
|
return m_currIt == other.m_currIt;
|
|
}
|
|
|
|
/**
|
|
* Operator to check if two iterators point to different objects
|
|
*
|
|
* @param other [in] instance to compare with
|
|
*/
|
|
inline XnBool operator!=(const ConstIterator& other) const
|
|
{
|
|
return m_currIt != other.m_currIt;
|
|
}
|
|
|
|
/**
|
|
* Get the value of the current object (const version)
|
|
*/
|
|
inline TPair const& operator*() const
|
|
{
|
|
return *m_currIt;
|
|
}
|
|
|
|
/**
|
|
* Get a pointer to the value of the current object (const version)
|
|
*/
|
|
inline TPair const* operator->() const
|
|
{
|
|
return m_currIt.operator->();
|
|
}
|
|
|
|
protected:
|
|
friend class XnHashT;
|
|
|
|
TPairList* const* m_ppBins;
|
|
XnUInt32 m_nCurrBin;
|
|
typename TPairList::ConstIterator m_currIt;
|
|
};
|
|
|
|
class Iterator : public ConstIterator
|
|
{
|
|
public:
|
|
Iterator() : ConstIterator()
|
|
{}
|
|
|
|
Iterator(TPairList** apBins, XnUInt32 nCurrBin, typename TPairList::Iterator currIt)
|
|
: ConstIterator(apBins, nCurrBin, currIt)
|
|
{}
|
|
|
|
Iterator(const Iterator& other) : ConstIterator(other)
|
|
{}
|
|
|
|
/**
|
|
* Support ++iterator, go to the next object in the list
|
|
*/
|
|
Iterator& operator++()
|
|
{
|
|
++(*(ConstIterator*)this);
|
|
return (*this);
|
|
}
|
|
|
|
/**
|
|
* Support iterator++, go to the next object in the list, returning the old value
|
|
*/
|
|
inline Iterator operator++(int)
|
|
{
|
|
Iterator retVal(*this);
|
|
++*this;
|
|
return (retVal);
|
|
}
|
|
|
|
/**
|
|
* Support --iterator, go to the next object in the list
|
|
*/
|
|
inline Iterator& operator--()
|
|
{
|
|
--(*(ConstIterator*)this);
|
|
return (*this);
|
|
}
|
|
|
|
/**
|
|
* Support iterator--, go to the next object in the list, returning the old value
|
|
*/
|
|
inline Iterator operator--(int)
|
|
{
|
|
Iterator retVal(*this);
|
|
--*this;
|
|
return (retVal);
|
|
}
|
|
|
|
/**
|
|
* Get the value of the current object
|
|
*/
|
|
inline TPair& operator*() const
|
|
{
|
|
return const_cast<TPair&>(*this->m_currIt);
|
|
}
|
|
|
|
/**
|
|
* Get a pointer to the value of the current object
|
|
*/
|
|
inline TPair* operator->() const
|
|
{
|
|
return const_cast<TPair*>(this->m_currIt.operator->());
|
|
}
|
|
};
|
|
|
|
XnHashT()
|
|
{
|
|
Init();
|
|
}
|
|
|
|
XnHashT(const XnHashT& other)
|
|
{
|
|
Init();
|
|
*this = other;
|
|
}
|
|
|
|
XnHashT& operator=(const XnHashT& other)
|
|
{
|
|
Clear();
|
|
|
|
XnStatus nRetVal = XN_STATUS_OK;
|
|
|
|
for (ConstIterator it = other.Begin(); it != other.End(); ++it)
|
|
{
|
|
nRetVal = Set(it->Key(), it->Value());
|
|
XN_ASSERT(nRetVal == XN_STATUS_OK);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
~XnHashT()
|
|
{
|
|
// NOTE: we don't want to delete LAST_BIN (it points to the m_lastBin member)
|
|
for (XnUInt32 i = 0; i < LAST_BIN; ++i)
|
|
{
|
|
if (m_apBins[i] != NULL)
|
|
{
|
|
XN_DELETE(m_apBins[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An iterator to the first entry of the list (non-const version)
|
|
*/
|
|
Iterator Begin()
|
|
{
|
|
return Iterator(m_apBins, m_nMinBin, m_apBins[m_nMinBin]->Begin());
|
|
}
|
|
|
|
/**
|
|
* An iterator to the first entry of the list (const version)
|
|
*/
|
|
ConstIterator Begin() const
|
|
{
|
|
return ConstIterator(m_apBins, m_nMinBin, m_apBins[m_nMinBin]->Begin());
|
|
}
|
|
|
|
/**
|
|
* An iterator 1to the end of the list (non-const version). The position is invalid.
|
|
*/
|
|
Iterator End()
|
|
{
|
|
return Iterator(m_apBins, LAST_BIN, m_apBins[LAST_BIN]->Begin());
|
|
}
|
|
|
|
/**
|
|
* An iterator to the end of the list (const version). The position is invalid.
|
|
*/
|
|
ConstIterator End() const
|
|
{
|
|
return ConstIterator(m_apBins, LAST_BIN, m_apBins[LAST_BIN]->Begin());
|
|
}
|
|
|
|
/**
|
|
* Set a new key-value entry. If key exists, will replace value.
|
|
*
|
|
* @param key [in] The key to which to associate the value
|
|
* @param value [in] The value to add to the XnHash
|
|
*/
|
|
XnStatus Set(const TKey& key, const TValue& value)
|
|
{
|
|
XnHashCode nHash = TKeyManager::Hash(key);
|
|
|
|
// check if bin exists
|
|
if (m_apBins[nHash] == NULL)
|
|
{
|
|
// create it
|
|
XN_VALIDATE_NEW(m_apBins[nHash], TPairList);
|
|
|
|
if (nHash < m_nMinBin)
|
|
{
|
|
m_nMinBin = nHash;
|
|
}
|
|
}
|
|
|
|
// now check if key is already in the bin
|
|
for (typename TPairList::Iterator it = m_apBins[nHash]->Begin(); it != m_apBins[nHash]->End(); ++it)
|
|
{
|
|
if (TKeyManager::Compare(it->Key(), key) == 0)
|
|
{
|
|
// replace it
|
|
it->Value() = value;
|
|
return (XN_STATUS_OK);
|
|
}
|
|
}
|
|
|
|
// if we got here, key is not in bin. Add it.
|
|
return m_apBins[nHash]->AddLast(TPair(key, value));
|
|
}
|
|
|
|
/**
|
|
* Get an iterator pointing to the pair in the hash (const version).
|
|
*
|
|
* @param key [in] The searched key
|
|
*
|
|
* @return End() if value doesn't exist
|
|
*/
|
|
ConstIterator Find(TKey const& key) const
|
|
{
|
|
XnUInt32 nBin = LAST_BIN;
|
|
typename TPairList::ConstIterator it;
|
|
if (TRUE == Find(key, nBin, it))
|
|
{
|
|
return ConstIterator(m_apBins, nBin, it);
|
|
}
|
|
else
|
|
{
|
|
return End();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get an iterator pointing to the pair in the hash.
|
|
*
|
|
* @param key [in] The searched key
|
|
*
|
|
* @return End() if value doesn't exist
|
|
*/
|
|
Iterator Find(TKey const& key)
|
|
{
|
|
XnUInt32 nBin = LAST_BIN;
|
|
typename TPairList::Iterator it;
|
|
if (TRUE == Find(key, nBin, it))
|
|
{
|
|
return Iterator(m_apBins, nBin, it);
|
|
}
|
|
else
|
|
{
|
|
return End();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get an iterator pointing to the pair in the hash (const version).
|
|
*
|
|
* @param key [in] The searched key
|
|
* @param it [out] An iterator to the entry in the hash.
|
|
*
|
|
* @return XN_STATUS_NO_MATCH if value doesn't exist
|
|
*/
|
|
XnStatus Find(TKey const& key, ConstIterator& it) const
|
|
{
|
|
it = Find(key);
|
|
return (it == End() ? XN_STATUS_NO_MATCH : XN_STATUS_OK);
|
|
}
|
|
|
|
/**
|
|
* Get an iterator pointing to the pair in the hash (const version).
|
|
*
|
|
* @param key [in] The searched key
|
|
* @param it [out] An iterator to the entry in the hash.
|
|
*
|
|
* @return XN_STATUS_NO_MATCH if value doesn't exist
|
|
*/
|
|
XnStatus Find(TKey const& key, Iterator& it)
|
|
{
|
|
it = Find(key);
|
|
return (it == End() ? XN_STATUS_NO_MATCH : XN_STATUS_OK);
|
|
}
|
|
|
|
/**
|
|
* Get the value associated with the supplied key
|
|
*
|
|
* @param key [in] The key of the entry
|
|
* @param value [out] The retrieved value
|
|
*
|
|
* @return XN_STATUS_NO_MATCH if no such key exists
|
|
*/
|
|
XnStatus Get(TKey const& key, TValue& value) const
|
|
{
|
|
ConstIterator it = Find(key);
|
|
if (it == End())
|
|
{
|
|
return XN_STATUS_NO_MATCH;
|
|
}
|
|
else
|
|
{
|
|
value = it->Value();
|
|
return XN_STATUS_OK;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a pointer to the value associated with the supplied key
|
|
*
|
|
* @param key [in] The key of the entry
|
|
* @param pValue [out] A const pointer to the value that is stored in the hash.
|
|
*
|
|
* @return XN_STATUS_NO_MATCH if no such key exists
|
|
*/
|
|
XnStatus Get(TKey const& key, TValue const*& pValue) const
|
|
{
|
|
ConstIterator it = Find(key);
|
|
if (it == End())
|
|
{
|
|
return XN_STATUS_NO_MATCH;
|
|
}
|
|
else
|
|
{
|
|
pValue = &it->Value();
|
|
return XN_STATUS_OK;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the value associated with the supplied key
|
|
*
|
|
* @param key [in] The key of the entry
|
|
* @param value [out] The retrieved value
|
|
*
|
|
* @return XN_STATUS_NO_MATCH if no such key exists
|
|
*/
|
|
XnStatus Get(TKey const& key, TValue& value)
|
|
{
|
|
Iterator it = Find(key);
|
|
if (it == End())
|
|
{
|
|
return XN_STATUS_NO_MATCH;
|
|
}
|
|
else
|
|
{
|
|
value = it->Value();
|
|
return XN_STATUS_OK;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a pointer to the value associated with the supplied key
|
|
*
|
|
* @param key [in] The key of the entry
|
|
* @param pValue [out] A pointer to the value that is stored in the hash
|
|
*
|
|
* @return XN_STATUS_NO_MATCH if no such key exists
|
|
*/
|
|
XnStatus Get(TKey const& key, TValue*& pValue)
|
|
{
|
|
Iterator it = Find(key);
|
|
if (it == End())
|
|
{
|
|
return XN_STATUS_NO_MATCH;
|
|
}
|
|
else
|
|
{
|
|
pValue = &it->Value();
|
|
return XN_STATUS_OK;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets a reference to the value of a specific key. If this key is not in the hash, it will be added.
|
|
*
|
|
* @param key [in] The key of the entry.
|
|
*/
|
|
TValue& operator[](TKey const& key)
|
|
{
|
|
XnStatus nRetVal = XN_STATUS_OK;
|
|
Iterator it = Find(key);
|
|
if (it == End())
|
|
{
|
|
nRetVal = Set(key, TValue());
|
|
XN_ASSERT(nRetVal == XN_STATUS_OK);
|
|
|
|
it = Find(key);
|
|
XN_ASSERT(it != End());
|
|
}
|
|
|
|
return it->Value();
|
|
}
|
|
|
|
XnStatus Remove(ConstIterator it)
|
|
{
|
|
// Verify iterator is valid
|
|
if (it == End())
|
|
{
|
|
XN_ASSERT(FALSE);
|
|
return XN_STATUS_ILLEGAL_POSITION;
|
|
}
|
|
|
|
XN_ASSERT(m_apBins == it.m_ppBins);
|
|
XN_ASSERT(m_apBins[it.m_nCurrBin] != NULL);
|
|
|
|
return m_apBins[it.m_nCurrBin]->Remove(it.m_currIt);
|
|
}
|
|
|
|
XnStatus Remove(TKey const& key)
|
|
{
|
|
ConstIterator it = Find(key);
|
|
if (it != End())
|
|
{
|
|
return Remove(it);
|
|
}
|
|
else
|
|
{
|
|
return XN_STATUS_NO_MATCH;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove all entries from the XnHash.
|
|
*/
|
|
XnStatus Clear()
|
|
{
|
|
while (Begin() != End())
|
|
Remove(Begin());
|
|
|
|
return XN_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* Checks if hash is empty.
|
|
*/
|
|
XnBool IsEmpty() const
|
|
{
|
|
return (Begin() == End());
|
|
}
|
|
|
|
/**
|
|
* Gets the number of entries in the hash.
|
|
*/
|
|
XnUInt32 Size() const
|
|
{
|
|
XnUInt32 nSize = 0;
|
|
for (ConstIterator iter = Begin(); iter != End(); ++iter, ++nSize)
|
|
;
|
|
|
|
return nSize;
|
|
}
|
|
|
|
private:
|
|
XnBool Find(TKey const& key, XnUInt32& nBin, typename TPairList::ConstIterator& currIt) const
|
|
{
|
|
XnHashCode nHash = TKeyManager::Hash(key);
|
|
|
|
if (m_apBins[nHash] != NULL)
|
|
{
|
|
// look for value in bin
|
|
for (typename TPairList::ConstIterator it = m_apBins[nHash]->Begin(); it != m_apBins[nHash]->End(); ++it)
|
|
{
|
|
if (TKeyManager::Compare(it->Key(), key) == 0)
|
|
{
|
|
nBin = nHash;
|
|
currIt = it;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if we got here, key wasn't found
|
|
return FALSE;
|
|
}
|
|
|
|
void Init()
|
|
{
|
|
xnOSMemSet(m_apBins, 0, sizeof(m_apBins));
|
|
m_apBins[LAST_BIN] = &m_lastBin;
|
|
m_nMinBin = LAST_BIN;
|
|
}
|
|
|
|
TPairList* m_apBins[NUM_BINS];
|
|
TPairList m_lastBin;
|
|
XnUInt32 m_nMinBin;
|
|
};
|
|
|
|
|
|
|
|
#endif // _XN_HASH_T_H_
|