// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// e32test/buffer/t_hashtab.cpp
// 
//

#include <e32test.h>
#include <e32hashtab.h>
#include <hal.h>

#if defined(__VC32__) || defined(__CW32__)
typedef unsigned short wch;
#else
typedef wchar_t wch;
#endif


RTest test(_L("T_HASHTAB"));
TInt NanoTickPeriod;

typedef TBuf8<80> TTestName;
typedef RHashSet<TInt> TIntSet;
typedef RHashSet<TTestName> TNameSet;
typedef RPtrHashSet<TDesC8> TStringSet8;
typedef RPtrHashSet<TDesC16> TStringSet16;
typedef RPtrHashMap<TDesC8,TDesC8> TStringMap8;
typedef RPtrHashMap<TDesC16,TDesC16> TStringMap16;

#define INTSET(x)	TIntSet x
#define NAMESET(x)	TNameSet x(&HashTestName, &TestNameIdentity)
#define STRSET8(x)	TStringSet8 x
#define STRSET16(x)	TStringSet16 x
#define STRMAP8(x)	TStringMap8 x
#define STRMAP16(x)	TStringMap16 x

RPointerArray<TDesC8> DesC8Array;
RPointerArray<TDesC16> DesC16Array;

class HashTest : public RHashTableBase
	{
public:
	HashTest() : RHashTableBase(0,0,0,0) {}
	using RHashTableBase::ConsistencyCheck;
	using RHashTableBase::Count;
	};

void CCheck(RHashTableBase& aHT)
	{
	TUint32 ci[1024];
	TUint32 dc;
	TUint32 cmp;
	HashTest* h = (HashTest*)&aHT;
	h->ConsistencyCheck(&dc, &cmp, 1024, ci);
	test.Printf(_L("Count = %d, Deleted = %d, Cmp = %d\n"), h->Count(), dc, cmp);
	TInt i;
	for (i=0; i<1024; ++i)
		{
		if (ci[i])
			test.Printf(_L("%d chains of length %d\n"), ci[i], i);
		}
	}

const char* Numbers[] =
	{
	"zero",
	"one",
	"two",
	"three",
	"four",
	"five",
	"six",
	"seven",
	"eight",
	"nine",
	"ten",
	"eleven",
	"twelve",
	"thirteen",
	"fourteen",
	"fifteen",
	"sixteen",
	"seventeen",
	"eighteen",
	"nineteen",
	"twenty",
	"thirty",
	"forty",
	"fifty",
	"sixty",
	"seventy",
	"eighty",
	"ninety",
	"hundred",
	"thousand"
	};

TTestName NumberInWords(const TInt& aNum)
	{
	TInt a = aNum;
	TTestName n;
	if (a<20)
		{
		n.Copy((const TUint8*)Numbers[a]);
		return n;
		}
	if (a<100)
		{
		TInt tens = a/10;
		TInt units = a%10;
		n.Copy((const TUint8*)Numbers[tens-2+20]);
		if (units)
			{
			n.Append(' ');
			n.Append(TPtrC8((const TUint8*)Numbers[units]));
			}
		return n;
		}
	if (a<1000)
		{
		TInt h = a/100;
		n.Copy((const TUint8*)Numbers[h]);
		n.Append(' ');
		n.Append(TPtrC8((const TUint8*)Numbers[28]));
		a%=100;
		if (a)
			{
			TTestName n2(NumberInWords(a));
			n.Append(_L8(" and "));
			n+=n2;
			}
		return n;
		}
	TInt t = a/1000;
	n = NumberInWords(t);
	n.Append(' ');
	n.Append(TPtrC8((const TUint8*)Numbers[29]));
	a%=1000;
	if (a)
		{
		TTestName n2(NumberInWords(a));
		if (a<100)
			n.Append(_L8(" and "));
		else
			n.Append(' ');
		n+=n2;
		}
	return n;
	}

void PrintNumberInWords(TInt a)
	{
	TBuf<256> buf;
	TTestName n(NumberInWords(a));
	buf.Copy(n);
	test.Printf(_L("%d: %S\n"), a, &buf);
	}

TUint32 HashTestName(const TTestName& aN)
	{
	return DefaultHash::Des8(aN);
	}

TBool TestNameIdentity(const TTestName& aA, const TTestName& aB)
	{
	return aA == aB;
	}

/******************************************************************************
 * Utility functions for RHashSet<T>
 ******************************************************************************/
template <class T>
void Union(RHashSet<T>& aD, const RHashSet<T>& aS)
	{
	TInt c = aS.Count();
	TInt c2 = c;
	TInt d0 = aD.Count();
	TInt d1 = d0;
	typename RHashSet<T>::TIter iS(aS);
	FOREVER
		{
		const T* p = iS.Next();
		if (!p)
			break;
		--c2;
		TInt r = aD.Insert(*p);
		test(r==KErrNone);
		++d1;
		}
	test(d1 == aD.Count());
	test(c2 == 0);
	}

template <class T>
void Subtract(RHashSet<T>& aD, const RHashSet<T>& aS)
	{
	TInt c = aS.Count();
	TInt c2 = c;
	TInt d0 = aD.Count();
	TInt d1 = d0;
	TInt nfd = 0;
	typename RHashSet<T>::TIter iS(aS);
	FOREVER
		{
		const T* p = iS.Next();
		if (!p)
			break;
		--c2;
		TInt r = aD.Remove(*p);
		test(r==KErrNone || r==KErrNotFound);
		if (r==KErrNotFound)
			++nfd;
		else
			--d1;
		}
	test(d1 == aD.Count());
	test(c2 == 0);
	test( (d0-d1) + nfd == c);
	}

template <class T>
void Intersect(RHashSet<T>& aD, const RHashSet<T>& aS)
	{
	typename RHashSet<T>::TIter iD(aD);
	FOREVER
		{
		const T* p = iD.Next();
		if (!p)
			break;
		if (!aS.Find(*p))
			iD.RemoveCurrent();
		}
	}

template <class T>
void CheckIdentical(const RHashSet<T>& aA, const RHashSet<T>& aB)
	{
	test(aA.Count()==aB.Count());
	TInt c = aA.Count();
	typename RHashSet<T>::TIter iA(aA);
	FOREVER
		{
		const T* p = iA.Next();
		if (!p)
			break;
		--c;
		test(aB.Find(*p)!=0);
		}
	test(c==0);
	c = aA.Count();
	typename RHashSet<T>::TIter iB(aB);
	FOREVER
		{
		const T* p = iB.Next();
		if (!p)
			break;
		--c;
		test(aA.Find(*p)!=0);
		}
	test(c==0);
	}


/******************************************************************************
 * Utility functions for RPtrHashSet<T>
 ******************************************************************************/
template <class T>
void Union(RPtrHashSet<T>& aD, const RPtrHashSet<T>& aS)
	{
	TInt c = aS.Count();
	TInt c2 = c;
	TInt d0 = aD.Count();
	TInt d1 = d0;
	typename RPtrHashSet<T>::TIter iS(aS);
	FOREVER
		{
		const T* p = iS.Next();
		if (!p)
			break;
		--c2;
		TInt r = aD.Insert(p);
		test(r==KErrNone);
		++d1;
		}
	test(d1 == aD.Count());
	test(c2 == 0);
	}

template <class T>
void Subtract(RPtrHashSet<T>& aD, const RPtrHashSet<T>& aS)
	{
	TInt c = aS.Count();
	TInt c2 = c;
	TInt d0 = aD.Count();
	TInt d1 = d0;
	TInt nfd = 0;
	typename RPtrHashSet<T>::TIter iS(aS);
	FOREVER
		{
		const T* p = iS.Next();
		if (!p)
			break;
		--c2;
		TInt r = aD.Remove(p);
		test(r==KErrNone || r==KErrNotFound);
		if (r==KErrNotFound)
			++nfd;
		else
			--d1;
		}
	test(d1 == aD.Count());
	test(c2 == 0);
	test( (d0-d1) + nfd == c);
	}

template <class T>
void Intersect(RPtrHashSet<T>& aD, const RPtrHashSet<T>& aS)
	{
	typename RPtrHashSet<T>::TIter iD(aD);
	FOREVER
		{
		const T* p = iD.Next();
		if (!p)
			break;
		if (!aS.Find(*p))
			iD.RemoveCurrent();
		}
	}

template <class T>
void CheckIdentical(const RPtrHashSet<T>& aA, const RPtrHashSet<T>& aB)
	{
	test(aA.Count()==aB.Count());
	TInt c = aA.Count();
	typename RPtrHashSet<T>::TIter iA(aA);
	FOREVER
		{
		const T* p = iA.Next();
		if (!p)
			break;
		--c;
		test(aB.Find(*p)!=0);
		}
	test(c==0);
	c = aA.Count();
	typename RPtrHashSet<T>::TIter iB(aB);
	FOREVER
		{
		const T* p = iB.Next();
		if (!p)
			break;
		--c;
		test(aA.Find(*p)!=0);
		}
	test(c==0);
	}


/******************************************************************************
 * Utility functions for RHashMap<K,V>
 ******************************************************************************/
