persistentstorage/dbms/pcdbms/utable/UT_WIN.CPP
changeset 0 08ec8eefde2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/dbms/pcdbms/utable/UT_WIN.CPP	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,337 @@
+// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "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:
+//
+
+#include "UT_STD.H"
+
+// Class CDbBasicWindowStage
+
+CDbBasicWindowStage::CDbBasicWindowStage(const TDbWindow& aWindow)
+	: iWindow(aWindow), iRecords(EWindowArrayGranularity), iPos(-1)
+	{
+	__ASSERT(aWindow.Size()!=aWindow.ENone);
+	}
+
+TBool CDbBasicWindowStage::GetRecord(TDbRecordId& aRecordId)
+	{
+	if (TUint(iPos)>=TUint(iRecords.Count()))
+		return EFalse;
+	aRecordId=iRecords[iPos];
+	return ETrue;
+	}
+
+void CDbBasicWindowStage::Reset()
+//
+// Reset the window to initial state
+//
+	{
+	CDbDataStage::Reset();
+	iRecords.Reset();
+	iPos=-1;
+	}
+
+TBool CDbBasicWindowStage::EvaluateL(TInt& aWork,TDbRecordId& aRecordId,TBool& aAtRow)
+//
+// Do as much work as we can to make the window match the desired shape
+//
+	{
+	TBool eval=CDbDataStage::EvaluateL(aWork,aRecordId,aAtRow);
+	if (!eval)
+		{
+		eval=DoEvaluateL(aWork);
+		aAtRow=GetRecord(aRecordId);
+		}
+	return eval;
+	}
+
+TInt CDbBasicWindowStage::CountL()
+//
+// Window'd views only report the evaluated records
+//
+	{
+	return iRecords.Count();
+	}
+
+CDbBasicWindowStage::TGoto CDbBasicWindowStage::GotoL(TInt& /*aWork*/,TDbPosition aPosition,TDbRecordId& aRecordId)
+	{
+	switch (aPosition)
+		{
+	default:
+		__ASSERT(0);
+		break;
+	case EDbFirst:
+		iPos=0;
+		break;
+	case EDbLast:
+		iPos=iRecords.Count()-1;
+		break;
+	case EDbNext:
+		++iPos;
+		break;
+	case EDbPrevious:
+		--iPos;
+		break;
+		}
+	return GetRecord(aRecordId) ? ESuccess : ENoRow;
+	}
+
+TInt CDbBasicWindowStage::Find(TDbRecordId aRecordId,TInt& aPos)
+	{
+	TKeyArrayFix key(0,ECmpTUint32);
+	return iRecords.Find(aRecordId,key,aPos);
+	}
+
+TBool CDbBasicWindowStage::GotoL(TDbRecordId aRecordId)
+	{
+	return Find(aRecordId,iPos)==0;
+	}
+
+void CDbBasicWindowStage::ReadRowL(TDbRecordId aRecordId)
+	{
+	TRAPD(r,CDbDataStage::ReadRowL(aRecordId));
+	if (r==KErrNotFound)
+		{
+		TInt pos;
+		if (Find(aRecordId,pos)==KErrNone)
+			{
+			iRecords.Delete(pos);
+			if (pos<iPos)
+				--iPos;
+			}
+		}
+	__LEAVE_IF_ERROR(r);
+	}
+
+TDbRecordId CDbBasicWindowStage::WriteRowL(TWrite aWrite,TSynch aSynch)
+	{
+	TDbRecordId id=CDbDataStage::WriteRowL(aWrite,ENoSynch);
+	if (aWrite==EAppend && iWindow.Size()==iWindow.EUnlimited)
+		{
+		iRecords.AppendL(id);
+		if (aSynch==ESynch)
+			iPos=iRecords.Count()-1;	// follow the append
+		}
+	return id;
+	}
+
+CDbBasicWindowStage::TDelete CDbBasicWindowStage::DeleteRowL(TDbRecordId& aRecordId,TSynch)
+//
+// Remove the row from the window if it is present
+//
+	{
+	CDbDataStage::DeleteRowL(aRecordId,ENoSynch);
+	if (GotoL(aRecordId))
+		{
+		iRecords.Delete(iPos);
+		if (GetRecord(aRecordId))
+			return EDeletedAtNext;
+		}
+	return EDeletedAtEnd;
+	}
+
+// Class CDbWindowStage
+
+CDbWindowStage::CDbWindowStage(const TDbWindow& aWindow)
+	: CDbBasicWindowStage(aWindow), iIterPos(EAtBeginning), iView(EBeginning)
+	{}
+
+void CDbWindowStage::Reset()
+//
+// Reset the window to initial state
+//
+	{
+	CDbBasicWindowStage::Reset();
+	iIterPos=EAtBeginning;
+	iView=EBeginning;
+	}
+
+TInt CDbWindowStage::WhatToEvaluate()
+//
+// count of slots to fill, <0 at beginning, >0 at end. 0 none
+//
+	{
+	if (iView==EAll)
+		return 0;
+	if (iWindow.Size()==iWindow.EUnlimited)
+		return KMaxTInt;
+	TInt space=iWindow.Size()-iRecords.Count();
+	TInt lag=iPos-iWindow.PreferredPos();
+	switch (iView)
+		{
+	default:
+		__ASSERT(0);
+	case EBeginning:
+		return space+Max(lag,0);	// fill up and use forward lag if any
+	case EEnd:
+		return Min(lag,0)-space;	// fill up backwards and use rear lag if any
+	case EMiddle:
+		if (lag<0 && iIterPos==EAtBeginning)	// use iterator position if we can
+			return lag;
+		if (space+lag>0)
+			return space+lag;
+		if (lag<0)
+			return lag;
+		return 0;
+		}
+	}
+
+TDbPosition CDbWindowStage::ResetIterToBeginningL()
+	{
+	for (TInt ii=iRecords.Count();--ii>=0;)
+		{
+		if (CDbDataStage::GotoL(iRecords[0]))
+			return EDbPrevious;
+// has been deleted, try the next one
+		iRecords.Delete(0);
+		if (iPos>0)
+			--iPos;
+		}
+// no records to work with, start at the end
+	return EDbLast;
+	}
+
+TDbPosition CDbWindowStage::ResetIterToEndL()
+	{
+	for (TInt ii=iRecords.Count();--ii>=0;)
+		{
+		if (CDbDataStage::GotoL(iRecords[ii]))
+			return EDbNext;
+// has been deleted, try the next one
+		iRecords.Delete(ii);
+		if (iPos>ii)
+			--iPos;
+		}
+// no records to work with, start at the beginning
+	return EDbFirst;
+	}
+
+TDbPosition CDbWindowStage::SetIteratorL(TInt anEval)
+//
+// Set the iterator for some work and return the first iterator direction
+//
+	{
+	switch (iIterPos)
+		{
+	default:
+		__ASSERT(0);
+	case EAtBeginning:
+		if (anEval<0)
+			return EDbPrevious;
+// turn around iterator to work at end
+		iIterPos=EAtEnd;
+		return ResetIterToEndL();
+	case EAtEnd:
+		if (anEval>0)
+			return EDbNext;
+// turn around iterator to work at beginning
+		iIterPos=EAtBeginning;
+		return ResetIterToBeginningL();
+		}
+	}
+
+void CDbWindowStage::ExtendAtBeginningL(TInt aRecords,TDbPosition aFirst,TInt& aWork)
+	{
+	TDbRecordId id=iRecords.Count()>0 ? iRecords[0] : KDbNullRecordId;
+	while (aRecords>0)
+		{
+		switch (CDbDataStage::GotoL(aWork,aFirst,id))
+			{
+		default:
+			__ASSERT(0);
+		case EExhausted:
+			return;
+		case ESuccess:
+			if (iRecords.Count()==iWindow.Size())
+				{	// drop last record
+				iRecords.Delete(iRecords.Count()-1);
+				if (iView==EEnd)
+					iView=EMiddle;
+				}
+			iRecords.InsertL(0,id);
+			++iPos;
+			if (aFirst==EDbLast)
+				aFirst=EDbPrevious;
+			--aRecords;
+			break;
+		case ENoRow:	// no more data that way
+			iView=iView==EEnd ? EAll : EBeginning;
+			return;
+		case ESynchFailure:	// have to do some work on the iterator now
+			aFirst=ResetIterToBeginningL();
+			break;
+			}
+		}
+	}
+
+void CDbWindowStage::ExtendAtEndL(TInt aRecords,TDbPosition aFirst,TInt& aWork)
+	{
+	TDbRecordId id=iRecords.Count()>0 ? iRecords[iRecords.Count()-1] : KDbNullRecordId;
+	while (aRecords>0)
+		{
+		switch (CDbDataStage::GotoL(aWork,aFirst,id))
+			{
+		default:
+			__ASSERT(0);
+		case EExhausted:
+			return;
+		case ESuccess:
+			if (iRecords.Count()==iWindow.Size())
+				{	// drop first record
+				iRecords.Delete(0);
+				--iPos;
+				if (iView==EBeginning)
+					iView=EMiddle;
+				}
+			iRecords.AppendL(id);
+			if (aFirst==EDbFirst)
+				aFirst=EDbNext;
+			--aRecords;
+			break;
+		case ENoRow:
+			iView=iView==EBeginning ? EAll : EEnd;
+			return;
+		case ESynchFailure:
+			aFirst=ResetIterToEndL();
+			break;
+			}
+		}
+	}
+
+TBool CDbWindowStage::DoEvaluateL(TInt& aWork)
+//
+// Do as much work as we can to make the window match the desired shape
+//
+	{
+	for (;;)
+		{
+		TInt eval=WhatToEvaluate();
+		if (eval==0)
+			return EFalse;
+		if (aWork<=0)
+			return ETrue;
+		TDbPosition dir=SetIteratorL(eval);
+		if (eval>0)
+			ExtendAtEndL(eval,dir,aWork);
+		else
+			ExtendAtBeginningL(-eval,dir,aWork);
+		}
+	}
+
+TBool CDbWindowStage::Unevaluated()
+//
+// Return whether it is worth Evaluating
+//
+	{
+	return WhatToEvaluate()==0 ? CDbDataStage::Unevaluated() : ETrue;
+	}