// UB_ARRAY.CPP
//
// Copyright (c) 1994-1999 Symbian Ltd.  All rights reserved.
//

#include "ub_std.h"

struct SVarRec
	{
	TInt len;
	TAny *data;
	};

class TSwapArray : public TSwap
	{
public:
	inline TSwapArray(CBufBase *aBase,TInt aRecordLength);
	TUint8 *At(TInt anIndex) const;
	virtual void Swap(TInt aLeft,TInt aRight) const;
private:
	CBufBase *iBase;
	TInt iLength;
	};
inline TSwapArray::TSwapArray(CBufBase *aBase,TInt aRecordLength)
	: iBase(aBase),iLength(aRecordLength)
	{}

TUint8 *TSwapArray::At(TInt anIndex) const
//
// Return a pointer to the array element
//
	{
	
	return((TUint8 *)iBase->Ptr(anIndex*iLength).Ptr());
	}

void TSwapArray::Swap(TInt aLeft,TInt aRight) const
//
// Swap two elements of the array.
//
	{
	
	Mem::Swap(At(aLeft),At(aRight),iLength);
	}

EXPORT_C TKeyArrayFix::TKeyArrayFix(TInt anOffset,TKeyCmpText aType)
//
// Constructor
//
	: TKey(anOffset,aType)
	{}

EXPORT_C TKeyArrayFix::TKeyArrayFix(TInt anOffset,TKeyCmpText aType,TInt aLength)
//
// Constructor
//
	: TKey(anOffset,aType,aLength)
	{}

EXPORT_C TKeyArrayFix::TKeyArrayFix(TInt anOffset,TKeyCmpNumeric aType)
//
// Constructor
//
	: TKey(anOffset,aType)
	{}

EXPORT_C void TKeyArrayFix::Set(CBufBase *aBase,TInt aRecordLength)
//
// Set the base and record length
//
	{

	iBase=aBase;
	iRecordLength=aRecordLength;
	}

EXPORT_C TAny *TKeyArrayFix::At(TInt anIndex) const
//
// Return an address in the array.
//
	{

	if (anIndex==KIndexPtr)
		return((TUint8 *)iPtr+iKeyOffset); 			
	return((TAny *)(iBase->Ptr(anIndex*iRecordLength).Ptr()+iKeyOffset));
	}

EXPORT_C TKeyArrayVar::TKeyArrayVar(TInt anOffset,TKeyCmpText aType)
//
// Constructor
//
	: TKey(anOffset,aType)
	{}

EXPORT_C TKeyArrayVar::TKeyArrayVar(TInt anOffset,TKeyCmpText aType,TInt aLength)
//
// Constructor
//
	: TKey(anOffset,aType,aLength)
	{}

EXPORT_C TKeyArrayVar::TKeyArrayVar(TInt anOffset,TKeyCmpNumeric aType)
//
// Constructor
//
	: TKey(anOffset,aType)
	{}

EXPORT_C void TKeyArrayVar::Set(CBufBase *aBase)
//
// Set the private variable iBase to aBase.
//
	{

	iBase=aBase;
	}

EXPORT_C TAny *TKeyArrayVar::At(TInt anIndex) const
//
// Return an address in the array.
//
	{

	if (anIndex==KIndexPtr)
		return((TUint8 *)iPtr+iKeyOffset);   
	SVarRec *pV=(SVarRec *)iBase->Ptr(anIndex*sizeof(SVarRec)).Ptr();
	return(((TUint8 *)pV->data)+iKeyOffset);
	}

EXPORT_C TKeyArrayPak::TKeyArrayPak(TInt anOffset,TKeyCmpText aType)
//
// Constructor
//
	: TKeyArrayVar(anOffset,aType)
	{}

EXPORT_C TKeyArrayPak::TKeyArrayPak(TInt anOffset,TKeyCmpText aType,TInt aLength)
//
// Constructor
//
	: TKeyArrayVar(anOffset,aType,aLength)
	{}

EXPORT_C TKeyArrayPak::TKeyArrayPak(TInt anOffset,TKeyCmpNumeric aType)
//
// Constructor
//
	: TKeyArrayVar(anOffset,aType)
	{}