template <class K, class V>
void UnionTransform(RHashMap<K,V>& aD, const RHashSet<K>& aS, V (*aTransform)(const K&) )
	{
	TInt c = aS.Count();
	TInt c2 = c;
	TInt d0 = aD.Count();
	TInt d1 = d0;
	typename RHashSet<K>::TIter iS(aS);
	FOREVER
		{
		const K* p = iS.Next();
		if (!p)
			break;
		--c2;
		TInt r = aD.Insert(*p, (*aTransform)(*p) );
		test(r==KErrNone);
		++d1;
		}
	test(d1 == aD.Count());
	test(c2 == 0);
	}


template <class K, class V>
void UnionMap(RHashSet<V>& aD, const RHashSet<K>& aS, const RHashMap<K,V>& aM)
	{
	TInt c = aS.Count();
	TInt c2 = c;
	TInt d0 = aD.Count();
	TInt d1 = d0;
	typename RHashSet<K>::TIter iS(aS);
	FOREVER
		{
		const K* p = iS.Next();
		if (!p)
			break;
		--c2;
		const V* q = aM.Find(*p);
		if (!q)
			continue;
		TInt r = aD.Insert(*q);
		test(r==KErrNone);
		++d1;
		}
	test(d1 == aD.Count());
	test(c2 == 0);
	}


template <class K, class V>
void UnionKeys(RHashSet<K>& aD, const RHashMap<K,V>& aM)
	{
	typename RHashMap<K,V>::TIter iM(aM);
	FOREVER
		{
		const K* p = iM.NextKey();
		if (!p)
			break;
		aD.Insert(*p);
		}
	}


template <class K, class V>
void UnionValues(RHashSet<V>& aD, const RHashMap<K,V>& aM)
	{
	typename RHashMap<K,V>::TIter iM(aM);
	FOREVER
		{
		const K* p = iM.NextKey();
		if (!p)
			break;
		const V* q = iM.CurrentValue();
		aD.Insert(*q);
		}
	}


template <class K, class V>
void UnionTransform(RHashMap<K,V>& aD, const RHashMap<K,V>& aS, V (*aTransform)(const V&) )
	{
	TInt c = aS.Count();
	TInt c2 = c;
	TInt d0 = aD.Count();
	TInt d1 = d0;
	typename RHashMap<K,V>::TIter iS(aS);
	FOREVER
		{
		const K* p = iS.NextKey();
		if (!p)
			break;
		--c2;
		TInt r = aD.Insert(*p, (*aTransform)(*iS.CurrentValue()) );
		test(r==KErrNone);
		++d1;
		}
	test(d1 == aD.Count());
	test(c2 == 0);
	}


template <class K, class V>
void UnionInverse(RHashMap<V,K>& aD, const RHashMap<K,V>& aS)
	{
	TInt c = aS.Count();
	TInt c2 = c;
	TInt d0 = aD.Count();
	TInt d1 = d0;
	typename RHashMap<K,V>::TIter iS(aS);
	FOREVER
		{
		const K* p = iS.NextKey();
		if (!p)
			break;
		--c2;
		const V* q = iS.CurrentValue();
		TInt r = aD.Insert(*q, *p);
		test(r==KErrNone);
		++d1;
		}
	test(d1 == aD.Count());
	test(c2 == 0);
	}

template <class K, class V>
void SetMap(RHashMap<V,K>& aM, const V& aV)
	{
	typename RHashMap<K,V>::TIter iM(aM);
	FOREVER
		{
		const K* p = iM.NextKey();
		if (!p)
			break;
		V* q = iM.CurrentValue();
		*q = aV;
		test(*q == aV);
		}
	}


/******************************************************************************
 * Utility functions for RPtrHashMap<K,V>
 ******************************************************************************/
template <class K, class V>
void UnionTransform(RPtrHashMap<K,V>& aD, const RPtrHashMap<K,V>& aS, V* (*aTransform)(const V*) )
	{
	TInt c = aS.Count();
	TInt c2 = c;
	TInt d0 = aD.Count();
	TInt d1 = d0;
	typename RPtrHashMap<K,V>::TIter iS(aS);
	FOREVER
		{
		const K* p = iS.NextKey();
		if (!p)
			break;
		--c2;
		TInt r = aD.Insert(p, (*aTransform)(iS.CurrentValue()) );
		test(r==KErrNone);
		++d1;
		}
	test(d1 == aD.Count());
	test(c2 == 0);
	}


template <class A, class B>
void UnionInverse(RPtrHashMap<B,A>& aD, const RPtrHashMap<A,B>& a1)
	{
	typename RPtrHashMap<A,B>::TIter iter(a1);
	const A* pA;
	while ( (pA=iter.NextKey()) != 0 )
		{
		const B* pB = iter.CurrentValue();
		TInt r = aD.Insert(pB, pA);
		test(r==KErrNone);
		}
	}


template <class A, class B, class C>
void UnionCompose(RPtrHashMap<A,C>& aD, const RPtrHashMap<A,B>& a1, const RPtrHashMap<B,C>& a2)
	{
	typename RPtrHashMap<A,B>::TIter iter(a1);
	const A* pA;
	while ( (pA=iter.NextKey()) != 0 )
		{
		const B* pB = iter.CurrentValue();
		const C* pC = a2.Find(*pB);
		if (pC)
			{
			TInt r = aD.Insert(pA, pC);
			test(r==KErrNone);
			}
		}
	}


template <class K, class V>
void CheckIdenticalMaps(const RPtrHashMap<K,V>& aA, const RPtrHashMap<K,V>& aB)
	{
	test(aA.Count()==aB.Count());
	TInt c = aA.Count();
	const K* p;
	const V* q;
	typename RPtrHashMap<K,V>::TIter iA(aA);
	while( (p=iA.NextKey()) != 0)
		{
		--c;
		q = aB.Find(*p);
		test(q && q==iA.CurrentValue());
		}
	test(c==0);
	c = aB.Count();
	typename RPtrHashMap<K,V>::TIter iB(aB);
	while( (p=iB.NextKey()) != 0)
		{
		--c;
		q = aA.Find(*p);
		test(q && q==iB.CurrentValue());
		}
	test(c==0);
	}





/******************************************************************************
 * Tests of TIntSet
 ******************************************************************************/
void Populate(TIntSet& aH, TInt aS, TInt aE, TInt aM)
	{
	TInt x = aS;
	for (; x<=aE; x+=aM)
		aH.Insert(x);
	}

void PrimeSieve(TIntSet& aH, TInt aStart, TInt aEnd)
	{
	TInt x;
	TInt e = (aEnd&1) ? aEnd : aEnd-1;
	TInt s = (aStart<2) ? 2 : aStart|1;
	for (x=s; x<=e; ++x)
		{
//		test.Printf(_L("add %d\n"),x);
		aH.Insert(x);
		}
	TInt m=2;
	FOREVER
		{
		for (; m*m<=e && !aH.Find(m); ++m)
			{}
		if (m*m > e)
			break;
		for (x=m*2; x<=e; x+=m)
			{
//			test.Printf(_L("remove %d\n"),x);
			aH.Remove(x);
			}
		++m;
		}
	}

TBool IsPrime(TInt x)
	{
	if (x==2)
		return ETrue;
	if (!(x&1))
		return EFalse;
	TInt d;
	for (d=3; d*d<=x; d+=2)
		{
		if (x%d==0)
			return EFalse;
		}
	return ETrue;
	}

void CheckSieveOutput(TIntSet& aH)
	{
	RHashSet<TInt>::TIter iter(aH);
	TInt min = KMaxTInt;
	TInt max = KMinTInt;
	TInt c = 0;
	test.Printf(_L("%d elements:\n"),aH.Count());
	FOREVER
		{
		const TInt* p = iter.Next();
		if (!p)
			break;
		++c;
		if (*p>max) max=*p;
		if (*p<min) min=*p;
//		test.Printf(_L("%d\n"),*p);
		test(IsPrime(*p));
		}
	test(c==aH.Count());
	TInt x;
	if (min==2)
		{
		test(aH.Find(2)!=0);
		min++;
		}
	for (x=min; x<=max; x+=2)
		{
		if (IsPrime(x))
			test(aH.Find(x)!=0);
		}
	for (x=min; x<=max; x+=2)
		{
		if (IsPrime(x))
			test(aH.Find(x)==&aH.FindL(x));
		else
			{
			TRAPD(rr,aH.FindL(x));
			test(rr==KErrNotFound);
			}
		}
	}

TUint32 CheckSmallHashSet(const TIntSet& aA)
	{
	TUint32 m = 0;
	RHashSet<TInt>::TIter iter(aA);
	FOREVER
		{
		const TInt* p = iter.Next();
		if (!p)
			break;
		m |= (1<<*p);
		}
	return m;
	}

void AddToSmallHashSet(TIntSet& aA, TUint32 aMask)
	{
	CheckSmallHashSet(aA);
	TInt i;
	TInt r;
	for (i=0; i<32; ++i)
		{
		if (aMask & (1<<i))
			{
			r = aA.Insert(i);
			test(r==KErrNone);
			}
		}
	}

