#ifndef _XN_HASH_T_H_ #define _XN_HASH_T_H_ //--------------------------------------------------------------------------- // Includes //--------------------------------------------------------------------------- #include #include //--------------------------------------------------------------------------- // Defines //--------------------------------------------------------------------------- typedef XnUInt8 XnHashCode; //--------------------------------------------------------------------------- // Code //--------------------------------------------------------------------------- template 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 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 TAlloc = XnLinkedNodeDefaultAllocatorT > > class XnHashT { public: typedef XnKeyValuePair TPair; typedef XnListT 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(*this->m_currIt); } /** * Get a pointer to the value of the current object */ inline TPair* operator->() const { return const_cast(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_