EXPORT_C void TKeyArrayPak::Set(CBufBase *aBase)
//
// Set the private variable iBase to aBase.
//
	{

	iBase=aBase;
	iCacheIndex=0;
	iCacheOffset=0;
	}

EXPORT_C TAny *TKeyArrayPak::At(TInt anIndex) const
//
// Return a pointer to the data in the record with index anIndex.
//
	{
//
// When anIndex is equal to KIndexPtr (HighValues) this means that we should return the address of
// the iPtr+iKeyOffset which will have been set up by the TKeyArrayPak constructor.
//
	if (anIndex==KIndexPtr)
		return((TUint8 *)iPtr+iKeyOffset); 
//
// Otherwise get the offset into the buffer of the record with index anIndex.
//
	TInt offset=0;
 	TInt curIndex=0;
	if (iCacheIndex<=anIndex)
		{
		curIndex=iCacheIndex;
		offset=iCacheOffset;
		}
	TAny *pRecord=(TAny *)iBase->Ptr(offset).Ptr();
	while (curIndex<anIndex)
		{
		TInt lenData=(*(TInt *)pRecord);
		offset+=Align4(lenData)+sizeof(TUint);
		pRecord=(TAny *)iBase->Ptr(offset).Ptr();
		curIndex++;
		}
	(TInt &)iCacheIndex=anIndex;
	(TInt &)iCacheOffset=offset;
	TAny *pData=(TAny *)((TInt *)pRecord + 1);
 	return((TUint8 *)pData+iKeyOffset);
	}

EXPORT_C CArrayFixBase::CArrayFixBase(TBufRep aRep,TInt aRecordLength,TInt aGranularity)
//
// Constructor
//
	{

	__ASSERT_ALWAYS(aRecordLength>0,Panic(EArrayFixInvalidLength));
	__ASSERT_ALWAYS(aGranularity>0,Panic(EArrayFixInvalidGranularity));
//	iCount=0;
//	iBase=NULL;
	iLength=aRecordLength;
	iGranularity=aGranularity;
	iCreateRep=aRep;
	__DECLARE_NAME(_S("CArrayFixBase"));
	}

EXPORT_C CArrayFixBase::~CArrayFixBase()
//
// Destructor
//
	{

	delete iBase;
	}

EXPORT_C void CArrayFixBase::Compress()
//
// Compress the array.
//
	{

	if (iBase)
		iBase->Compress();
	}

EXPORT_C void CArrayFixBase::Reset()
//
// Delete all records in the array.
//
	{

	iCount=0;
	if (iBase)
		iBase->Reset();
	}

EXPORT_C TInt CArrayFixBase::Sort(TKeyArrayFix &aKey)
//
// Sort the array.
//
	{

	if (iCount==0)
		return KErrNone;
	TSwapArray aSwap(iBase,iLength);
	SetKey(aKey);
	return(User::QuickSort(iCount,aKey,aSwap));
	}

EXPORT_C TAny *CArrayFixBase::At(TInt anIndex) const
//
// Index into the array.
//
	{

	__ASSERT_ALWAYS(anIndex>=0 && anIndex<iCount,Panic(EArrayIndexOutOfRange));
	return((TAny *)iBase->Ptr(anIndex*iLength).Ptr());
	}

EXPORT_C TAny *CArrayFixBase::End(TInt anIndex) const
//
// Return a pointer past contiguous elements starting at anIndex.
//
	{

	__ASSERT_ALWAYS(anIndex>=0 && anIndex<=iCount,Panic(EArrayIndexOutOfRange));
	TPtr8 p=iBase->Ptr(anIndex*iLength);
	return((TAny *)(p.Ptr()+p.Length()));
	}

EXPORT_C TAny *CArrayFixBase::Back(TInt anIndex) const
//
// Return a pointer to contiguous elements before anIndex.
//
	{

	__ASSERT_ALWAYS(anIndex>=0 && anIndex<=iCount,Panic(EArrayIndexOutOfRange));
	TPtr8 p=iBase->BackPtr(anIndex*iLength);
	return((TAny *)p.Ptr());
	}

EXPORT_C void CArrayFixBase::Delete(TInt anIndex)
//
// Delete a record from the array.
//
	{

	Delete(anIndex,1);
	}