void RemoveFromSmallHashSet(TIntSet& aA, TUint32 aMask)
	{
	TUint32 m = CheckSmallHashSet(aA);
	TInt i;
	TInt r;
	for (i=0; i<32; ++i)
		{
		if (aMask & (1<<i))
			{
			r = aA.Remove(i);
			if (m & (1<<i))
				test(r==KErrNone);
			else
				test(r==KErrNotFound);
			}
		}
	}

void TestHashSet()
	{
	test.Next(_L("Test RHashSet"));

	INTSET(hs);
	CCheck(hs);		// check consistency for empty table
	INTSET(hs2);
	INTSET(hs3);
	PrimeSieve(hs, 1, 100);
	CheckSieveOutput(hs);
	test(hs.Reserve(1000)==KErrNone);
	CCheck(hs);
	CheckSieveOutput(hs);	// check that Reserve() preserves existing entries

	INTSET(m1);
	INTSET(m2);
	INTSET(m3);
	INTSET(m5);
	INTSET(m7);
	Populate(m1,2,100,1);
	Populate(m2,4,100,2);
	Populate(m3,6,100,3);
	Populate(m5,10,100,5);
	Populate(m7,14,100,7);
	Union(hs3, m1);
	Subtract(hs3, m2);
	Subtract(hs3, m3);
	Subtract(hs3, m5);
	Subtract(hs3, m7);
	CheckSieveOutput(hs3);
	CheckIdentical(hs,hs3);
	hs3.Close();
	INTSET(cm2);
	INTSET(cm3);
	INTSET(cm5);
	INTSET(cm7);
	Union(cm2, m1);
	Subtract(cm2, m2);
	Union(cm3, m1);
	Subtract(cm3, m3);
	Union(cm5, m1);
	Subtract(cm5, m5);
	Union(cm7, m1);
	Subtract(cm7, m7);
	Union(hs3, m1);
	Intersect(hs3, cm7);
	Intersect(hs3, cm3);
	Intersect(hs3, cm5);
	Intersect(hs3, cm2);
	CheckSieveOutput(hs3);
	CheckIdentical(hs,hs3);
	hs3.Close();


	cm2.Close();
	cm3.Close();
	cm5.Close();
	cm7.Close();
	m1.Close();
	m2.Close();
	m3.Close();
	m5.Close();
	m7.Close();

	PrimeSieve(hs2, 1, 1000);
	CheckSieveOutput(hs2);
	test(hs2.Reserve(1000)==KErrNone);
	CCheck(hs2);
	CheckSieveOutput(hs2);	// check that Reserve() preserves existing entries

	PrimeSieve(hs, 100, 997);
	CheckSieveOutput(hs);
	CCheck(hs);
	CheckIdentical(hs,hs2);

	hs2.Close();
	Union(hs2, hs);
	CheckIdentical(hs,hs2);
	CheckSieveOutput(hs2);

	hs2.Close();
	hs.Close();

	test(CheckSmallHashSet(hs)==0);
	AddToSmallHashSet(hs, 1);
	test(CheckSmallHashSet(hs)==1);
	AddToSmallHashSet(hs, 4);
	test(CheckSmallHashSet(hs)==5);
	AddToSmallHashSet(hs, 0x80000001);
	test(CheckSmallHashSet(hs)==0x80000005);
	AddToSmallHashSet(hs, 0x317217f8);
	test(CheckSmallHashSet(hs)==0xb17217fd);
	RemoveFromSmallHashSet(hs, 0x00000007);
	test(CheckSmallHashSet(hs)==0xb17217f8);
	RemoveFromSmallHashSet(hs, 0xffffffff);
	test(CheckSmallHashSet(hs)==0);
	hs.Close();
	}

void TestHashIter()
	{
	test.Next(_L("Test iterators"));

	RHashSet<TInt> hs;		// empty
	RHashSet<TInt>::TIter iter(hs);
	test(iter.Next() == 0);
	test(iter.Current() == 0);
	iter.RemoveCurrent();
	test(iter.Next() == 0);
	test(iter.Current() == 0);

	test(hs.Insert(1) == KErrNone);
	test(hs.Insert(2) == KErrNone);
	test(hs.Insert(3) == KErrNone);
	iter.Reset();
	TUint mask = 14;
	TInt i;
	for (i=0; i<3; ++i)
		{
		const TInt* p = iter.Next();
		test(p!=0);
		TInt x = *p;
		test (x>=1 && x<=3 && (mask&(1<<x))!=0);
		mask &= ~(1<<x);
		}
	test(iter.Next() == 0);
	test(mask==0);
	test(CheckSmallHashSet(hs)==0x0e);
	test(hs.Insert(4) == KErrNone);
	test(hs.Insert(5) == KErrNone);
	test(hs.Insert(6) == KErrNone);
	test(hs.Insert(7) == KErrNone);
	test(CheckSmallHashSet(hs)==0xfe);
	iter.Reset();
	while(iter.Next())
		{
		if ((*iter.Current() & 1) == 0)
			iter.RemoveCurrent();
		}
	test(CheckSmallHashSet(hs)==0xaa);
	iter.Reset();
	while(iter.Next())
		{
		iter.RemoveCurrent();
		}
	test(CheckSmallHashSet(hs)==0);
	iter.Reset();
	test(iter.Next() == 0);
	test(iter.Current() == 0);
	RHashSet<TInt> empty;
	CheckIdentical(hs, empty);
#ifdef _DEBUG
	__UHEAP_FAILNEXT(1);
	test(empty.Insert(1)==KErrNoMemory);
	test(empty.Insert(1)==KErrNone);
	empty.Close();
	__UHEAP_FAILNEXT(1);
	test(hs.Insert(1)==KErrNone);
	hs.Close();
	__UHEAP_FAILNEXT(1);
	test(hs.Insert(1)==KErrNoMemory);
#endif
	hs.Close();
	}

void Print(const char* aTitle, const RHashMap<TInt,TTestName>& aM)
	{
	TBuf<256> buf;
	buf.Copy(TPtrC8((const TUint8*)aTitle));
	test.Printf(_L("%S\n"), &buf);
	RHashMap<TInt,TTestName>::TIter iter(aM);
	FOREVER
		{
		const TInt* p = iter.NextKey();
		if (!p) break;
		buf.Copy(*iter.CurrentValue());
		test.Printf(_L("%d: %S\n"), *p, &buf);
		}
	}

void Print(const char* aTitle, const RHashSet<TTestName>& aS)
	{
	TBuf<256> buf;
	buf.Copy(TPtrC8((const TUint8*)aTitle));
	test.Printf(_L("%S\n"), &buf);
	RHashSet<TTestName>::TIter iter(aS);
	FOREVER
		{
		if (!iter.Next())
			break;
		buf.Copy(*iter.Current());
		test.Printf(_L("%S\n"), &buf);
		}
	}

