/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. 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 3 of the License, or (at your option) 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, see . Additional permissions under GNU GPL version 3 section 7 If you modify this Program, or any covered work, by linking or combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK (or a modified version of those libraries), containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the licensors of this Program grant you additional permission to convey the resulting work. Corresponding Source for a non-source form of such a combination shall include the source code for the parts of OpenSSL and IJG JPEG Library used as well as that of the covered work. You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ /***************************************************************************** * * $/Plasma20/Sources/Plasma/NucleusLib/pnUtils/Private/pnUtHash.h * ***/ #ifdef PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNUTILS_PRIVATE_PNUTHASH_H #error "Header $/Plasma20/Sources/Plasma/NucleusLib/pnUtils/Private/pnUtHash.h included more than once" #endif #define PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNUTILS_PRIVATE_PNUTHASH_H /**************************************************************************** * * Macros * ***/ // Define a field inside an object that is used to link it into a hash table #define HASHLINK(object) THashLink< object > // Define a POINTER to a hash table, not a hash table #define HASHTABLE(object,key) THashTable< object, key > // Define a hash table: // - starts with kSlotMinCount rows // - can grow to kDefaultSlotMaxCount rows // (hash table grows when a row contains more than kGrowOnListSize entries #define HASHTABLEDECL(object,key,link) THashTableDecl< object, key, offsetof(object,link), 0 > // Define a hash table in situations when a forward reference prevents use of HASHTABLEDECL // - Size characteristics are identical to HASHTABLEDECL #define HASHTABLEDYN(object,key) THashTableDyn< object, key > // Define a hash table with: // - starts with // - row table never grows #define HASHTABLEDECLSIZE(object,key,link,size) THashTableDecl /**************************************************************************** * * Forward declarations * ***/ template class THashLink; template class TBaseHashTable; /**************************************************************************** * * THashLink * ***/ template class THashLink { friend class TBaseHashTable; private: unsigned m_hash; LINK(T) m_linkToFull; LINK(T) m_linkToSlot; public: inline bool IsLinked () const; inline T * Next (); inline const T * Next () const; inline T * Prev (); inline const T * Prev () const; inline void Unlink (); }; //=========================================================================== template bool THashLink::IsLinked () const { return m_linkToFull.IsLinked(); } //=========================================================================== template T * THashLink::Next () { return m_linkToFull.Next(); } //=========================================================================== template const T * THashLink::Next () const { return m_linkToFull.Next(); } //=========================================================================== template T * THashLink::Prev () { return m_linkToFull.Prev(); } //=========================================================================== template const T * THashLink::Prev () const { return m_linkToFull.Prev(); } //=========================================================================== template void THashLink::Unlink () { m_linkToFull.Unlink(); m_linkToSlot.Unlink(); } /**************************************************************************** * * TBaseHashTable * ***/ template class TBaseHashTable { private: enum { kSlotMinCount = 8 }; enum { kDefaultSlotMaxCount = 1024 }; enum { kGrowOnListSize = 5 }; LIST(T) m_fullList; int m_linkOffset; FARRAYOBJ(LIST(T)) m_slotListArray; unsigned m_slotMask; // always set to a power of two minus one unsigned m_slotMaxCount; inline bool CheckGrowTable (LIST(T) * slotList); inline const THashLink & GetLink (const T * object) const; inline THashLink & GetLink (T * object); inline void SetSlotCount (unsigned count); protected: inline unsigned GetHash (const T * object) const; inline unsigned & GetHash (T * object); inline const LIST(T) & GetSlotList (unsigned hash) const; inline LIST(T) & GetSlotList (unsigned hash); inline void SetLinkOffset (int linkOffset, unsigned maxSize); inline void SetSlotMaxCount (unsigned count); public: inline TBaseHashTable (); inline TBaseHashTable (const TBaseHashTable & source); inline TBaseHashTable & operator= (const TBaseHashTable & source); inline void Add (T * object, unsigned hash); inline void Clear (); inline void Delete (T * object); inline T * Head (); inline const T * Head () const; inline T * Next (const T * object); inline const T * Next (const T * object) const; inline void Order (T * linkedObject, ELinkType linkType, T * existingObject); inline T * Prev (const T * object); inline const T * Prev (const T * object) const; inline T * Tail (); inline const T * Tail () const; inline void Unlink (T * object); }; //=========================================================================== template TBaseHashTable::TBaseHashTable () { m_slotMask = 0; m_slotMaxCount = kDefaultSlotMaxCount; // more initialization done during call to SetLinkOffset() } //=========================================================================== template TBaseHashTable::TBaseHashTable (const TBaseHashTable & source) { REF(source); #ifdef HS_DEBUGGING FATAL("No copy constructor"); #endif TBaseHashTable(); } //=========================================================================== template TBaseHashTable & TBaseHashTable::operator= (const TBaseHashTable & source) { REF(source); #ifdef HS_DEBUGGING FATAL("No assignment operator"); #endif return *this; } //=========================================================================== template void TBaseHashTable::Add (T * object, unsigned hash) { GetHash(object) = hash; LIST(T) * list = &GetSlotList(hash); if (CheckGrowTable(list)) list = &GetSlotList(hash); m_fullList.Link(object); list->Link(object); } //=========================================================================== template bool TBaseHashTable::CheckGrowTable (LIST(T) * list) { unsigned nextCount = (m_slotMask + 1) * 2; if (nextCount > m_slotMaxCount) return false; unsigned listCount = 0; for (T * curr = list->Head(); curr; curr = list->Next(curr)) ++listCount; if (listCount + 1 < kGrowOnListSize) return false; SetSlotCount(nextCount); return true; } //=========================================================================== template void TBaseHashTable::Clear () { m_fullList.Clear(); } //=========================================================================== template void TBaseHashTable::Delete (T * object) { DEL(object); } //=========================================================================== template unsigned TBaseHashTable::GetHash (const T * object) const { return GetLink(object).m_hash; } //=========================================================================== template unsigned & TBaseHashTable::GetHash (T * object) { return GetLink(object).m_hash; } //=========================================================================== template const THashLink & TBaseHashTable::GetLink (const T * object) const { return *(const THashLink *)((const byte *)object + m_linkOffset); } //=========================================================================== template THashLink & TBaseHashTable::GetLink (T * object) { return *(THashLink *)((byte *)object + m_linkOffset); } //=========================================================================== template const LIST(T) & TBaseHashTable::GetSlotList (unsigned hash) const { return m_slotListArray[hash & m_slotMask]; } //=========================================================================== template LIST(T) & TBaseHashTable::GetSlotList (unsigned hash) { return m_slotListArray[hash & m_slotMask]; } //=========================================================================== template T * TBaseHashTable::Head () { return m_fullList.Head(); } //=========================================================================== template const T * TBaseHashTable::Head () const { return m_fullList.Head(); } //=========================================================================== template T * TBaseHashTable::Next (const T * object) { return m_fullList.Next(object); } //=========================================================================== template const T * TBaseHashTable::Next (const T * object) const { return m_fullList.Next(object); } //=========================================================================== template void TBaseHashTable::Order (T * linkedObject, ELinkType linkType, T * existingObject) { THashLink & link = GetLink(linkedObject); REF(link); ASSERT(link.m_linkToFull.IsLinked()); m_fullList.Link(linkedObject, linkType, existingObject); } //=========================================================================== template T * TBaseHashTable::Prev (const T * object) { return m_fullList.Prev(object); } //=========================================================================== template const T * TBaseHashTable::Prev (const T * object) const { return m_fullList.Prev(object); } //=========================================================================== template void TBaseHashTable::SetLinkOffset (int linkOffset, unsigned maxSize) { ASSERT(!m_fullList.Head()); ASSERT(!m_slotListArray.Count()); ASSERT(!m_slotMask); m_linkOffset = linkOffset; m_fullList.SetLinkOffset(m_linkOffset + offsetof(THashLink, m_linkToFull)); if (!m_slotMask) SetSlotCount(max(kSlotMinCount, MathNextPow2(maxSize))); } //=========================================================================== template void TBaseHashTable::SetSlotCount (unsigned count) { ASSERT(!(count & (count - 1))); // power of two ASSERT(count >= 2); if (count == m_slotMask + 1) return; m_slotMask = count - 1; m_slotListArray.ZeroCount(); m_slotListArray.SetCount(count); for (unsigned loop = 0; loop < count; ++loop) m_slotListArray[loop].SetLinkOffset(m_linkOffset + offsetof(THashLink, m_linkToSlot)); for (T * curr = Head(); curr; curr = Next(curr)) GetSlotList(GetHash(curr)).Link(curr); } //=========================================================================== template void TBaseHashTable::SetSlotMaxCount (unsigned count) { if (count) m_slotMaxCount = max(kSlotMinCount, count); } //=========================================================================== template T * TBaseHashTable::Tail () { return m_fullList.Tail(); } //=========================================================================== template const T * TBaseHashTable::Tail () const { return m_fullList.Tail(); } //=========================================================================== template void TBaseHashTable::Unlink (T * object) { THashLink & link = GetLink(object); link.Unlink(); } /**************************************************************************** * * THashTable * ***/ template class THashTable : public TBaseHashTable { public: inline void Add (T * object); inline void Add (T * object, unsigned hash); inline T * Find (const K & key); inline T * FindNext (const K & key, T * object); inline const T * Find (const K & key) const; inline const T * FindNext (const K & key, const T * object) const; inline T * Unduplicate (T * object, const K & key); }; //=========================================================================== template inline void THashTable::Add (T * object) { TBaseHashTable::Add(object, object->GetHash()); } //=========================================================================== template inline void THashTable::Add (T * object, unsigned hash) { TBaseHashTable::Add(object, hash); } //=========================================================================== template T * THashTable::Find (const K & key) { return (T *)((const THashTable *)this)->Find(key); } //=========================================================================== template T * THashTable::FindNext (const K & key, T * object) { return (T *)((const THashTable *)this)->FindNext(key, object); } //=========================================================================== template const T * THashTable::Find (const K & key) const { unsigned hash = key.GetHash(); const LIST(T) & slotList = GetSlotList(hash); for (const T * curr = slotList.Head(); curr; curr = slotList.Next(curr)) if ((GetHash(curr) == hash) && (*curr == key)) return curr; return nil; } //=========================================================================== template const T * THashTable::FindNext (const K & key, const T * object) const { unsigned hash = key.GetHash(); const LIST(T) & slotList = GetSlotList(hash); for (const T * curr = slotList.Next(object); curr; curr = slotList.Next(curr)) if ((GetHash(curr) == hash) && (*curr == key)) return curr; return nil; } //=========================================================================== template T * THashTable::Unduplicate (T * object, const K & key) { T * existing = Find(key); if (existing) { DEL(object); return existing; } else { Add(object); return object; } } /**************************************************************************** * * THashTableDecl * ***/ template class THashTableDecl : public THashTable { public: inline THashTableDecl (); }; //=========================================================================== template THashTableDecl::THashTableDecl () { SetLinkOffset(linkOffset, maxSize); SetSlotMaxCount(maxSize); } /**************************************************************************** * * THashTableDyn * ***/ template class THashTableDyn : public THashTable { public: void Initialize (int linkOffset, unsigned maxSize = 0); }; //=========================================================================== template void THashTableDyn::Initialize (int linkOffset, unsigned maxSize) { SetLinkOffset(linkOffset, maxSize); SetSlotMaxCount(maxSize); } /**************************************************************************** * * THashKeyVal * ***/ template class THashKeyVal { public: THashKeyVal () : m_value(0) { } THashKeyVal (const T & value) : m_value(value) { } bool operator== (const THashKeyVal & rhs) const { return m_value == rhs.m_value; } unsigned GetHash () const { CHashValue hash(&m_value, sizeof(m_value)); return hash.GetHash(); } const T & GetValue () const { return m_value; } void SetValue (const T & value) { m_value = value; } protected: T m_value; }; /**************************************************************************** * * CHashKeyStrPtr / CHashKeyStrPtrI * ***/ //=========================================================================== template class THashKeyStrBase { public: const C * GetString () const { return m_str; } protected: THashKeyStrBase () : m_str(nil) { } THashKeyStrBase (const C str[]) : m_str(str) { } virtual ~THashKeyStrBase () { } const C * m_str; }; //=========================================================================== template class THashKeyStrCmp : public THashKeyStrBase { public: bool operator== (const THashKeyStrCmp & rhs) const { return StrCmp(m_str, rhs.m_str) == 0; } unsigned GetHash () const { return StrHash(m_str); } protected: THashKeyStrCmp () { } THashKeyStrCmp (const C str[]) : THashKeyStrBase(str) { } }; //=========================================================================== template class THashKeyStrCmpI : public THashKeyStrBase { public: bool operator== (const THashKeyStrCmpI & rhs) const { return StrCmpI(m_str, rhs.m_str) == 0; } unsigned GetHash () const { return StrHashI(m_str); } protected: THashKeyStrCmpI () { } THashKeyStrCmpI (const C str[]) : THashKeyStrBase(str) { } }; /**************************************************************************** * * THashKeyStrPtr * ***/ template class THashKeyStrPtr : public T { public: THashKeyStrPtr () { } THashKeyStrPtr (const C str[]) : T(str) { } void SetString (const C str[]) { m_str = str; } }; typedef THashKeyStrPtr< wchar, THashKeyStrCmp > CHashKeyStrPtr; typedef THashKeyStrPtr< wchar, THashKeyStrCmpI > CHashKeyStrPtrI; typedef THashKeyStrPtr< char, THashKeyStrCmp > CHashKeyStrPtrChar; typedef THashKeyStrPtr< char, THashKeyStrCmpI > CHashKeyStrPtrCharI; /**************************************************************************** * * THashKeyStr * ***/ template class THashKeyStr : public T { public: THashKeyStr () { } THashKeyStr (const C str[]) { SetString(str); } THashKeyStr (const THashKeyStr &); // intentionally unimplemented THashKeyStr & operator= (const THashKeyStr &); // intentionally unimplemented ~THashKeyStr () { SetString(nil); } void SetString (const C str[]) { // deprecated if (m_str) FREE(const_cast(m_str)); if (str) m_str = StrDup(str); else m_str = nil; } }; typedef THashKeyStr< wchar, THashKeyStrCmp > CHashKeyStr; typedef THashKeyStr< wchar, THashKeyStrCmpI > CHashKeyStrI; typedef THashKeyStr< char, THashKeyStrCmp > CHashKeyStrChar; typedef THashKeyStr< char, THashKeyStrCmpI > CHashKeyStrCharI; /**************************************************************************** * * CHashValue * ***/ class CHashValue { private: static const dword s_hashTable[]; dword m_result; inline void Construct () { m_result = 0x325d1eae; } public: static dword LookupHashBits (unsigned value) { ASSERT(value < 0x100); return s_hashTable[value]; } inline CHashValue () { Construct() ; } inline CHashValue (const CHashValue & source) { m_result = source.m_result; } inline CHashValue (const void * data, unsigned bytes) { Construct(); Hash(data, bytes); } inline CHashValue & operator= (const CHashValue & source) { m_result = source.m_result; return *this; } inline bool operator== (const CHashValue & source) const { return (m_result == source.m_result); } inline dword GetHash () const { return m_result; } __forceinline void Hash (const void * data, unsigned bytes); __forceinline void Hash8 (unsigned data); __forceinline void Hash16 (unsigned data); __forceinline void Hash32 (unsigned data); }; //=========================================================================== void CHashValue::Hash (const void * data, unsigned bytes) { for (const byte * curr = (const byte *)data, * term = curr + bytes; curr != term; ++curr) Hash8(*curr); } //=========================================================================== void CHashValue::Hash8 (unsigned data) { m_result += s_hashTable[m_result >> 24] ^ (m_result >> 6) ^ s_hashTable[data & 0xff]; } //=========================================================================== void CHashValue::Hash16 (unsigned data) { Hash8(data); Hash8(data >> 8); } //=========================================================================== void CHashValue::Hash32 (unsigned data) { Hash8(data); Hash8(data >> 8); Hash8(data >> 16); Hash8(data >> 24); }