EXPORT_C void CArrayFixBase::Delete(TInt anIndex,TInt aCount)
//
// Delete aCount records from the array.
//
	{

	if (aCount==0)
		return;
	__ASSERT_ALWAYS(aCount>0,Panic(EArrayCountNegative));
	__ASSERT_ALWAYS(anIndex>=0 && anIndex<iCount,Panic(EArrayIndexOutOfRange));
	__ASSERT_ALWAYS(anIndex+aCount<=iCount,Panic(EArrayCountTooBig));
	iBase->Delete(anIndex*iLength,aCount*iLength);
	iCount-=aCount;
	}

EXPORT_C TAny *CArrayFixBase::ExpandL(TInt anIndex)
//
// Expand the array to make room for a new record at anIndex.
//
	{

	if (iBase==NULL)
		iBase=(*iCreateRep)(iLength*iGranularity);
	__ASSERT_ALWAYS(anIndex>=0 && anIndex<=iCount,Panic(EArrayIndexOutOfRange));
	iBase->ExpandL(anIndex*iLength,iLength);
	++iCount;
	return((TAny *)iBase->Ptr(anIndex*iLength).Ptr());
	}

EXPORT_C TInt CArrayFixBase::Find(const TAny *aPtr,TKeyArrayFix &aKey,TInt &anIndex) const
//
// Find in the array using a sequential search.
//
	{

	if (iCount==0)
	    {
	    anIndex=0;
		return(-1);
		}
	aKey.SetPtr(aPtr);
	SetKey(aKey);
	TInt r=1;
	TInt i=0;
	while (i<Count())
		{
		TInt j=aKey.Compare(i,KIndexPtr);
		if (j==0)
			{
			r=j;
			break;
			}
		i++;
		}
	anIndex=i;
	return(r);
	}

EXPORT_C TInt CArrayFixBase::FindIsq(const TAny *aPtr,TKeyArrayFix &aKey,TInt &anIndex) const
//
// Find in the array using a binary search.
//
	{

	if (iCount==0)
	    {
	    anIndex=0;
		return(-1);
		}
	aKey.SetPtr(aPtr);
	SetKey(aKey);
    return(User::BinarySearch(Count(),aKey,anIndex));
	}

EXPORT_C void CArrayFixBase::InsertL(TInt anIndex,const TAny *aPtr)
//													  
// Insert a record into the array.
//
	{

	InsertL(anIndex,aPtr,1);
	}

EXPORT_C void CArrayFixBase::InsertL(TInt anIndex,const TAny *aPtr,TInt aCount)
//													  
// Insert aCount records into the array.
//
	{

	if (aCount==0)
		return;
	if (iBase==NULL)
		iBase=(*iCreateRep)(iLength*iGranularity);
	__ASSERT_ALWAYS(aCount>0,Panic(EArrayCountNegative2));
	__ASSERT_ALWAYS(anIndex>=0 && anIndex<=iCount,Panic(EArrayIndexOutOfRange));
	iBase->InsertL(anIndex*iLength,aPtr,aCount*iLength);
	iCount+=aCount;
	}

EXPORT_C void CArrayFixBase::InsertRepL(TInt anIndex,const TAny *aPtr,TInt aReplicas)
//													  
// Insert aReplicas copies  of a record into the array.
//
	{

	if (aReplicas==0)
		return;
	if (iBase==NULL)
		iBase=(*iCreateRep)(iLength*iGranularity);
	__ASSERT_ALWAYS(aReplicas>0,Panic(EArrayReplicasNegative));
	__ASSERT_ALWAYS(anIndex>=0 && anIndex<=iCount,Panic(EArrayIndexOutOfRange));
	TInt pos=anIndex*iLength;
	TInt len=aReplicas*iLength;
	iBase->ExpandL(pos,len);
	for (TInt end=pos+len;pos<end;pos+=iLength)
		iBase->Write(pos,aPtr,iLength);
	iCount+=aReplicas;
	}

EXPORT_C TInt CArrayFixBase::InsertIsqL(const TAny *aPtr,TKeyArrayFix &aKey)
//
// Insert in sequence, no duplicates allowed.
//
	{

	TInt i=0;
	TInt r=FindIsq(aPtr,aKey,i);
	if (r==0) // a duplicate, leave
		User::Leave(KErrAlreadyExists);
	InsertL(i,aPtr,1);
	return(i);
	}