void TestHashMap()
	{
	test.Next(_L("Test RHashMap"));

	RHashMap<TInt,TInt> ht;
	CCheck(ht);		// check consistency for empty table
	TInt x;
	for (x=0; x<200; x++)
		{
		TInt r = ht.Insert(x*x, x);
		test(r==KErrNone);
		}
	test(ht.Count()==200);

	TInt z = 0;
	TInt y;
	for (x=0; x<40000; x++)
		{
		const TInt* e = ht.Find(x);
		if (e)
			{
			const TInt& ee = ht.FindL(x);
			test(&ee==e);
			y = *e;
//			test.Printf(_L("Find(%d) -> %d\n"), x, y);
			test(x == z*z);
			test(y == z);
			++z;
			}
		else
			{
			TRAPD(rr, ht.FindL(x));
			test(rr==KErrNotFound);
			}
		}
	CCheck(ht);

	for (x=0; x<200; x++)
		{
		TInt r = ht.Insert(x*x*x, x);
		test(r==KErrNone);
		}
	test(ht.Count()==200*2-6);
	CCheck(ht);

	TInt sq = 0;
	TInt cb = 0;
	for (x=0; x<8000000; x++)
		{
		const TInt* e = ht.Find(x);
		if (e)
			{
			const TInt& ee = ht.FindL(x);
			test(&ee==e);
			y = *e;
//			test.Printf(_L("Find(%d) -> %d\n"), x, y);
			if (x == cb*cb*cb)
				{
				test(y==cb);
				++cb;
				if (x == sq*sq)
					++sq;
				}
			else if (x == sq*sq)
				{
				test(y==sq);
				++sq;
				}
			}
		}

	for (x=0; x<200; x++)
		{
		TInt r = ht.Remove(x*x);
		test(r==KErrNone);
		}
	test(ht.Count()==200-6);
	CCheck(ht);

	cb = 2;
	for (x=2; x<8000000; x++)
		{
		const TInt* e = ht.Find(x);
		if (e)
			{
			const TInt& ee = ht.FindL(x);
			test(&ee==e);
			y = *e;
//			test.Printf(_L("Find(%d) -> %d\n"), x, y);
			if (cb == 4 || cb == 9 || cb == 16 || cb == 25) ++cb;
			test(x == cb*cb*cb);
			test(y == cb);
			++cb;
			}
		}

	SetMap<TInt,TInt>(ht, 17);

	ht.Close();

	PrintNumberInWords(2000);
	PrintNumberInWords(2001);
	PrintNumberInWords(131072);
	PrintNumberInWords(111111);
	PrintNumberInWords(524288);

	INTSET(all);
	Populate(all,0,1000,1);
	RHashMap<TInt,TTestName> to_words(&DefaultHash::Integer, &DefaultIdentity::Integer);
	UnionTransform<TInt,TTestName>(to_words, all, &NumberInWords);
	RHashMap<TTestName,TInt> from_words(&HashTestName, &TestNameIdentity);
	UnionInverse<TInt,TTestName>(from_words, to_words);
//	Print("TO WORDS:", to_words);
	INTSET(primes);
	PrimeSieve(primes, 1, 100);
//	Print("Primes 1-100", primes);
	RHashMap<TInt,TTestName> prime_map(&DefaultHash::Integer, &DefaultIdentity::Integer);
	UnionTransform<TInt,TTestName>(prime_map, primes, &NumberInWords);
//	Print("Prime map 1-100", prime_map);
	INTSET(pmkeys);
	UnionKeys<TInt,TTestName>(pmkeys, prime_map);
	NAMESET(pmval);
	NAMESET(pmval2);
	UnionValues<TInt,TTestName>(pmval, prime_map);
	CheckIdentical(pmkeys, primes);
	INTSET(pr2);
	UnionMap<TTestName,TInt>(pr2, pmval, from_words);
	CheckIdentical(pr2, primes);
	pr2.Close();
	Union(pmval2, pmval);
//	Print("pmval",pmval);
//	Print("pmval2",pmval2);
	CheckIdentical(pmval2, pmval);
	UnionMap<TTestName,TInt>(pr2, pmval2, from_words);
	CheckIdentical(pr2, primes);

	pr2.Close();
	pmval.Close();
	pmval2.Close();
	pmkeys.Close();
	prime_map.Close();
	primes.Close();
	all.Close();

	INTSET(m);
	Populate(all,2,1000,1);

	NAMESET(pr3);
	NAMESET(nm);
	UnionMap<TInt,TTestName>(pr3, all, to_words);
	all.Close();
	CCheck(pr3);

	Populate(m,4,1000,2);
	UnionMap<TInt,TTestName>(nm, m, to_words);
	m.Close();
	Subtract(pr3, nm);
	nm.Close();

	Populate(m,6,1000,3);
	UnionMap<TInt,TTestName>(nm, m, to_words);
	m.Close();
	Subtract(pr3, nm);
	nm.Close();

	Populate(m,10,1000,5);
	UnionMap<TInt,TTestName>(nm, m, to_words);
	m.Close();
	Subtract(pr3, nm);
	nm.Close();

	Populate(m,14,1000,7);
	UnionMap<TInt,TTestName>(nm, m, to_words);
	m.Close();
	Subtract(pr3, nm);
	nm.Close();

	Populate(m,22,1000,11);
	UnionMap<TInt,TTestName>(nm, m, to_words);
	m.Close();
	Subtract(pr3, nm);
	nm.Close();

	Populate(m,26,1000,13);
	UnionMap<TInt,TTestName>(nm, m, to_words);
	m.Close();
	Subtract(pr3, nm);
	nm.Close();

	Populate(m,34,1000,17);
	UnionMap<TInt,TTestName>(nm, m, to_words);
	m.Close();
	Subtract(pr3, nm);
	nm.Close();

	Populate(m,38,1000,19);
	UnionMap<TInt,TTestName>(nm, m, to_words);
	m.Close();
	Subtract(pr3, nm);
	nm.Close();

	Populate(m,46,1000,23);
	UnionMap<TInt,TTestName>(nm, m, to_words);
	m.Close();
	Subtract(pr3, nm);
	nm.Close();

	Populate(m,58,1000,29);
	UnionMap<TInt,TTestName>(nm, m, to_words);
	m.Close();
	Subtract(pr3, nm);
	nm.Close();

	Populate(m,62,1000,31);
	UnionMap<TInt,TTestName>(nm, m, to_words);
	m.Close();
	Subtract(pr3, nm);
	nm.Close();

//	Print("pr3",pr3);
	PrimeSieve(primes, 1, 1000);
	UnionMap<TInt,TTestName>(nm, primes, to_words);
	CheckIdentical(nm, pr3);
	CCheck(pr3);
	UnionMap<TTestName,TInt>(m, pr3, from_words);
	CheckIdentical(m, primes);

	m.Close();
	nm.Close();
	primes.Close();
	pr3.Close();
	from_words.Close();
	to_words.Close();
	}

void PopulateArray8(TInt aMax)
	{
	TInt i;
	for (i=0; i<aMax; ++i)
		{
		TTestName n(NumberInWords(i));
		HBufC8* p = n.Alloc();
		test(p!=0);
		TInt r = DesC8Array.Append(p);
		test(r==KErrNone);
		}
	}

void PopulateArray16(TInt aMax)
	{
	TInt i;
	for (i=0; i<aMax; ++i)
		{
		TTestName n(NumberInWords(i));
		TBuf<128> n16;
		n16.Copy(n);
		HBufC16* p = n16.Alloc();
		test(p!=0);
		TInt r = DesC16Array.Append(p);
		test(r==KErrNone);
		}
	}

TUint32 istrh8(const TDesC8* const & a)
	{
	return DefaultHash::Des8(*a);
	}

TBool istrid8(const TDesC8* const & aA, const TDesC8* const & aB)
	{
	return *aA == *aB;
	}

TUint32 istrh16(const TDesC16* const & a)
	{
	return DefaultHash::Des16(*a);
	}

TBool istrid16(const TDesC16* const & aA, const TDesC16* const & aB)
	{
	return *aA == *aB;
	}

void TestPtrHashSet()
	{
	test.Next(_L("Test RPtrHashSet"));

	STRSET8(s);
	CCheck(s);		// check consistency for empty table
	RHashMap<const TDesC8*, TInt> hm(&istrh8, &istrid8);
	RPtrHashSet<TDesC8>::TIter iter(s);
	const TDesC8* q;
	TInt i;
	for (i=0; i<4096; ++i)
		{
		TInt r = s.Insert(DesC8Array[i]);
		test(r==KErrNone);
		r = hm.Insert(DesC8Array[i], i);
		test(r==KErrNone);
		}
	CCheck(s);
	for (i=0; i<4100; ++i)
		{
		TTestName n(NumberInWords(i));
		const TDesC8* p = s.Find(n);
		if (i<4096)
			{
			const TDesC8& pp = s.FindL(n);
			test(p && *p==n && p==DesC8Array[i]);
			test(&pp == p);
			}
		else
			{
			test(!p);
			TRAPD(rr,s.FindL(n));
			test(rr==KErrNotFound);
			}
		}
	while((q=iter.Next())!=0)
		{
		const TInt* qi = hm.Find(q);
		test(qi!=0 && *qi>=0 && *qi<4096);
		test(DesC8Array[*qi]==q);
		}
	for (i=0; i<4100; i+=2)
		{
		TTestName n(NumberInWords(i));
		TInt r = s.Remove(&n);
		if (i<4096)
			test(r==KErrNone);
		else
			test(r==KErrNotFound);
		}
	test(s.Count()==2048);
	CCheck(s);
	for (i=0; i<4100; ++i)
		{
		TTestName n(NumberInWords(i));
		const TDesC8* p = s.Find(n);
		if (i<4096 && (i&1))
			test(p && *p==n && p==DesC8Array[i]);
		else
			test(!p);
		}
	iter.Reset();
	while((q=iter.Next())!=0)
		{
		const TInt* qi = hm.Find(q);
		test(qi!=0 && *qi>=0 && *qi<4096 && (*qi&1));
		test(DesC8Array[*qi]==q);
		}
	for (i=2; i<4096; i+=4)
		{
		TInt r = s.Insert(DesC8Array[i]);
		test(r==KErrNone);
		}
	test(s.Count()==3072);
	CCheck(s);
	for (i=0; i<4100; ++i)
		{
		TTestName n(NumberInWords(i));
		const TDesC8* p = s.Find(n);
		if (i<4096 && (i&3))
			test(p && *p==n && p==DesC8Array[i]);
		else
			test(!p);
		}
	iter.Reset();
	while((q=iter.Next())!=0)
		{
		const TInt* qi = hm.Find(q);
		test(qi!=0 && *qi>=0 && *qi<4096 && (*qi&3));
		test(DesC8Array[*qi]==q);
		}
	s.Close();

	// test ResetAndDestroy
	for (i=0; i<16; ++i)
		{
		TInt r = s.Insert(DesC8Array[i]->Alloc());
		test(r==KErrNone);
		}
	iter.Reset();
	while((q=iter.Next())!=0)
		{
		const TInt* qi = hm.Find(q);
		test(qi!=0 && *qi>=0 && *qi<16);
		test(*DesC8Array[*qi]==*q);
		test(DesC8Array[*qi]!=q);
		}
	s.ResetAndDestroy();
	hm.Close();


	STRSET16(S);
	RHashMap<const TDesC16*, TInt> HM(&istrh16, &istrid16);
	RPtrHashSet<TDesC16>::TIter ITER(S);
	const TDesC16* Q;
	for (i=0; i<4096; ++i)
		{
		TInt r = S.Insert(DesC16Array[i]);
		test(r==KErrNone);
		r = HM.Insert(DesC16Array[i], i);
		test(r==KErrNone);
		}
	CCheck(S);
	for (i=0; i<4100; ++i)
		{
		TTestName n(NumberInWords(i));
		TBuf<80> buf;
		buf.Copy(n);
		const TDesC16* p = S.Find(buf);
		if (i<4096)
			test(p && *p==buf && p==DesC16Array[i]);
		else
			test(!p);
		}
	while((Q=ITER.Next())!=0)
		{
		const TInt* qi = HM.Find(Q);
		test(qi!=0 && *qi>=0 && *qi<4096);
		test(DesC16Array[*qi]==Q);
		}
	for (i=0; i<4100; i+=2)
		{
		TTestName n(NumberInWords(i));
		TBuf<80> buf;
		buf.Copy(n);
		TInt r = S.Remove(&buf);
		if (i<4096)
			test(r==KErrNone);
		else
			test(r==KErrNotFound);
		}
	test(S.Count()==2048);
	CCheck(S);
	for (i=0; i<4100; ++i)
		{
		TTestName n(NumberInWords(i));
		TBuf<80> buf;
		buf.Copy(n);
		const TDesC16* p = S.Find(buf);
		if (i<4096 && (i&1))
			test(p && *p==buf && p==DesC16Array[i]);
		else
			test(!p);
		}
	ITER.Reset();
	while((Q=ITER.Next())!=0)
		{
		const TInt* qi = HM.Find(Q);
		test(qi!=0 && *qi>=0 && *qi<4096 && (*qi&1));
		test(DesC16Array[*qi]==Q);
		}
	for (i=2; i<4096; i+=4)
		{
		TInt r = S.Insert(DesC16Array[i]);
		test(r==KErrNone);
		}
	test(S.Count()==3072);
	CCheck(S);
	for (i=0; i<4100; ++i)
		{
		TTestName n(NumberInWords(i));
		TBuf<80> buf;
		buf.Copy(n);
		const TDesC16* p = S.Find(buf);
		if (i<4096 && (i&3))
			test(p && *p==buf && p==DesC16Array[i]);
		else
			test(!p);
		}
	ITER.Reset();
	while((Q=ITER.Next())!=0)
		{
		const TInt* qi = HM.Find(Q);
		test(qi!=0 && *qi>=0 && *qi<4096 && (*qi&3));
		test(DesC16Array[*qi]==Q);
		}
	S.Close();

	// test ResetAndDestroy
	for (i=0; i<16; ++i)
		{
		TInt r = S.Insert(DesC16Array[i]->Alloc());
		test(r==KErrNone);
		}
	ITER.Reset();
	while((Q=ITER.Next())!=0)
		{
		const TInt* qi = HM.Find(Q);
		test(qi!=0 && *qi>=0 && *qi<16);
		test(*DesC16Array[*qi]==*Q);
		test(DesC16Array[*qi]!=Q);
		}
	S.ResetAndDestroy();
	HM.Close();
	}

