fbs/fontandbitmapserver/sfbs/FbsRalc.cpp
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fbs/fontandbitmapserver/sfbs/FbsRalc.cpp	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,370 @@
+// Copyright (c) 2006-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:
+// This file holds the class methods for the Rom Address Lookup Cache feature
+// of FBServ: CFbsRalCacheEl, CFbsRalCache.
+// 
+//
+
+#include "FbsRalc.h"
+#include <e32svr.h>
+
+
+// ============================================================================
+
+/**
+Destructor of CFbsRalCacheEl objects releasing memory used by attributes.
+@internalComponent 
+@post		Object state undefined.
+*/
+CFbsRalCacheEl::~CFbsRalCacheEl()
+	{
+	User::Free(iFilename);
+	iFilename = 0;
+	}
+
+/**
+Default constructor for CFbsRalCacheEl objects.
+@internalComponent 
+@post		CFbsRalCacheEl initialised with a null mapping information.
+*/
+CFbsRalCacheEl::CFbsRalCacheEl() 
+: CBase(), iFilename(0), iAddress(0)
+	{
+	}
+
+/**
+Constructor for constructing TFbsRalCacheEl objects with valid 
+mapping information.
+@internalComponent 
+@param		aFilename full name of the file to store
+@param		aMemAddr ROM memory address file starts at
+@post		TFbsRalCacheEl initialised with the filename and memory address 
+supplied.
+@panic		EEmptyFilename panic generated when no chars in name
+@panic		EInvalidRomAddress panic generated when address out of range
+*/
+CFbsRalCacheEl* 
+CFbsRalCacheEl::New(
+	const TDesC& aFilename,
+	TAny* aMemAddr
+)
+	{
+	// Allocate memory for new cache element object and construct.
+	CFbsRalCacheEl* ptr = new CFbsRalCacheEl;
+	if (!ptr)
+		return 0;
+
+	// Initialise attributes of cache element.
+	ptr->iFilename = HBufC::New(aFilename.Length());
+	if (!ptr->iFilename)
+		{
+		User::Free(ptr);
+		return 0;
+		}
+	*(ptr->iFilename) = aFilename;
+	ptr->iAddress = aMemAddr;
+#ifdef _RALC_DEBUG
+	ptr->iHitCount = 1;
+#endif //_RALC_DEBUG
+
+	// Done, return address to caller.
+	return ptr;
+	}
+
+/**
+This routine is used by callers to release the memory directly used for the 
+CFbsRalCacheEl object specified WITHOUT destroying the object first. Users
+wishing to destroy the object can do so by calling the destructory directly. 
+This is necessary since new/delete are not used for objects of this class as
+out of memory panics must be avoided.
+Therefore this routine must be used with caution to avoid memory leaks! 
+@internalComponent 
+@param		aThisRef Ptr to object to free. Ptr set to 0 on exit
+*/
+void
+CFbsRalCacheEl::FreeOnly(
+	CFbsRalCacheEl*& aThisRef
+)
+	{
+	User::Free (aThisRef);
+	aThisRef = 0;
+	}
+
+/**
+An optimised routine for checking the filename in the entry matches that
+supplied to the routine. It compares filenames in a right to left fashion
+since most differences in filenames are in the last 16 characters or so.
+ASCII characters are compared in a case insensitive fashion.
+@internalComponent 
+@param		aSearchKey filename to compare entry with
+@return		ETrue if entry matches search key, EFalse otherwise.
+*/
+TBool
+CFbsRalCacheEl::MatchKey(
+	const TDesC& aSearchKey
+)
+	{
+	if (!iFilename)
+		return EFalse;
+
+	// Check both filename descriptors are the same length
+	TInt charIndex = iFilename->Length();	
+	if (charIndex != aSearchKey.Length())
+		return EFalse;
+	
+	// Then check every character is the same by comparing right to left.
+	while (charIndex)
+		{
+		charIndex--;
+		if (ToLower((*iFilename)[charIndex]) != ToLower(aSearchKey[charIndex]))
+			return EFalse;
+		}
+
+	// If we reach here we know the entry matches what we are looking for.
+	return ETrue;
+	}
+
+TInt CFbsRalCacheEl::ToLower(TInt aInt)
+	{
+	return (0x40 < aInt && 0x5B > aInt) ? (aInt + 0x20) : aInt;
+	}
+
+// ============================================================================
+
+/**
+Destructor of CFbsRalCache objects by resetting the circular buffer.
+@internalComponent 
+@post		Object state undefined.
+*/
+CFbsRalCache::~CFbsRalCache()
+	{
+#ifdef _RALC_DEBUG
+	RDebug::Print(_L("FBS RALCache destructed for process:%x\n"),(TUint)iProcId);
+	PrintCache();
+#endif //_RALC_DEBUG
+
+	while (Count())
+		DropItem();
+
+	Reset();
+	}
+
+/**
+CFbsRalCache private constructor.
+@internalComponent 
+@param		aFs valid file serve session handle used in lookups.
+@post		TFbsRalCache initialised with empty cache buffer.
+@see		Public construction achieved using static New() class method.
+*/
+CFbsRalCache::CFbsRalCache(
+	RFs& aFs
+) 
+: CCirBuf<CFbsRalCacheEl>(), iFs(aFs)
+	{
+#ifdef _RALC_DEBUG
+	RProcess current;
+	iProcId = current.Id();
+	RDebug::Print(_L("FBS RALCache constructed for process:%x\n"), 
+		(TUint)iProcId);
+#endif
+	}
+
+/**
+CFbsRalCache public constructor. This method allocates memory for a new
+object on the default heap and initialises it with the supplied data.
+@internalComponent 
+@param		aCacheSize number (fixed) of entries in the cache. 
+@param		aFs valid file serve session handle used in lookups.
+@return		Pointer to new object, otherwise 0 when error detected.
+@post		TFbsRalCache initialised with empty cache buffer.
+*/
+CFbsRalCache* 
+CFbsRalCache::New(
+	TInt aCacheSize,
+	RFs& aFs
+)
+	{
+	if (aCacheSize == 0)
+		return 0;
+
+	// Allocate memory for new cache object
+	// and call its constructor to initialise it.
+	CFbsRalCache* ptr = new CFbsRalCache(aFs);
+	if (!ptr) 
+		return 0;
+
+	// Reserve capacity in circular buffer for cache entries.
+	TRAPD(lc, ptr->SetLengthL(aCacheSize));
+	if (lc != KErrNone)
+		{
+		User::Free(ptr);
+		return 0;
+		}
+
+	// Successful, new cache created.
+	return ptr;
+	}
+
+/**
+This is the main cache lookup method for getting a file's start address
+should it be found in ROM. It first scans the cache for a match and on a hit
+it returns the stored address. On a miss it uses the file server to get
+the file's ROM address. This result if +ve is stored and the Most-recently-used
+cache, otherwise 0 is returned.
+@internalComponent 
+@param		aFileKey Full file name of file to get address for.
+@return		Start address in ROM for the file, 0 if not in ROM.
+@post		Cache updated with new entry if ROM file and not in cache.
+*/
+TAny*
+CFbsRalCache::Lookup(
+	const TDesC& aFileKey
+)
+	{
+
+	// Search the cache from the head to the tail should it have any entries
+	// based on a MRU policy.
+	if (Count())
+		{
+		TUint8* ptr = iHead;
+		for (TInt num = Count(); num; num--)
+			{
+			// Calculate the address of the entry.
+			if (ptr <= iPtr)
+				ptr = iPtrE;
+			ptr-=iSize;
+			CFbsRalCacheEl* entry = (CFbsRalCacheEl*)ptr;
+
+			// Compare the entry key with that suppled for a match and return.
+			if (entry->MatchKey(aFileKey))
+				{
+#ifdef _RALC_DEBUG
+				RDebug::Print(_L("FBS RALCache lookup HIT: %S\n"), &aFileKey);
+				entry->iHitCount++;
+#endif //_RALC_DEBUG
+				return entry->iAddress;
+				}
+			}
+		}
+
+#ifdef _RALC_DEBUG
+	RDebug::Print(_L("FBS RALCache lookup MISS: %S\n"), &aFileKey);
+#endif //_RALC_DEBUG
+
+	// Filename not in cache, ask file server for it's ROM address.
+	TAny *romAddr = iFs.IsFileInRom (aFileKey);
+	if (romAddr)
+		{
+		// Store new filename/address mapping in cache and return.
+		(void)AddItem (aFileKey, romAddr);
+		return romAddr;
+		}
+
+	// It's not a file in ROM
+	return 0;
+	}
+
+/**
+This method will create a cache entry from the supplied data and add it to the
+head of the circular cache buffer. If the cache is full this will result in the
+entry at the tail being overwritten with the new entry inserted at the head.
+@internalComponent 
+@param		aFilename full name of the file to store
+@param		aMemAddr ROM memory address file starts at
+@return		ETrue when successfully added, EFalse otherwise.
+@post		Cache updated as described above.
+*/
+TBool 
+CFbsRalCache::AddItem(
+	const TDesC& aFilename, 
+	TAny* aMemAddr
+)
+	{
+	// Construct the new cache entry from the supplied data.
+	CFbsRalCacheEl* entry = CFbsRalCacheEl::New(aFilename, aMemAddr);
+	if (!entry)
+		return EFalse;
+
+	// Make room in the cache if we need to based on MRU policy.
+	if (Count() == Length()) // Is it full?
+		DropItem();
+
+	// Add a copy of the cache entry to the circular buffer.
+	if (Add(entry) == 0)
+		{
+		// Failed, can't cache it!
+		entry->~CFbsRalCacheEl();
+		CFbsRalCacheEl::FreeOnly(entry);
+		return EFalse;
+		}
+
+	// Item now cached so clean up local entry memory only
+	CFbsRalCacheEl::FreeOnly(entry);
+	return ETrue;
+	}
+
+/**
+This method will create a cache entry from the supplied data and add it to the
+head of the circular cache buffer. If tha cache is full this will result in the
+entry at the tail being overwritten with the new entry inserted at the head.
+@internalComponent 
+@post		Cache updated as described above.
+*/
+void
+CFbsRalCache::DropItem()
+	{
+	// No items to drop from cache!?
+	if (Count() == 0)
+		return;
+
+	// Remove cache entry at tail copying into temporary variable.
+	CFbsRalCacheEl entry;
+	Remove(&entry);
+
+#ifdef _RALC_DEBUG
+	RDebug::Print(_L("FBS RALCache droped element: %S, %x, %d\n"),
+				entry.iFilename, entry.iAddress, entry.iHitCount); 
+#endif //_RALC_DEBUG
+
+	// 'entry' destroyed on exit and cleaned up.
+	}
+
+
+#ifdef _RALC_DEBUG
+void 
+CFbsRalCache::PrintCache()
+	{
+	if (Count())
+        {
+        TUint8* ptr = iHead;
+		TInt num = Count();
+		RDebug::Print(_L("FBS RALCache contents (%d):\n"), num);
+        for (; num; num--)
+            {
+            if (ptr <= iPtr)
+                ptr = iPtrE;
+            ptr-=iSize;
+            CFbsRalCacheEl* entry = (CFbsRalCacheEl*)ptr;
+			RDebug::Print(_L("FBS RALCache El %d: %S, %x, %d\n"), num, 
+				entry->iFilename, entry->iAddress, entry->iHitCount); 
+            }
+        }
+	else
+		{
+		RDebug::Print(_L("FBS RALCache emtpy.\n"));
+		}
+	}
+#endif
+
+// ==========================================================================