EXPORT_C TInt CArrayFixBase::InsertIsqAllowDuplicatesL(const TAny *aPtr,TKeyArrayFix &aKey)
//
// Insert in sequence, allow duplicates.
//
	{

	TInt i=0;
	TInt r=FindIsq(aPtr,aKey,i);
	if (r==0) // a duplicate, insert after
		++i;
	InsertL(i,aPtr,1);
	return(i);
	}

EXPORT_C void CArrayFixBase::ResizeL(TInt aCount,const TAny *aPtr)
//
// Resize the array to contain aCount records, copying a record into any new slots.
//
	{

	__ASSERT_ALWAYS(aCount>=0,Panic(EArrayCountNegative3));
	TInt excess=iCount-aCount;
	if (excess>0)
		Delete(aCount,excess);
	else
		InsertRepL(iCount,aPtr,-excess);
	}

EXPORT_C void CArrayFixBase::SetReserveFlatL(TInt aCount) 
//
// Reserve space to contain aCount items. Only for flat arrays!
//
	{

	__ASSERT_ALWAYS(aCount>=iCount,Panic(EArrayReserveTooSmall));
	if (iBase==NULL)
		iBase=(*iCreateRep)(iLength*iGranularity);
	((CBufFlat*)iBase)->SetReserveL(iLength*aCount);		// dodgy cast. Can we assert the type?
	}

EXPORT_C void CArrayFixBase::SetKey(TKeyArrayFix &aKey) const
//
// Set the key data.
//
	{

	aKey.Set(iBase,iLength);
	}

EXPORT_C TInt CArrayFixBase::CountR(const CBase *aPtr)
//
// Return the number of items in the array.
//
	{

	return(((CArrayFixBase *)aPtr)->Count());
	}

EXPORT_C const TAny *CArrayFixBase::AtR(const CBase *aPtr,TInt anIndex)
//
// Return the address of an item in the array.
//
	{

	return(((CArrayFixBase *)aPtr)->At(anIndex));
	}

EXPORT_C CArrayVarBase::CArrayVarBase(TBufRep aRep,TInt aGranularity)
//
// Constructor
//
	{

	__ASSERT_ALWAYS(aGranularity>0,Panic(EArrayVarInvalidGranularity));
//	iCount=0;
//	iBase=NULL;
	iGranularity=aGranularity;
	iCreateRep=aRep;
	__DECLARE_NAME(_S("CArrayVarBase"));
	}

EXPORT_C CArrayVarBase::~CArrayVarBase()
//
// Destructor
//
	{

	if (iBase)
		{
		Reset();
		delete iBase;
		}
	}

EXPORT_C TInt CArrayVarBase::Length(TInt anIndex) const
//
// Return the length of an item in the array.
//
	{

	__ASSERT_ALWAYS(anIndex>=0 && anIndex<iCount,Panic(EArrayIndexOutOfRange));
	return(((SVarRec *)iBase->Ptr(anIndex*sizeof(SVarRec)).Ptr())->len);
	}

EXPORT_C void CArrayVarBase::Compress()
//
// Compress the array.
//
	{

	if (iBase)
		iBase->Compress();
	}

EXPORT_C void CArrayVarBase::Reset()
//
// Reset the contents of the array.
//
	{

	Delete(0,Count());
	}

EXPORT_C TInt CArrayVarBase::Sort(TKeyArrayVar &aKey)
//
// Sort a variable length array.
//
	{

	if (iCount==0)
		return KErrNone;
	TSwapArray aSwap(iBase,sizeof(SVarRec));
	SetKey(aKey);
	return(User::QuickSort(iCount,aKey,aSwap));
	}

EXPORT_C TAny * CArrayVarBase::At(TInt anIndex) const
//
// Return a pointer to the data in the array.
//
	{

	__ASSERT_ALWAYS(anIndex>=0 && anIndex<iCount,Panic(EArrayIndexOutOfRange));
	return(((SVarRec *)iBase->Ptr(anIndex*sizeof(SVarRec)).Ptr())->data);
	}

EXPORT_C void CArrayVarBase::Delete(TInt anIndex)
//
// Delete a record from the array.
//
	{

	Delete(anIndex,1);
	}