void TestPtrHashMap()
	{
	test.Next(_L("Test RPtrHashMap"));

	STRMAP8(map);
	CCheck(map);		// check consistency for empty table
	STRMAP8(id);
	TInt i;
	for (i=0; i<4096; ++i)
		{
		TInt r = map.Insert(DesC8Array[i], DesC8Array[(i+1)&0xfff]);
		test(r==KErrNone);
		r = id.Insert(DesC8Array[i], DesC8Array[i]);
		test(r==KErrNone);
		}
	for (i=0; i<4096; ++i)
		{
		const TDesC8* p = map.Find(*DesC8Array[i]);
		test(p == DesC8Array[(i+1)&0xfff]);
		const TDesC8& pp = map.FindL(*DesC8Array[i]);
		test(&pp == p);
		}
	TRAPD(rr,map.FindL(_L8("two")));
	test(rr==KErrNone);
	TRAP(rr,map.FindL(_L8("twx")));
	test(rr==KErrNotFound);
	CCheck(map);
	STRMAP8(map2);
	STRMAP8(mapi);
	STRMAP8(map3);
	UnionInverse<TDesC8,TDesC8>(mapi, map);
	UnionCompose<TDesC8,TDesC8,TDesC8>(map2, map, map);
	UnionCompose<TDesC8,TDesC8,TDesC8>(map3, map, mapi);
	CheckIdenticalMaps<TDesC8,TDesC8>(map3, id);
	map3.Close();
	UnionCompose<TDesC8,TDesC8,TDesC8>(map3, map2, mapi);
	CheckIdenticalMaps<TDesC8,TDesC8>(map3, map);
	map3.Close();
	for (i=0; i<4096; ++i)
		{
		TInt r = map3.Insert(DesC8Array[i], DesC8Array[(i+2)&0xfff]);
		test(r==KErrNone);
		}
	CheckIdenticalMaps<TDesC8,TDesC8>(map3, map2);
	map3.Close();

	mapi.Close();
	map2.Close();
	id.Close();
	map.Close();

	// test ResetAndDestroy()
	for(i=0; i<16; ++i)
		{
		TInt r = map.Insert(DesC8Array[i]->Alloc(), DesC8Array[i*i]->Alloc());
		test(r==KErrNone);
		}
	map.ResetAndDestroy();
	}

void TestOOM()
	{
	// Max out memory and check it still works
	test.Next(_L("Test OOM"));

	TInt x = 0;
	TInt n = 0;
	TInt r;
	INTSET(set);
	FOREVER
		{
		x += 0x58b90bfb;
		r = set.Insert(x);
		if (r != KErrNone)
			break;
		++n;
		}
	test(r==KErrNoMemory);
	TRAPD(rr,set.InsertL(x));
	test(rr==KErrNoMemory);
	test.Printf(_L("%d integers stored\n"), n);
	test(set.Count()==n);
	TRAP(rr,set.InsertL(0x58b90bfb));	// already there
	test(rr==KErrNone);	// should succeed

	// final count should be a power of 2 minus 1
	test( (n&(n+1)) == 0 );

	x = 0;
	TInt i;
	for (i=0; i<=n; ++i)		// check everything has been stored correctly
		{
		x += 0x58b90bfb;
		const TInt* p = set.Find(x);
		if (i < n)
			test(p && *p == x);
		else
			test(!p);
		}
	set.Close();
	TInt nn;
	for (nn=256; nn<=n+256; nn+=256)
		{
		r = set.Reserve(nn);
		set.Close();
		if (r!=KErrNone)
			break;
		}
	test.Printf(_L("Max reserve %d\n"),nn);
	TInt thresh = 3*((n+1)>>2);
	test(nn == thresh + 256);
	}

class RDummyAllocator : public RAllocator
	{
public:
	virtual TAny* Alloc(TInt) {test(0); return 0;}
	virtual void Free(TAny*) {test(0);}
	virtual TAny* ReAlloc(TAny*, TInt, TInt) {test(0); return 0;}
	virtual TInt AllocLen(const TAny*) const  {test(0); return 0;}
	virtual TInt Compress() {test(0); return 0;}
	virtual void Reset() {test(0);}
	virtual TInt AllocSize(TInt&) const  {test(0); return 0;}
	virtual TInt Available(TInt&) const  {test(0); return 0;}
	virtual TInt DebugFunction(TInt, TAny*, TAny*) {test(0); return 0;}
	virtual TInt Extension_(TUint, TAny*&, TAny*) {test(0); return 0;}
	};

