First public contribution.
1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32/euser/us_htab.cpp
19 #include <e32hashtab.h>
21 const TUint KDefaultIndexBits = 4;
22 const TUint KMaxIndexBits = 28;
24 extern TUint32 DefaultIntegerHash(const TAny*);
25 extern TUint32 DefaultStringHash(const TUint8*, TInt);
26 extern TUint32 DefaultWStringHash(const TUint16*, TInt);
28 #define _DEBUG_HASH_TABLE
30 #undef _DEBUG_HASH_TABLE
33 #define __PANIC(x) Panic(x)
35 EXPORT_C RHashTableBase::RHashTableBase(TGeneralHashFunction32 aHash, TGeneralIdentityRelation aId, TInt aElementSize, TInt aKeyOffset)
38 iIndexBits(TUint8(KDefaultIndexBits)),
46 __ASSERT_ALWAYS(aHash!=NULL, __PANIC(EHashTableNoHashFunc));
47 __ASSERT_ALWAYS(aId!=NULL, __PANIC(EHashTableNoIdentityRelation));
48 __ASSERT_ALWAYS(aElementSize>0, __PANIC(EHashTableBadElementSize));
49 __ASSERT_ALWAYS(aKeyOffset==0 || TUint(aKeyOffset-4)<(TUint)Min(252,aElementSize-4), __PANIC(EHashTableBadKeyOffset));
50 iElementSize = aElementSize;
51 iKeyOffset = (TUint8)aKeyOffset; // 0 means ptr at offset 4
56 void RHashTableBase::SetThresholds()
58 TUint32 max = 1u << iIndexBits;
59 if (iIndexBits == KMaxIndexBits)
60 iUpperThreshold = KMaxTUint;
62 iUpperThreshold = (max>>1) + (max>>2); // 3/4 of max
63 if (iIndexBits == KDefaultIndexBits)
66 iLowerThreshold = max >> 2; // 1/4 of max
68 // clean table if <1/8 of entries empty
69 iCleanThreshold = max>>3;
72 EXPORT_C void RHashTableBase::Close()
74 User::Free(iElements);
75 new (this) RHashTableBase(iHashFunc, iIdFunc, iElementSize, iKeyOffset);
78 EXPORT_C TInt RHashTableBase::Count() const
83 EXPORT_C TAny* RHashTableBase::Find(const TAny* aKey, TInt aOffset) const
87 TUint32 hash = (*iHashFunc)(aKey);
88 TUint32 ix = hash >> (32 - iIndexBits); // top bits of hash used as initial index
89 hash = (hash &~ EStateMask) | iGeneration;
90 TUint32 mask = (1u << iIndexBits) - 1; // iIndexBits 1's
91 TUint32 step = (hash >> 1) & mask; // iIndexBits-1 LSBs of hash followed by 1
94 const SElement* e = ElementC(ix);
95 if (e->iHash==hash && (*iIdFunc)(aKey, GetKey(e)))
98 return ((TUint8*)e) + aOffset;
99 return *(TAny**)((TUint8*)e - aOffset);
103 ix = (ix + step) & mask;
108 EXPORT_C TAny* RHashTableBase::FindL(const TAny* aKey, TInt aOffset) const
110 TAny* p = Find(aKey, aOffset);
112 User::Leave(KErrNotFound);
116 TInt RHashTableBase::Insert(const TAny* aKey, TAny*& aElement)
119 TUint32 max = 1u << iIndexBits;
122 iElements = User::AllocZ(max * iElementSize);
127 else if (iCount > iUpperThreshold)
129 r = ExpandTable(iIndexBits+1);
131 r = KErrNone; // doesn't matter if expand fails unless there is only one empty slot left
132 max = 1u << iIndexBits;
134 else if (iEmptyCount < iCleanThreshold)
135 ReformTable(iIndexBits);
137 TUint32 hash = (*iHashFunc)(aKey);
138 TUint32 ix = hash >> (32 - iIndexBits);
139 TUint32 mask = max - 1;
140 hash = (hash &~ EStateMask) | iGeneration;
141 TUint32 step = (hash >> 1) & mask; // iIndexBits-1 LSBs of hash followed by 1
154 else if (e->iHash==hash && (*iIdFunc)(aKey, GetKey(e)))
157 return KErrNone; // duplicate so always succeed
159 ix = (ix + step) & mask;
162 e = d; // if we can reuse a deleted slot, always succeed
166 return r; // new slot needed - if we failed to expand, fail the request here
175 EXPORT_C TInt RHashTableBase::PtrInsert(const TAny* aKey, const TAny* aValue)
178 TInt r = Insert(aKey, (TAny*&)e);
182 if (iElementSize>=12)
188 EXPORT_C void RHashTableBase::PtrInsertL(const TAny* aKey, const TAny* aValue)
191 User::LeaveIfError(Insert(aKey, (TAny*&)e));
193 if (iElementSize>=12)
197 EXPORT_C TInt RHashTableBase::ValueInsert(const TAny* aKey, TInt aKeySize, const TAny* aValue, TInt aValueOffset, TInt aValueSize)
200 TInt r = Insert(aKey, (TAny*&)e);
203 memcpy(e+iKeyOffset, aKey, aKeySize);
205 memcpy(e+aValueOffset, aValue, aValueSize);
210 EXPORT_C void RHashTableBase::ValueInsertL(const TAny* aKey, TInt aKeySize, const TAny* aValue, TInt aValueOffset, TInt aValueSize)
213 User::LeaveIfError(Insert(aKey, (TAny*&)e));
214 memcpy(e+iKeyOffset, aKey, aKeySize);
216 memcpy(e+aValueOffset, aValue, aValueSize);
219 EXPORT_C TInt RHashTableBase::Remove(const TAny* aKey)
221 SElement* e = (SElement*)Find(aKey);
230 if (iCount < iLowerThreshold)
235 void RHashTableBase::ReformTable(TUint aNewIndexBits)
239 TUint32 max = 1u << iIndexBits;
240 TUint32 newmax = 1u << aNewIndexBits;
241 TUint32 newmask = newmax - 1;
243 TUint32 newsh = 32 - aNewIndexBits;
244 iGeneration ^= 1; // change generation so we know which entries have been updated
245 for (; ix < max; ++ix)
247 SElement* e = Element(ix);
249 continue; // skip empty entries
252 e->SetEmpty(); // mark deleted entries as empty
255 if ((e->iHash & EStateMask) == iGeneration) // entry has been processed so leave it alone
257 TUint32 pos = e->iHash >> newsh;
260 e->iHash ^= 1; // entry is in first position for its hash so leave it there
263 TUint32 step = (e->iHash >> 1) & newmask;
266 SElement* d = Element(pos);
267 if (d->IsEmptyOrDeleted())
269 memcpy(d, e, iElementSize);
270 d->iHash &= ~EStateMask;
271 d->iHash |= iGeneration; // mark it as processed
272 e->SetEmpty(); // remove old entry
275 if ((d->iHash & EStateMask) != iGeneration)
279 e->iHash ^= 1; // entry is already in correct position so leave it there
282 if ((d->iHash >> newsh) == pos)
284 // candidate for replacement is in correct position so leave it and look elsewhere
289 Mem::Swap(d, e, iElementSize); // switch entries
290 d->iHash ^= 1; // mark entry as processed
291 --ix; // process current position again
295 pos = (pos + step) & newmask;
298 iIndexBits = (TUint8)aNewIndexBits;
299 iEmptyCount = newmax - iCount;
301 #ifdef _DEBUG_HASH_TABLE
306 #ifdef _DEBUG_HASH_TABLE
307 void RHashTableBase::VerifyReform()
310 ConsistencyCheck(&dcount);
311 __ASSERT_ALWAYS(dcount==0, __PANIC(EHashTableDeletedEntryAfterReform));
315 EXPORT_C void RHashTableBase::ConsistencyCheck(TUint32* aDeleted, TUint32* aComparisons, TUint32 aChainLimit, TUint32* aChainInfo)
317 #ifdef _DEBUG_HASH_TABLE
321 TUint32 max = 1u << iIndexBits;
322 TUint32 mask = max - 1;
323 TUint32 sh = 32 - iIndexBits;
327 memclr(aChainInfo, aChainLimit*sizeof(TUint32));
330 for (ix = 0; ix < max; ++ix)
332 SElement* e = Element(ix);
344 __ASSERT_ALWAYS((e->iHash & EStateMask) == iGeneration, __PANIC(EHashTableBadGeneration));
345 TUint32 hash = (*iHashFunc)(GetKey(e));
346 hash = (hash &~ EStateMask) | iGeneration;
347 __ASSERT_ALWAYS(e->iHash == hash, __PANIC(EHashTableBadHash));
349 TUint32 pos = hash >> sh;
350 TUint32 step = (hash >> 1) & mask;
362 if (!f->IsDeleted() && f->iHash==hash)
365 if (e==f || (*iIdFunc)(GetKey(e), GetKey(f)))
368 pos = (pos + step) & mask;
370 __ASSERT_ALWAYS(e==f, __PANIC(EHashTableEntryLost));
371 if (aChainInfo && cl<aChainLimit)
379 __ASSERT_ALWAYS(iCount==count, __PANIC(EHashTableCountWrong));
380 __ASSERT_ALWAYS(iEmptyCount==ecount, __PANIC(EHashTableEmptyCountWrong));
383 *aDeleted = KMaxTUint;
385 *aComparisons = KMaxTUint;
387 memclr(aChainInfo, aChainLimit*sizeof(TUint32));
391 void RHashTableBase::ShrinkTable()
393 ReformTable(iIndexBits - 1);
394 TUint32 max = 1u << iIndexBits;
395 iElements = User::ReAlloc(iElements, max * iElementSize);
398 TInt RHashTableBase::ExpandTable(TInt aNewIndexBits)
400 TUint32 newmax = 1u << aNewIndexBits;
403 iElements = User::AllocZ(newmax * iElementSize);
406 iIndexBits = (TUint8)aNewIndexBits;
407 iEmptyCount = newmax;
411 TUint32 max = 1u << iIndexBits;
412 TAny* p = User::ReAlloc(iElements, newmax * iElementSize);
416 memclr(Element(max), (newmax-max)*iElementSize);
417 ReformTable(aNewIndexBits);
421 EXPORT_C TInt RHashTableBase::Reserve(TInt aCount)
423 __ASSERT_ALWAYS((TUint)aCount<0x40000000u, __PANIC(EHashTableBadReserveCount));
424 TInt new_ixb = iIndexBits;
425 TUint grow_threshold = iUpperThreshold;
426 while (TUint(aCount) > grow_threshold)
428 grow_threshold <<= 1;
431 // Expand the table if it isn't large enough to fit aCount elements in it
432 // or if the table hasn't yet been created, create it with ExpandTable
433 if (new_ixb > TInt(iIndexBits) || !iElements)
435 return ExpandTable(new_ixb);
440 EXPORT_C void RHashTableBase::ReserveL(TInt aCount)
442 User::LeaveIfError(Reserve(aCount));
445 EXPORT_C THashTableIterBase::THashTableIterBase(const RHashTableBase& aTable)
446 : iTbl(aTable), iIndex(-1), iPad1(0), iPad2(0)
450 EXPORT_C void THashTableIterBase::Reset()
455 EXPORT_C const TAny* THashTableIterBase::Next(TInt aOffset)
457 TInt max = 1 << iTbl.iIndexBits;
460 __ASSERT_DEBUG(iIndex>=-1 && iIndex<=max, __PANIC(EHashTableIterNextBadIndex));
463 for(; iIndex < max; ++iIndex)
465 const RHashTableBase::SElement* e = iTbl.ElementC(iIndex);
466 if (!e->IsEmptyOrDeleted())
469 return (TUint8*)e + aOffset;
470 return *(const TAny**)((TUint8*)e - aOffset);
476 EXPORT_C const TAny* THashTableIterBase::Current(TInt aOffset) const
478 TInt max = 1 << iTbl.iIndexBits;
479 if (!iTbl.iElements || iIndex<0 || iIndex>=max)
481 const RHashTableBase::SElement* e = iTbl.ElementC(iIndex);
482 __ASSERT_DEBUG(!e->IsEmptyOrDeleted(), __PANIC(EHashTableIterCurrentBadIndex));
484 return (TUint8*)e + aOffset;
485 return *(const TAny**)((TUint8*)e - aOffset);
488 EXPORT_C void THashTableIterBase::RemoveCurrent()
490 TInt max = 1 << iTbl.iIndexBits;
491 if (!iTbl.iElements || iIndex<0 || iIndex>=max)
493 RHashTableBase& tbl = (RHashTableBase&)iTbl;
494 RHashTableBase::SElement* e = tbl.Element(iIndex);
495 __ASSERT_DEBUG(!e->IsEmptyOrDeleted(), __PANIC(EHashTableIterCurrentBadIndex));
497 // mark entry as deleted but don't shrink the array since that will mess up the iteration
499 if (--tbl.iCount == 0)
501 memclr(tbl.iElements, max * tbl.iElementSize);
502 tbl.iEmptyCount = max;
503 tbl.iGeneration = RHashTableBase::EGen0;
511 Calculate a 32 bit hash from an 8 bit descriptor.
513 @param aDes The descriptor to be hashed.
514 @return The calculated 32 bit hash value.
516 EXPORT_C TUint32 DefaultHash::Des8(const TDesC8& aDes)
518 return DefaultStringHash(aDes.Ptr(), aDes.Length());
526 Calculate a 32 bit hash from a 16 bit descriptor.
528 @param aDes The descriptor to be hashed.
529 @return The calculated 32 bit hash value.
531 EXPORT_C TUint32 DefaultHash::Des16(const TDesC16& aDes)
533 return DefaultWStringHash(aDes.Ptr(), aDes.Size());
541 Calculate a 32 bit hash from a TInt pointer.
543 @param aPtr The TInt pointer to be hashed.
544 @return The calculated 32 bit hash value.
546 EXPORT_C TUint32 DefaultHash::IntegerPtr(TInt* const& aPtr)
548 return Integer((TInt)aPtr);
555 Calculate a 32 bit hash from a TDesC8 pointer.
557 @param aPtr The TDesC8 pointer to be hashed.
558 @return The calculated 32 bit hash value.
560 EXPORT_C TUint32 DefaultHash::Des8Ptr(TDesC8* const& aPtr)
562 return Integer((TInt)aPtr);
569 Calculate a 32 bit hash from a TDesC16 pointer.
571 @param aPtr The TDesC16 pointer to be hashed.
572 @return The calculated 32 bit hash value.
574 EXPORT_C TUint32 DefaultHash::Des16Ptr(TDesC16* const& aPtr)
576 return Integer((TInt)aPtr);
583 Compare two integers for equality.
585 @param aA The first integer to be compared
586 @param aB The second integer to be compared
587 @return ETrue if the arguments are equal, EFalse otherwise.
589 EXPORT_C TBool DefaultIdentity::Integer(const TInt& aA, const TInt& aB)
599 Compare two 8 bit descriptors for exact binary equality.
601 @param aA The first integer to be compared
602 @param aB The second integer to be compared
603 @return ETrue if the arguments are identical, EFalse otherwise.
605 EXPORT_C TBool DefaultIdentity::Des8(const TDesC8& aA, const TDesC8& aB)
615 Compare two 16 bit descriptors for exact binary equality.
617 @param aA The first integer to be compared
618 @param aB The second integer to be compared
619 @return ETrue if the arguments are identical, EFalse otherwise.
621 EXPORT_C TBool DefaultIdentity::Des16(const TDesC16& aA, const TDesC16& aB)
630 Compare two TInt pointers for equality.
632 @param aA The first pointer to be compared
633 @param aB The second pointer to be compared
634 @return ETrue if the arguments are equal, EFalse otherwise.
636 EXPORT_C TBool DefaultIdentity::IntegerPtr(TInt* const& aA,TInt* const& aB)
645 Compare two TDesC8 pointers for equality.
647 @param aA The first pointer to be compared
648 @param aB The second pointer to be compared
649 @return ETrue if the arguments are equal, EFalse otherwise.
651 EXPORT_C TBool DefaultIdentity::Des8Ptr(TDesC8* const& aA,TDesC8* const& aB)
660 Compare two TDesC16 pointers for equality.
662 @param aA The first pointer to be compared
663 @param aB The second pointer to be compared
664 @return ETrue if the arguments are equal, EFalse otherwise.
666 EXPORT_C TBool DefaultIdentity::Des16Ptr(TDesC16* const& aA,TDesC16* const& aB)