EXPORT_C void CArrayVarBase::Delete(TInt anIndex,TInt aCount)
//
// Delete records from the array.
//
	{

	if (aCount==0)
		return;
	__ASSERT_ALWAYS(aCount>0,Panic(EArrayCountNegative4));
	__ASSERT_ALWAYS(anIndex>=0 && anIndex<iCount,Panic(EArrayIndexOutOfRange));
	TInt end=anIndex+aCount;
	__ASSERT_ALWAYS(end<=iCount,Panic(EArrayCountTooBig));
	for (TInt i=anIndex;i<end;i++)
		{
		TPtr8 p=iBase->Ptr(i*sizeof(SVarRec));
		User::Free(((SVarRec *)p.Ptr())->data);
		}
	iBase->Delete(anIndex*sizeof(SVarRec),aCount*sizeof(SVarRec));
	iCount-=aCount;
	}

EXPORT_C TAny *CArrayVarBase::ExpandL(TInt anIndex,TInt aLength)
//
// Expand the array at anIndex.
//
	{

	if (iBase==NULL)
		iBase=(*iCreateRep)(sizeof(SVarRec)*iGranularity);
	__ASSERT_ALWAYS(aLength>=0,Panic(EArrayLengthNegative));
	__ASSERT_ALWAYS(anIndex>=0 && anIndex<=iCount,Panic(EArrayIndexOutOfRange));
	TAny *pV=User::AllocL(aLength);
	SVarRec s;
	s.data=pV;
	s.len=aLength;
	TRAPD(r,iBase->InsertL(anIndex*sizeof(SVarRec),&s,sizeof(SVarRec)));
	if (r!=KErrNone)
		{
		User::Free(pV);
		User::Leave(r);
		}
	iCount++;
	return(pV);
	}

EXPORT_C TInt CArrayVarBase::Find(const TAny *aPtr,TKeyArrayVar &aKey,TInt &anIndex) const
//
// Find using a sequential search.
//
	{

	if (iCount==0)
	    {
	    anIndex=0;
		return(-1);
		}
	aKey.SetPtr(aPtr);
	SetKey(aKey);
	TInt ret=(-1);
	TInt i=0;
	while (i<Count())
		{
		TInt j=aKey.Compare(i,KIndexPtr);
		if (j==0)
			{
			ret=j;
			break;
			}
		i++;
		}
	anIndex=i;
	return(ret);
	}

EXPORT_C TInt CArrayVarBase::FindIsq(const TAny *aPtr,TKeyArrayVar &aKey,TInt &anIndex) const
//
// Find using a binary search.
//
	{

	if (iCount==0)
	    {
	    anIndex=0;
		return(-1);
		}
	aKey.SetPtr(aPtr);
	SetKey(aKey);
	return(User::BinarySearch(Count(),aKey,anIndex));
	}

EXPORT_C void CArrayVarBase::InsertL(TInt anIndex,const TAny *aPtr,TInt aLength)
//
// Insert a new record in the array.
//
	{

	TAny *pV=ExpandL(anIndex,aLength);
    Mem::Copy(pV,aPtr,aLength);
	}

EXPORT_C TInt CArrayVarBase::InsertIsqL(const TAny *aPtr,TInt aLength,TKeyArrayVar &aKey)
//
// Insert in sequence, no duplicates allowed.
//
	{

	TInt i=0;
	TInt r=FindIsq(aPtr,aKey,i);
	if (r==0) // a duplicate, leave
		User::Leave(KErrAlreadyExists);
	InsertL(i,aPtr,aLength);
	return(i);
	}

EXPORT_C TInt CArrayVarBase::InsertIsqAllowDuplicatesL(const TAny *aPtr,TInt aLength,TKeyArrayVar &aKey)
//
// Insert in sequence, allow duplicates.
//
	{

	TInt i=0;
	TInt r=FindIsq(aPtr,aKey,i);
	if (r==0) // a duplicate, insert after
		++i;
	InsertL(i,aPtr,aLength);
	return(i);
	}

EXPORT_C void CArrayVarBase::SetKey(TKeyArrayVar &aKey) const
//
// Set the key data.
//
	{

	aKey.Set(iBase);
	}

EXPORT_C TInt CArrayVarBase::CountR(const CBase *aPtr)
//
// Return the number of items in the array.
//
	{

	return(((CArrayVarBase *)aPtr)->Count());
	}