void IntegerBenchmark(TInt aCount, TBool aReserve)
	{
	RArray<TInt> array;
	TUint32 before, after, diff;
	TInt x=0;
	TInt i;
	double avg;

	test.Printf(_L("**** INTEGER BENCHMARKS ***\n"));

	if (!aReserve)
		{
		before = User::NTickCount();
		for (i=0; i<aCount; ++i)
			{
			x += 0x58b90bfb;
			TInt r = array.InsertInOrder(x);
			test(r==KErrNone);
			}
		after = User::NTickCount();
		diff = after - before;
		diff *= NanoTickPeriod;
		avg = (double)diff / (double)aCount;
		test.Printf(_L("ARRAY:      %d insertions take %dus (%.2gus each)\n"), aCount, diff, avg);

		x=0;
		before = User::NTickCount();
		for (i=0; i<aCount; ++i)
			{
			x += 0x58b90bfb;
			TInt r = array.FindInOrder(x);
			test(r>=0);
			}
		after = User::NTickCount();
		diff = after - before;
		diff *= NanoTickPeriod;
		avg = (double)diff / (double)aCount;
		test.Printf(_L("ARRAY:      %d successful finds take %dus (%.2gus each)\n"), aCount, diff, avg);

		before = User::NTickCount();
		for (i=0; i<aCount; ++i)
			{
			x += 0x58b90bfb;
			TInt r = array.FindInOrder(x);
			test(r==KErrNotFound);
			}
		after = User::NTickCount();
		diff = after - before;
		diff *= NanoTickPeriod;
		avg = (double)diff / (double)aCount;
		test.Printf(_L("ARRAY:      %d unsuccessful finds take %dus (%.2gus each)\n"), aCount, diff, avg);

		x=0;
		before = User::NTickCount();
		for (i=0; i<aCount; ++i)
			{
			x += 0x58b90bfb;
			TInt r = array.FindInOrder(x);
			test(r>=0);
			array.Remove(r);
			}
		after = User::NTickCount();
		diff = after - before;
		diff *= NanoTickPeriod;
		avg = (double)diff / (double)aCount;
		test.Printf(_L("ARRAY:      %d deletions take %dus (%.2gus each)\n"), aCount, diff, avg);
		array.Close();
		}

	INTSET(set);
	x=0;
	RAllocator* pA = 0;
	RDummyAllocator da;
	if (aReserve)
		{
		test(set.Reserve(aCount)==KErrNone);
		pA = User::SwitchAllocator(&da);			// check that no memory accesses occur
		test(set.Reserve(10)==KErrNone);			// shouldn't need to do anything
		test(set.Reserve(aCount/2)==KErrNone);		// shouldn't need to do anything
		test(set.Reserve(aCount)==KErrNone);		// shouldn't need to do anything
		}
	before = User::NTickCount();
	for (i=0; i<aCount; ++i)
		{
		x += 0x58b90bfb;
		TInt r = set.Insert(x);	// we have no heap here so this tests that Reserve() has preallocated sufficient memory
		test(r==KErrNone);
		}
	after = User::NTickCount();
	diff = after - before;
	diff *= NanoTickPeriod;
	avg = (double)diff / (double)aCount;
	if (aReserve)
		User::SwitchAllocator(pA);
	test.Printf(_L("HASH TABLE: %d insertions take %dus (%.2gus each)\n"), aCount, diff, avg);

	x=0;
	before = User::NTickCount();
	for (i=0; i<aCount; ++i)
		{
		x += 0x58b90bfb;
		const TInt* p = set.Find(x);
		test(p!=0);
		}
	after = User::NTickCount();
	diff = after - before;
	diff *= NanoTickPeriod;
	avg = (double)diff / (double)aCount;
	test.Printf(_L("HASH TABLE: %d successful finds take %dus (%.2gus each)\n"), aCount, diff, avg);

	before = User::NTickCount();
	for (i=0; i<aCount; ++i)
		{
		x += 0x58b90bfb;
		const TInt* p = set.Find(x);
		test(!p);
		}
	after = User::NTickCount();
	diff = after - before;
	diff *= NanoTickPeriod;
	avg = (double)diff / (double)aCount;
	test.Printf(_L("HASH TABLE: %d unsuccessful finds take %dus (%.2gus each)\n"), aCount, diff, avg);

	x=0;
	before = User::NTickCount();
	for (i=0; i<aCount; ++i)
		{
		x += 0x58b90bfb;
		TInt r = set.Remove(x);
		test(r==KErrNone);
		}
	after = User::NTickCount();
	diff = after - before;
	diff *= NanoTickPeriod;
	avg = (double)diff / (double)aCount;
	test.Printf(_L("HASH TABLE: %d deletions take %dus (%.2gus each)\n"), aCount, diff, avg);
	set.Close();
	}

TInt des8order(const TDesC8& aA, const TDesC8& aB)
	{
	return aA.Compare(aB);
	}

void StringBenchmark8(TInt aCount, TBool aReserve)
	{
	RPointerArray<TDesC8> array;
	TUint32 before, after, diff;
	TInt x=0;
	TInt i;
	double avg;
	const TDesC8** base = (const TDesC8**)&DesC8Array[0];
	test(base[1331] == DesC8Array[1331]);

	test.Printf(_L("**** 8 BIT STRING BENCHMARKS ***\n"));

	if (!aReserve)
		{
		before = User::NTickCount();
		for (i=0; i<aCount; ++i)
			{
			x = (x+4339)&0x3fff;
			TInt r = array.InsertInOrder(base[x], &des8order);
			test(r==KErrNone);
			}
		after = User::NTickCount();
		diff = after - before;
		diff *= NanoTickPeriod;
		avg = (double)diff / (double)aCount;
		test.Printf(_L("ARRAY:      %d insertions take %dus (%.2gus each)\n"), aCount, diff, avg);

		x=0;
		before = User::NTickCount();
		for (i=0; i<aCount; ++i)
			{
			x = (x+4339)&0x3fff;
			TInt r = array.FindInOrder(base[x], &des8order);
			test(r>=0);
			}
		after = User::NTickCount();
		diff = after - before;
		diff *= NanoTickPeriod;
		avg = (double)diff / (double)aCount;
		test.Printf(_L("ARRAY:      %d successful finds take %dus (%.2gus each)\n"), aCount, diff, avg);

		before = User::NTickCount();
		for (i=0; i<aCount; ++i)
			{
			x = (x+4339)&0x3fff;
			TInt r = array.FindInOrder(base[x], &des8order);
			test(r==KErrNotFound);
			}
		after = User::NTickCount();
		diff = after - before;
		diff *= NanoTickPeriod;
		avg = (double)diff / (double)aCount;
		test.Printf(_L("ARRAY:      %d unsuccessful finds take %dus (%.2gus each)\n"), aCount, diff, avg);

		x=0;
		before = User::NTickCount();
		for (i=0; i<aCount; ++i)
			{
			x = (x+4339)&0x3fff;
			TInt r = array.FindInOrder(base[x], &des8order);
			test(r>=0);
			array.Remove(r);
			}
		after = User::NTickCount();
		diff = after - before;
		diff *= NanoTickPeriod;
		avg = (double)diff / (double)aCount;
		test.Printf(_L("ARRAY:      %d deletions take %dus (%.2gus each)\n"), aCount, diff, avg);
		array.Close();
		}

	STRSET8(set);
	x=0;
	if (aReserve)
		test(set.Reserve(aCount)==KErrNone);
	before = User::NTickCount();
	for (i=0; i<aCount; ++i)
		{
		x = (x+4339)&0x3fff;
		TInt r = set.Insert(base[x]);
		test(r==KErrNone);
		}
	after = User::NTickCount();
	diff = after - before;
	diff *= NanoTickPeriod;
	avg = (double)diff / (double)aCount;
	test.Printf(_L("HASH TABLE: %d insertions take %dus (%.2gus each)\n"), aCount, diff, avg);

	x=0;
	before = User::NTickCount();
	for (i=0; i<aCount; ++i)
		{
		x = (x+4339)&0x3fff;
		const TDesC8* p = set.Find(*base[x]);
		test(p!=0);
		}
	after = User::NTickCount();
	diff = after - before;
	diff *= NanoTickPeriod;
	avg = (double)diff / (double)aCount;
	test.Printf(_L("HASH TABLE: %d successful finds take %dus (%.2gus each)\n"), aCount, diff, avg);

	before = User::NTickCount();
	for (i=0; i<aCount; ++i)
		{
		x = (x+4339)&0x3fff;
		const TDesC8* p = set.Find(*base[x]);
		test(!p);
		}
	after = User::NTickCount();
	diff = after - before;
	diff *= NanoTickPeriod;
	avg = (double)diff / (double)aCount;
	test.Printf(_L("HASH TABLE: %d unsuccessful finds take %dus (%.2gus each)\n"), aCount, diff, avg);

	x=0;
	before = User::NTickCount();
	for (i=0; i<aCount; ++i)
		{
		x = (x+4339)&0x3fff;
		TInt r = set.Remove(base[x]);
		test(r==KErrNone);
		}
	after = User::NTickCount();
	diff = after - before;
	diff *= NanoTickPeriod;
	avg = (double)diff / (double)aCount;
	test.Printf(_L("HASH TABLE: %d deletions take %dus (%.2gus each)\n"), aCount, diff, avg);
	set.Close();
	}

TInt des16order(const TDesC16& aA, const TDesC16& aB)
	{
	return aA.Compare(aB);
	}

void StringBenchmark16(TInt aCount, TBool aReserve)
	{
	RPointerArray<TDesC16> array;
	TUint32 before, after, diff;
	TInt x=0;
	TInt i;
	double avg;
	const TDesC16** base = (const TDesC16**)&DesC16Array[0];
	test(base[1331] == DesC16Array[1331]);

	test.Printf(_L("**** 16 BIT STRING BENCHMARKS ***\n"));

	if (!aReserve)
		{
		before = User::NTickCount();
		for (i=0; i<aCount; ++i)
			{
			x = (x+4339)&0x3fff;
			TInt r = array.InsertInOrder(base[x], &des16order);
			test(r==KErrNone);
			}
		after = User::NTickCount();
		diff = after - before;
		diff *= NanoTickPeriod;
		avg = (double)diff / (double)aCount;
		test.Printf(_L("ARRAY:      %d insertions take %dus (%.2gus each)\n"), aCount, diff, avg);

		x=0;
		before = User::NTickCount();
		for (i=0; i<aCount; ++i)
			{
			x = (x+4339)&0x3fff;
			TInt r = array.FindInOrder(base[x], &des16order);
			test(r>=0);
			}
		after = User::NTickCount();
		diff = after - before;
		diff *= NanoTickPeriod;
		avg = (double)diff / (double)aCount;
		test.Printf(_L("ARRAY:      %d successful finds take %dus (%.2gus each)\n"), aCount, diff, avg);

		before = User::NTickCount();
		for (i=0; i<aCount; ++i)
			{
			x = (x+4339)&0x3fff;
			TInt r = array.FindInOrder(base[x], &des16order);
			test(r==KErrNotFound);
			}
		after = User::NTickCount();
		diff = after - before;
		diff *= NanoTickPeriod;
		avg = (double)diff / (double)aCount;
		test.Printf(_L("ARRAY:      %d unsuccessful finds take %dus (%.2gus each)\n"), aCount, diff, avg);

		x=0;
		before = User::NTickCount();
		for (i=0; i<aCount; ++i)
			{
			x = (x+4339)&0x3fff;
			TInt r = array.FindInOrder(base[x], &des16order);
			test(r>=0);
			array.Remove(r);
			}
		after = User::NTickCount();
		diff = after - before;
		diff *= NanoTickPeriod;
		avg = (double)diff / (double)aCount;
		test.Printf(_L("ARRAY:      %d deletions take %dus (%.2gus each)\n"), aCount, diff, avg);
		array.Close();
		}

	STRSET16(set);
	x=0;
	if (aReserve)
		test(set.Reserve(aCount)==KErrNone);
	before = User::NTickCount();
	for (i=0; i<aCount; ++i)
		{
		x = (x+4339)&0x3fff;
		TInt r = set.Insert(base[x]);
		test(r==KErrNone);
		}
	after = User::NTickCount();
	diff = after - before;
	diff *= NanoTickPeriod;
	avg = (double)diff / (double)aCount;
	test.Printf(_L("HASH TABLE: %d insertions take %dus (%.2gus each)\n"), aCount, diff, avg);

	x=0;
	before = User::NTickCount();
	for (i=0; i<aCount; ++i)
		{
		x = (x+4339)&0x3fff;
		const TDesC16* p = set.Find(*base[x]);
		test(p!=0);
		}
	after = User::NTickCount();
	diff = after - before;
	diff *= NanoTickPeriod;
	avg = (double)diff / (double)aCount;
	test.Printf(_L("HASH TABLE: %d successful finds take %dus (%.2gus each)\n"), aCount, diff, avg);

	before = User::NTickCount();
	for (i=0; i<aCount; ++i)
		{
		x = (x+4339)&0x3fff;
		const TDesC16* p = set.Find(*base[x]);
		test(!p);
		}
	after = User::NTickCount();
	diff = after - before;
	diff *= NanoTickPeriod;
	avg = (double)diff / (double)aCount;
	test.Printf(_L("HASH TABLE: %d unsuccessful finds take %dus (%.2gus each)\n"), aCount, diff, avg);

	x=0;
	before = User::NTickCount();
	for (i=0; i<aCount; ++i)
		{
		x = (x+4339)&0x3fff;
		TInt r = set.Remove(base[x]);
		test(r==KErrNone);
		}
	after = User::NTickCount();
	diff = after - before;
	diff *= NanoTickPeriod;
	avg = (double)diff / (double)aCount;
	test.Printf(_L("HASH TABLE: %d deletions take %dus (%.2gus each)\n"), aCount, diff, avg);
	set.Close();
	}

void Benchmark()
	{
	test.Next(_L("Benchmarks ..."));

	IntegerBenchmark(1000, EFalse);
	IntegerBenchmark(1000, ETrue);
	IntegerBenchmark(2000, EFalse);
	IntegerBenchmark(2000, ETrue);
	IntegerBenchmark(4000, EFalse);
	IntegerBenchmark(4000, ETrue);
	IntegerBenchmark(8000, EFalse);
	IntegerBenchmark(8000, ETrue);
	IntegerBenchmark(16000, EFalse);
	IntegerBenchmark(16000, ETrue);
	IntegerBenchmark(32000, EFalse);
	IntegerBenchmark(32000, ETrue);

	PopulateArray8(16384);
	StringBenchmark8(1000, EFalse);
	StringBenchmark8(2000, EFalse);
	StringBenchmark8(4000, EFalse);
	StringBenchmark8(8000, EFalse);
	DesC8Array.ResetAndDestroy();

	PopulateArray16(16384);
	StringBenchmark16(1000, EFalse);
	StringBenchmark16(2000, EFalse);
	StringBenchmark16(4000, EFalse);
	StringBenchmark16(8000, EFalse);
	DesC16Array.ResetAndDestroy();
	}


TUint32 mp(TUint32 x)
	{
	TUint32 x3 = x+(x<<1);
	TUint32 x7 = x+(x3<<1);
	TUint32 x15 = x+(x7<<1);
	TUint32 y = x + (x7<<3) + (x3<<7) + (x15<<11) + (x7<<16) + (x3<<20) + (x15<<25) + (x<<31);
	return y;
	}

TUint32 strh(const char* aIn)
	{
	TUint32 h = 0;
	TInt i = 0;
	while (*aIn)
		{
		if (i==0)
			h = mp(h);
		TUint32 c = *aIn++;
		c <<= (8*i);
		h ^= c;
		i = (i+1)&3;
		}
	return mp(h);
	}

TUint32 strh(const wch* aIn)
	{
	TUint32 h = 0;
	TInt i = 0;
	while (*aIn)
		{
		if (i==0)
			h = mp(h);
		TUint32 c = *aIn++;
		switch (i)
			{
			case 0:		break;
			case 1:		c<<=16; break;
			case 2:		c<<=8; break;
			default:	c=(c<<24)|(c>>8); break;
			};
		h ^= c;
		i = (i+1)&3;
		}
	return mp(h);
	}

void TestHash(TInt* aIn, TUint32 aExpected)
	{
	THashFunction32<TInt*> hf(&DefaultHash::IntegerPtr);
	TUint32 out = hf.Hash(aIn);
	test(aExpected == mp((TUint32)aIn));
	if (out != aExpected)
		{
		test.Printf(_L("Hashing %08x Expected %08x Got %08x\n"), aIn, aExpected, out);
		test(0);
		}
	}

void TestHash(TDesC8* aIn, TUint32 aExpected)
	{
	THashFunction32<TDesC8*> hf(&DefaultHash::Des8Ptr);
	TUint32 out = hf.Hash(aIn);
	test(aExpected == mp((TUint32)aIn));
	if (out != aExpected)
		{
		test.Printf(_L("Hashing %08x Expected %08x Got %08x\n"), aIn, aExpected, out);
		test(0);
		}
	}

void TestHash(TDesC16* aIn, TUint32 aExpected)
	{
	THashFunction32<TDesC16*> hf(&DefaultHash::Des16Ptr);
	TUint32 out = hf.Hash(aIn);
	test(aExpected == mp((TUint32)aIn));
	if (out != aExpected)
		{
		test.Printf(_L("Hashing %08x Expected %08x Got %08x\n"), aIn, aExpected, out);
		test(0);
		}
	}


void TestHash(TInt aIn, TUint32 aExpected)
	{
	THashFunction32<TInt> hf(&DefaultHash::Integer);
	TUint32 out = hf.Hash(aIn);
	test(aExpected == mp((TUint32)aIn));
	if (out != aExpected)
		{
		test.Printf(_L("Hashing %08x Expected %08x Got %08x\n"), aIn, aExpected, out);
		test(0);
		}
	}

void TestHash(const char* aIn, TUint32 aExpected)
	{
	THashFunction32<TDesC8> hf(&DefaultHash::Des8);
	TPtrC8 p((const TUint8*)aIn);
	TUint32 out = hf.Hash(p);
	test(aExpected == strh(aIn));
	if (out != aExpected)
		{
		TBuf<256> buf;
		buf.Copy(p);
		test.Printf(_L("Hashing %S (len %d) Expected %08x Got %08x\n"), &buf, p.Length(), aExpected, out);
		test(0);
		}
	}

void TestHash(const wch* aIn)
	{
	THashFunction32<TDesC16> hf(&DefaultHash::Des16);
	TPtrC16 p((const TUint16*)aIn);
	TUint32 out = hf.Hash(p);
	TUint32 exp = strh(aIn);
	if (out != exp)
		{
		test.Printf(_L("Hashing %S (len %d) Expected %08x Got %08x\n"), &p, p.Size(), exp, out);
		test(0);
		}
	}

void TestHash()
	{
	test.Next(_L("Test integer hash"));
	TestHash(1,0x9e3779b9);
	TestHash(2,0x3c6ef372);
	TestHash(4,0x78dde6e4);
	TestHash(8,0xf1bbcdc8);
	TestHash(16,0xe3779b90);
	TestHash(0xc90fdaa2,0xbf999112);
	TestHash(0xb504f334,0x7fb35494);
	TestHash(0xddb3d743,0xd11a3a6b);
	TestHash(0xadf85458,0x873a8b98);
	TestHash(0x11730859,0xb4321951);
	TestHash(0x64636261,0x8628f119);
	}