EXPORT_C const TAny *CArrayVarBase::AtR(const CBase *aPtr,TInt anIndex)
//
// Return the address of an item in the array.
//
	{

	return(((CArrayVarBase *)aPtr)->At(anIndex));
	}

EXPORT_C CArrayPakBase::CArrayPakBase(TBufRep aRep,TInt aGranularity)
//
// Constructor
//
	{

	__ASSERT_ALWAYS(aGranularity>0,Panic(EArrayPakInvalidGranularity));
//	iCount=0;
//	iBase=NULL;
	iGranularity=aGranularity;
	iCreateRep=aRep;
	__DECLARE_NAME(_S("CArrayPakBase"));
	}

EXPORT_C CArrayPakBase::~CArrayPakBase()
//
// Destructor
//
	{

	if (iBase)
		{
		Reset();
		delete iBase;
		}
	}

EXPORT_C TInt CArrayPakBase::Length(TInt anIndex) const
//
// Return the length of the record with index anIndex;
//
	{

	__ASSERT_ALWAYS(anIndex>=0 && anIndex<iCount,Panic(EArrayIndexOutOfRange));
	return(*((TInt *)iBase->Ptr(GetOffset(anIndex)).Ptr()));
	}

EXPORT_C void CArrayPakBase::Compress()
//
// Compress the array.
//
	{

	if (iBase)
		iBase->Compress();
	}

EXPORT_C void CArrayPakBase::Reset()
//
// Reset the contents of the array.
//
	{

	Delete(0,Count());
	}

EXPORT_C void CArrayPakBase::SortL(TKeyArrayVar &aKey)
//
// Builds a transient CArrayVarFlat array, sorts it
// and then copies it back to the original array.
//
	{

	if (iCount==0)
		return;
//
// First build a variable length flat array.
//
	CArrayVarFlat<TAny> *pVarFlat=NULL;
	TRAPD(r,BuildVarArrayL(pVarFlat))
	if (r==KErrNone)
		{
//
// Now sort it.
//
		r=pVarFlat->Sort(aKey);
		if (r==KErrNone)
			{
			//
			// Delete the records and copy back from pVarFlat.
			//
 			Reset(); // Deletes the records but leaves the memory
			TInt tCount=pVarFlat->Count();
			for (TInt anIndex=0;anIndex<tCount;anIndex++)
	 			{
				TInt lenData=pVarFlat->Length(anIndex);
				TAny *pdata=pVarFlat->At(anIndex);
				TRAP(r,InsertL(anIndex,pdata,lenData));
				if (r!=KErrNone)
					break;
				}
			}
		}
	delete pVarFlat;
	User::LeaveIfError(r);
	}

EXPORT_C TAny *CArrayPakBase::At(TInt anIndex) const
//
// TAny points to the data associated with the record with anIndex.
//
	{

	__ASSERT_ALWAYS(anIndex>=0 && anIndex<iCount,Panic(EArrayIndexOutOfRange));
	TInt *pR=(TInt *)iBase->Ptr(GetOffset(anIndex)).Ptr();
 	return((TAny *)(pR+1));
	}

EXPORT_C void CArrayPakBase::Delete(TInt anIndex)
//
// Delete a record from the array.
//
	{

	Delete(anIndex,1);
	}

EXPORT_C void CArrayPakBase::Delete(TInt anIndex,TInt aCount)
//
// Delete aCount records from anIndex from the array.
//
	{

	if (aCount==0)
		return;
	__ASSERT_ALWAYS(aCount>0,Panic(EArrayCountNegative5));
	__ASSERT_ALWAYS(anIndex>=0 && anIndex<iCount,Panic(EArrayIndexOutOfRange));
	TInt end=anIndex+aCount;
	__ASSERT_ALWAYS(end<=iCount,Panic(EArrayCountTooBig));
	TInt totalToDelete=0;
	TInt firstRecOffset=0;
	for (TInt i=anIndex;i<end;i++)
		{
		TInt offset=GetOffset(i);
		if (i==anIndex)
			{
			firstRecOffset=offset;
			iCacheIndex=i;
			iCacheOffset=offset;
			}
		TAny *pRecord=(TAny *)iBase->Ptr(offset).Ptr();
		TInt lenData=(*(TInt *)pRecord);
		totalToDelete+=Align4(lenData)+sizeof(TUint);
		}
	iBase->Delete(firstRecOffset,totalToDelete);
	iCount-=aCount;
	}

EXPORT_C TAny *CArrayPakBase::ExpandL(TInt anIndex,TInt aLength)
//
// Expand the array at anIndex.
//
	{

	if (iBase==NULL)
		iBase=(*iCreateRep)(iGranularity);
	__ASSERT_ALWAYS(aLength>=0,Panic(EArrayLengthNegative));
	__ASSERT_ALWAYS(anIndex>=0 && anIndex<=iCount,Panic(EArrayIndexOutOfRange));
	TInt offset=GetOffset(anIndex);
	iCacheIndex=anIndex;
	iCacheOffset=offset;
	iBase->ExpandL(offset,Align4(aLength+sizeof(TInt)));
	TInt *pR=(TInt *)iBase->Ptr(offset).Ptr();
	*pR=aLength;
	iCount++;
 	return((TAny *)(pR+1));
	}

EXPORT_C TInt CArrayPakBase::Find(const TAny *aPtr,TKeyArrayPak &aKey,TInt &anIndex) const
//
// Find using a sequential search.
//
	{

	if (iCount==0)
	    {
	    anIndex=0;
		return(-1);
		}
	aKey.SetPtr(aPtr);
	SetKey(aKey);
	TInt ret=(-1);
	TInt i=0;
	while (i<Count())
		{
		TInt j=aKey.Compare(i,KIndexPtr);
		if (j==0)
			{
			ret=j;
			break;
			}
		i++;
		}
	anIndex=i;
	return(ret);
	}

EXPORT_C TInt CArrayPakBase::FindIsq(const TAny *aPtr,TKeyArrayPak &aKey,TInt &anIndex) const
//
// Find using a binary search.
//
	{

	if (iCount==0)
	    {
	    anIndex=0;
		return(-1);
		}
	aKey.SetPtr(aPtr);
	SetKey(aKey);
	return(User::BinarySearch(Count(),aKey,anIndex));
	}

EXPORT_C void CArrayPakBase::InsertL(TInt anIndex,const TAny *aPtr,TInt aLength)
//
// Inserts a record at index anIndex.
//
	{

	TAny *pV=ExpandL(anIndex,aLength);
    Mem::Copy(pV,aPtr,aLength);
	}

EXPORT_C TInt CArrayPakBase::InsertIsqL(const TAny *aPtr,TInt aLength,TKeyArrayPak &aKey)
//
// Insert in sequence, no duplicates allowed.
//
	{

	TInt i=0;
	TInt r=FindIsq(aPtr,aKey,i);
	if (r==0) // a duplicate, leave
		User::Leave(KErrAlreadyExists);
	InsertL(i,aPtr,aLength);
	return(i);
	}

EXPORT_C TInt CArrayPakBase::InsertIsqAllowDuplicatesL(const TAny *aPtr,TInt aLength,TKeyArrayPak &aKey)
//
// Insert in sequence, allow duplicates.
//
	{

	TInt i=0;
	TInt r=FindIsq(aPtr,aKey,i);
	if (r==0) // a duplicate, insert after
		++i;
	InsertL(i,aPtr,aLength);
	return(i);
	}

EXPORT_C void CArrayPakBase::SetKey(TKeyArrayPak &aKey) const
//
// Set the key data.
//
	{

	aKey.Set(iBase);
	}

EXPORT_C TInt CArrayPakBase::GetOffset(TInt anIndex) const
//
// Return the offset into the buffer of the record with index anIndex;
//
	{

	TInt offset=0;
 	TInt curIndex=0;
	if (iCacheIndex<=anIndex)
		{
		curIndex=iCacheIndex;
		offset=iCacheOffset;
		}
	TAny *pRecord=(TAny *)iBase->Ptr(offset).Ptr();
	while (curIndex<anIndex)
		{
		TInt lenData=(*(TInt *)pRecord);
		offset+=Align4(lenData)+sizeof(TUint);
		pRecord=(TAny *)iBase->Ptr(offset).Ptr();
		curIndex++;
		}
	(TInt &)iCacheIndex=anIndex;
	(TInt &)iCacheOffset=offset;
 	return(offset);
	}