void TestIntegerPtrHash()
	{
	TInt i[5];
	TInt* ptr;
	test.Next(_L("Test Integer pointer hash"));
	for (ptr=i; ptr<i+5; ptr++)
		{
		TestHash(ptr, DefaultHash::IntegerPtr(ptr));
		}
	}

void TestDes8PtrHash()
	{
	TBuf8<8> i[5];
	TDesC8* ptr;
	test.Next(_L("Test Des8 pointer hash"));
	for (ptr=i; ptr<i+5; ptr++)
		{
		TestHash(ptr, DefaultHash::Des8Ptr(ptr));
		}
	}

void TestDes16PtrHash()
	{
	TBuf16<8> i[5];
	TDesC16* ptr;
	test.Next(_L("Test Des16 pointer hash"));
	for (ptr=i; ptr<i+5; ptr++)
		{
		TestHash(ptr, DefaultHash::Des16Ptr(ptr));
		}
	}

const char teststr[] = "zyxwvutsrq";
void TestStringHash()
	{
	test.Next(_L("Test 8 bit string hash"));
	TestHash("",0x0);
	TestHash("a",0xf3051f19);
	TestHash("b",0x913c98d2);
	TestHash("ab",0x2f9df119);
	TestHash("ba",0x965bb1d2);
	TestHash("abc",0x4228f119);
	TestHash("abcd",0x8628f119);
	TestHash("abcde",0xb75e1e9c);
	TestHash("abcdef",0x3693149c);
	TestHash("abcdefg",0xc1c2149c);
	TestHash("abcdefgh",0xe9c2149c);
	TestHash("abcdefghi",0x5fcbf20d);
	TestHash("abcdefghj",0xfe036bc6);

	TestHash(teststr, 0x108ca51e);
	TestHash(teststr+1, 0x551002ad);
	TestHash(teststr+2, 0x37dc0d6c);
	TestHash(teststr+3, 0x2937f92c);
	TestHash(teststr+4, 0xf0818a94);
	TestHash(teststr+5, 0xb1b25f1c);
	TestHash(teststr+6, 0x7a3342d4);
	TestHash(teststr+7, 0x81c9101b);
	TestHash(teststr+8, 0xf16edd62);
	TestHash(teststr+9, 0xd67cbaa9);
	TestHash(teststr+10, 0);

	char t[16];
	int i,j;
	for (i=0; i<=4; ++i)
		{
		for (j=0; j<=10; ++j)
			{
			const char* s = teststr + j;
			int l = User::StringLength((const TUint8*)s);
			memset(t, 0xbb, 16);
			memcpy(t+i, s, l+1);
			TUint32 h;
			switch (j)
				{
				case 0: h = 0x108ca51e; break;
				case 1: h = 0x551002ad; break;
				case 2: h = 0x37dc0d6c; break;
				case 3: h = 0x2937f92c; break;
				case 4: h = 0xf0818a94; break;
				case 5: h = 0xb1b25f1c; break;
				case 6: h = 0x7a3342d4; break;
				case 7: h = 0x81c9101b; break;
				case 8: h = 0xf16edd62; break;
				case 9: h = 0xd67cbaa9; break;
				default: h = 0; break;
				};
			TestHash(t+i, h);
			}
		}
	}

const wch wteststr[] = L"zyxwvutsrq";
void TestWStringHash()
	{
	test.Next(_L("Test 16 bit string hash"));
	TestHash(L"");
	TestHash(L"a");
	TestHash(L"b");
	TestHash(L"ab");
	TestHash(L"ba");
	TestHash(L"abc");
	TestHash(L"abcd");
	TestHash(L"abcde");
	TestHash(L"abcdef");
	TestHash(L"abcdefg");
	TestHash(L"abcdefgh");
	TestHash(L"abcdefghi");
	TestHash(L"abcdefghj");

	TestHash(wteststr);
	TestHash(wteststr+1);
	TestHash(wteststr+2);
	TestHash(wteststr+3);
	TestHash(wteststr+4);
	TestHash(wteststr+5);
	TestHash(wteststr+6);
	TestHash(wteststr+7);
	TestHash(wteststr+8);
	TestHash(wteststr+9);
	TestHash(wteststr+10);

	wch t[16];
	int i,j;
	for (i=0; i<=4; ++i)
		{
		for (j=0; j<=10; ++j)
			{
			const wch* s = wteststr + j;
			int l = User::StringLength((const TUint16*)s);
			memset(t, 0xbb, 2*16);
			memcpy(t+i, s, 2*(l+1));
			TestHash(t+i);
			}
		}
	}
template <class K,class V> 
void TestHashMapPtr(RHashMap<K,V> &map, K ptr, V* i)
{
	test(map.Reserve(5) == KErrNone);
	for (ptr=i;ptr<i+5;ptr++)
		{
		test(map.Insert(ptr,*ptr) == KErrNone);
		}
	for (ptr=i+4;ptr>=i;ptr--)
		{
		test(*(map.Find(ptr)) == *ptr);
		}
	test(map.Count() == 5);
	test(map.Remove(i) == KErrNone);
	test(map.Count()==4);
	test(map.Find(i)==NULL);
	map.Close();
}

void TestPtrHashMaps()
	{	

	test.Next(_L("Test RHashMap of default pointer types"));
	TInt i[5];
	TInt *ptr=i;
	RHashMap<TInt*,TInt> mp;
	TestHashMapPtr(mp, ptr, i);

	TInt32 i1[5];
	TInt32 *ptr1=i1;
	RHashMap<TInt32*,TInt32> mp1;
	TestHashMapPtr(mp1,ptr1,i1);
	
	TUint i2[5];
	TUint *ptr2=i2;
	RHashMap<TUint*,TUint> mp2;
	TestHashMapPtr(mp2,ptr2,i2);

	TUint32 i3[5];
	TUint32 *ptr3=i3;
	RHashMap<TUint32*,TUint32> mp3;
	TestHashMapPtr(mp3,ptr3,i3);

	TBuf8<5> i4[5];
	TBuf8<5> *ptr4=i4;
	RHashMap<TDesC8*,TDesC8> mp4;
	for (ptr4=i4; ptr4 < i4+5; ptr4++) 
		{
		test(mp4.Insert(ptr4,*ptr4) == KErrNone);
		}
	for (ptr4=i4+4; ptr4 >= i4; ptr4--) 
		{
		test(*(mp4.Find(ptr4)) == *ptr4);
		}
	test(mp4.Count()==5);
	test(mp4.Remove(i4) == KErrNone);
	test(mp4.Find(i4) == NULL);
	test(mp4.Count()==4);
	mp4.Close();


	TBuf16<5> i5[5];
	TBuf16<5> *ptr5=i5;
	RHashMap<TDesC16*,TDesC16> mp5;
	for (ptr5=i5; ptr5 < i5+5; ptr5++) 
		{
		test(mp5.Insert(ptr5,*ptr5) == KErrNone);
		}
	for (ptr5=i5+4; ptr5 >= i5; ptr5--) 
		{
		test(*(mp5.Find(ptr5)) == *ptr5);
		}
	test(mp5.Count()==5);
	test(mp5.Remove(i5) == KErrNone);
	test(mp5.Find(i5) == NULL);
	test(mp5.Count()==4);
	mp5.Close();
	
}

/** Tests that Reserve() will always allocate memory for new tables 
	even for small reserve sizes
	See DEF087906.
*/
void TestSmallReserve()
	{
	test.Next(_L("Test RHashTableBase::Reserve preallocates memory, even for small no of elements"));
	RAllocator* pA = 0;
	RDummyAllocator da;
	
	// Reserve should allocate the memory required for the table of 1 element
	INTSET(set);
	RHashMap<TInt,TInt> hashMap;
	
	test(set.Reserve(1) == KErrNone);
	test(hashMap.Reserve(1) == KErrNone);
	
	pA = User::SwitchAllocator(&da);
	
	// No more memory should be allocated for the table as it should
	// have been already allocated by Reserve()
	test(set.Insert(123) == KErrNone);
	test(hashMap.Insert(123,456) == KErrNone);
	
	// Switch back to allow set to be closed
	User::SwitchAllocator(pA);
	set.Close();
	hashMap.Close();
	}
	

TInt E32Main()
	{
	test.Title();

	test(HAL::Get(HAL::ENanoTickPeriod, NanoTickPeriod)==KErrNone);
	test.Printf(_L("NanoTickPeriod %dus\n"), NanoTickPeriod);

	__UHEAP_MARK;

	test.Start(_L("Testing hash tables"));

	TestHash();
	TestStringHash();
	TestWStringHash();
	TestIntegerPtrHash();
	TestDes8PtrHash();
	TestDes16PtrHash();

	TestHashSet();
	TestHashIter();
	TestHashMap();
	TestPtrHashMaps();

	PopulateArray8(4096);
	PopulateArray16(4096);
	TestPtrHashSet();
	TestPtrHashMap();
	DesC16Array.ResetAndDestroy();
	DesC8Array.ResetAndDestroy();


	TestOOM();
	Benchmark();
	TestSmallReserve();

	test.End();

	__UHEAP_MARKEND;
	return 0;
	}