EXPORT_C void CArrayPakBase::BuildVarArrayL(CArrayVarFlat<TAny> * &aVarFlat)
//
// Make a copy of the current array as a CArrayVarFlat
//
	{

	aVarFlat=new(ELeave) CArrayVarFlat<TAny>(iGranularity);
	for (TInt anIndex=0;anIndex<iCount;anIndex++)
		{
		TInt offset=GetOffset(anIndex);
		TAny *pRecord=(TAny *)iBase->Ptr(offset).Ptr();
		TInt lengthData=(*(TInt *)pRecord);
		TAny *pData=(TAny *)((TInt *)pRecord+1);
		aVarFlat->InsertL(anIndex,pData,lengthData);
		}
	}

EXPORT_C TInt CArrayPakBase::CountR(const CBase *aPtr)
//
// Return the number of items in the array.
//
	{

	return(((CArrayPakBase *)aPtr)->Count());
	}

EXPORT_C const TAny *CArrayPakBase::AtR(const CBase *aPtr,TInt anIndex)
//
// Return the address of an item in the array.
//
	{

	return(((CArrayPakBase *)aPtr)->At(anIndex));
	}

class CArrayFixA : public CArrayFixBase
	{
public:
	IMPORT_C CArrayFixA(TBufRep aRep,TInt aRecordLength,TInt aGranularity);
	IMPORT_C ~CArrayFixA();
	};
class CArrayFixFlatA : public CArrayFixA
	{
public:
	IMPORT_C CArrayFixFlatA(TInt aRecordLength,TInt aGranularity);
	IMPORT_C ~CArrayFixFlatA();
	};
class CArrayFixSegA : public CArrayFixA
	{
public:
	IMPORT_C CArrayFixSegA(TInt aRecordLength,TInt aGranularity);
	IMPORT_C ~CArrayFixSegA();
	};

class CArrayVarA : public CArrayVarBase
	{
public:
	IMPORT_C CArrayVarA(TBufRep aRep,TInt aGranularity);
	IMPORT_C ~CArrayVarA();
	};

class CArrayPakA : public CArrayPakBase
	{
public:
	IMPORT_C CArrayPakA(TBufRep aRep,TInt aGranularity);
	IMPORT_C ~CArrayPakA();
	};

EXPORT_C CArrayFixA::CArrayFixA(TBufRep aRep,TInt aRecordLength,TInt aGranularity)
//
// Constructor for backward compatibility
//
	: CArrayFixBase(aRep,aRecordLength,aGranularity)
	{
	}

EXPORT_C CArrayFixA::~CArrayFixA()
//
// Destructor for backward compatibility
//
	{
	}

EXPORT_C CArrayFixFlatA::CArrayFixFlatA(TInt aRecordLength,TInt aGranularity)
//
// Constructor for backward compatibility
//
	: CArrayFixA((TBufRep)CBufFlat::NewL,aRecordLength,aGranularity)
	{
	}

EXPORT_C CArrayFixFlatA::~CArrayFixFlatA()
//
// Destructor for backward compatibility
//
	{
	}

EXPORT_C CArrayFixSegA::CArrayFixSegA(TInt aRecordLength,TInt aGranularity)
//
// Constructor for backward compatibility
//
	: CArrayFixA((TBufRep)CBufSeg::NewL,aRecordLength,aGranularity)
	{
	}

EXPORT_C CArrayFixSegA::~CArrayFixSegA()
//
// Destructor for backward compatibility
//
	{
	}

EXPORT_C CArrayVarA::CArrayVarA(TBufRep aRep,TInt aGranularity)
//
// Constructor for backward compatibility
//
	: CArrayVarBase(aRep,aGranularity)
	{
	}

EXPORT_C CArrayVarA::~CArrayVarA()
//
// Destructor for backward compatibility
//
	{
	}

EXPORT_C CArrayPakA::CArrayPakA(TBufRep aRep,TInt aGranularity)
//
// Constructor for backward compatibility
//
	: CArrayPakBase(aRep,aGranularity)
	{
	}

EXPORT_C CArrayPakA::~CArrayPakA()
//
// Destructor for backward compatibility
//
	{
	}

