kernel/eka/euser/cbase/ub_obj.cpp
changeset 9 96e5fb8b040d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/euser/cbase/ub_obj.cpp	Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,1516 @@
+// Copyright (c) 1994-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:
+// e32\euser\cbase\ub_obj.cpp
+// 
+//
+
+#include "ub_std.h"
+
+const TInt KObjectIxGranularity=8;
+const TInt KObjectConMinSize=8;		// must be power of 2 or 3*power of 2
+const TInt KObjectConIxGranularity=4;
+const TInt KObjectIndexMask=0x7fff;
+const TInt KObjectMaxIndex=0x7fff;
+const TInt KObjectInstanceShift=16;
+const TInt KObjectInstanceMask=0x3fff; 
+const TInt KObjectUniqueIDShift=16;
+const TInt KObjectUniqueIDMask=0xffff;
+const TInt KObjectIxMaxHandles=0x8000;
+const TInt KObjectConIxMaxSize=0x10000-1;
+
+inline TInt index(TInt aHandle)
+	{return(aHandle&KObjectIndexMask);}
+inline TInt instance(TInt aHandle)
+	{return((aHandle>>KObjectInstanceShift)&KObjectInstanceMask);}
+inline TInt instanceLimit(TInt& aCount)
+	{return ((aCount&KObjectInstanceMask)==0) ? ((++aCount)&KObjectInstanceMask) : aCount&KObjectInstanceMask;}
+inline TInt makeHandle(TInt anIndex,TInt anInstance)
+	{return((TInt)((anInstance<<KObjectInstanceShift)|anIndex));}
+
+inline TInt uniqueID(TInt aHandle)
+	{return((aHandle>>KObjectUniqueIDShift)&KObjectUniqueIDMask);}
+inline TInt makeFindHandle(TInt anIndex,TInt anUniqueID)
+	{return((TInt)((anUniqueID<<KObjectUniqueIDShift)|anIndex));}
+
+/**
+@internalComponent
+*/
+enum {ENotOwnerID};
+
+LOCAL_C void makeFullName(TFullName &aFullName,const CObject *anOwner,const TDesC &aName)
+//
+// Make a name from its owner name and aName.
+//
+	{
+
+	aFullName.Zero();
+	if (anOwner)
+		{
+        makeFullName(aFullName,anOwner->Owner(),anOwner->Name());
+		aFullName+=_L("::");
+		}
+	aFullName+=aName;
+	}
+
+
+
+
+/**
+Constructs the object and initializes the reference count to one. 
+
+Once constructed, a reference counting object cannot be deleted until its 
+reference count is reduced to zero. 
+
+@see CObject::Close
+*/
+EXPORT_C CObject::CObject()
+	{
+
+//	iContainer=NULL;
+//	iOwner=NULL;
+//	iName=NULL;
+	iAccessCount=1;
+	}
+
+
+
+
+/**
+Destructor.
+
+It removes this reference counting object from its object container,
+a CObjectCon type.
+
+@panic E32USER-CBase 33 if the reference count is not zero when
+       the destructor is called.
+
+@see CObjectCon
+*/
+EXPORT_C CObject::~CObject()
+	{
+
+	__ASSERT_ALWAYS(AccessCount()==0,Panic(EObjObjectStillReferenced));
+	User::Free(iName);
+	if (iContainer)
+		{
+		CObjectCon *p=iContainer;
+		iContainer=NULL;
+		p->Remove(this);
+		}
+	}
+
+
+
+
+/**
+Opens this reference counting object.
+
+The default behaviour increments the reference count by one and
+returns KErrNone. 
+Where a derived class implements its own version of this function, it must 
+either use the protected member function Inc() to increment the reference 
+count or make a base call to this function.
+
+@return KErrNone.
+*/
+EXPORT_C TInt CObject::Open()
+	{
+
+	Inc();
+	return(KErrNone);
+	}
+
+
+
+
+/**
+Closes this reference counting object.
+
+The default behaviour decrements the reference count by one. If this becomes 
+zero, then the function deletes this reference counting object.
+
+Where a derived class implements its own version of this function, it can 
+use the protected member function Dec() to decrement the reference count or 
+make a base call to this function.
+
+@panic E32USER-CBase 34 if the reference count is negative when this
+       function is called.
+*/
+EXPORT_C void CObject::Close()
+	{
+
+	Dec();
+	__ASSERT_ALWAYS(AccessCount()>=0,Panic(EObjNegativeAccessCount));
+	if (AccessCount()==0)
+		delete this;
+	}
+
+
+
+
+LOCAL_C TName GetLocalObjectName(const CObject *anObj)
+	{
+	TName n=_L("Local-");
+	n.AppendNumFixedWidth((TInt)anObj,EHex,8);
+	return n;
+	}
+
+
+
+
+/**
+Gets the name of this reference counting object.
+
+The default behaviour provided by this function depends on whether a name 
+has been explicitly set into the object:
+
+if a name has previously been set, then the function returns that name.
+
+if a name has not been set, then the function builds a default name. This 
+is fourteen characters and has the format: LOCAL-nnnnnnnn where nnnnnnnn is 
+the hexadecimal character representation of this reference counting object's 
+address. This default name is, therefore, guaranteed to be unique within the 
+current process.
+
+@return A modifiable buffer descriptor with a defined maximum length containing 
+        the name of this reference counting object.
+*/
+EXPORT_C TName CObject::Name() const
+	{
+	if (iName)
+		return(*iName);
+	return GetLocalObjectName(this);
+	}
+
+
+
+
+/**
+Gets the full name of this reference counting object.
+
+By default, the full name is a concatenation of this reference counting
+object's name with the full name of its owning reference counting object.
+
+@return A modifiable buffer descriptor with a defined maximum length containing 
+        the full name of this reference counting object.
+*/
+EXPORT_C TFullName CObject::FullName() const
+	{
+
+	TFullName n;
+	makeFullName(n,Owner(),Name());
+	return(n);
+	}
+
+
+
+
+/**
+Sets or clears this reference counting object's name.
+
+To set the name, the specified descriptor must contain the name to be set. 
+Once the name has been successfully set, then the specified source descriptor 
+can be discarded.
+
+To clear an existing name, specify a NULL argument.
+
+@param aName A pointer to the descriptor containing the name to be set, or 
+             NULL if an existing name is to be cleared.
+
+@return KErrNone, if the function is successful;
+        KerrNoMemory, if there is insufficient memory available.
+
+@panic USER 11 if the length of aName is greater than KMaxName
+       for a 16-bit descriptor.
+@panic USER 23 if the length of aName is greater than KMaxName
+       for an 8-bit descriptor.
+*/
+EXPORT_C TInt CObject::SetName(const TDesC *aName)
+	{
+
+	User::Free(iName);
+	iName=NULL;
+	if (aName!=NULL)
+		{
+		iName=aName->Alloc();
+		if (iName==NULL)
+			return(KErrNoMemory);
+		}
+	return(KErrNone);
+	}
+
+
+
+
+/**
+Sets or clears this reference counting object's name, and leaves on error.
+
+To set the name, the specified descriptor must contain the name to be set. 
+Once the name has been successfully set, then the specified source descriptor 
+can be discarded.
+
+To clear an existing name, specify a NULL argument.
+
+The function leaves if there is insufficient memory.
+
+@param aName A pointer to the descriptor containing the name to be set, or 
+             NULL if an existing name is to be cleared.
+
+@panic USER 11 if the length of aName is greater than KMaxName
+       for a 16-bit descriptor.
+@panic USER 23 if the length of aName is greater than KMaxName
+       for an 8-bit descriptor.
+*/
+EXPORT_C void CObject::SetNameL(const TDesC *aName)
+	{
+
+	User::Free(iName);
+	iName=NULL;
+	if (aName!=NULL)
+		iName=aName->AllocL();
+	}
+
+
+
+
+/**
+Extension function
+
+
+*/
+EXPORT_C TInt CObject::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
+	{
+	return CBase::Extension_(aExtensionId, a0, a1);
+	}
+
+
+
+
+/**
+Creates a new object index.
+
+@return A pointer to the newly created object index.
+*/
+EXPORT_C CObjectIx* CObjectIx::NewL()
+	{
+
+	return new(ELeave) CObjectIx;
+	}
+
+
+
+
+/**
+Default constructor.
+*/
+EXPORT_C CObjectIx::CObjectIx()
+	: iNextInstance(1), iFree(-1)
+	{
+	}
+
+
+
+
+/**
+Destructor.
+
+Frees all resources owned by the object index, prior to its destruction.
+In particular, it calls Close() on all reference counting objects in the index.
+
+@see CObject::Close
+*/
+EXPORT_C CObjectIx::~CObjectIx()
+	{
+	// We have to be very careful here. Calling Close() on the objects in the array
+	// may result in other entries being removed from the array before we delete
+	// them here, and may result in the array being ReAlloc()ed, corrupting the removed
+	// entries, hence we must check the iHighWaterMark value each time round the loop.
+	TInt i=-1;
+	while(++i<iHighWaterMark)
+		{
+		SObjectIxRec* pS=iObjects+i;
+		CObject *pO=pS->obj;
+		if (pO)
+			{
+			pO->Close();
+			pS->obj=NULL;	// invalidate entry after closing it
+			}
+		}
+	delete iObjects;
+	}
+
+
+
+/**
+Adds the specified reference counting object into this object index and
+returns the handle number that represents it.
+
+@param anObj The reference counting object to be added to this object index.
+
+@return The handle number.
+*/
+EXPORT_C TInt CObjectIx::AddL(CObject* anObj)
+	{
+	TInt index=iFree; //iFree contains the index of the first empty slot or -1 if there is no such.
+	if (index<0) //Check if the free list is empty
+		{
+		// The free list is empty, so more slots must be allocated.
+		if (iHighWaterMark==KObjectIxMaxHandles)
+ 			User::LeaveNoMemory();
+		
+		//Those are internal checking of the object consistency
+		__ASSERT_DEBUG(iAllocated==iHighWaterMark,Panic(EObjInconsistent));
+		__ASSERT_DEBUG(iAllocated==iNumEntries,Panic(EObjInconsistent));
+		
+		//Double allocated memory
+		TInt newAlloc=iAllocated ? 2*iAllocated : KObjectIxGranularity;
+		if(newAlloc>KObjectIxMaxHandles)
+ 			newAlloc=KObjectIxMaxHandles;
+		SObjectIxRec* pA=(SObjectIxRec*)User::ReAllocL(iObjects, newAlloc*sizeof(SObjectIxRec));
+		iObjects=pA;
+
+		//NOTE: There is no need to initialize newly allocated memory (e.g. to zero iObjects) as it all goes
+		//beyond HWM and will be not considered when search in At(...) or operator[]() methods. 
+		//As the free list is initially ordered, each slot must go to the states as follows:
+		//-Created as the part of the free list beyond HWM. - uninitialized and not searched in any method.
+		//-In use  - initialized.
+		//-The part of the free list within HWM - initialized to zero.
+		//Also, UpdateState() does not reorder free list beyond HWM but keep it preserverd.
+
+		iAllocated=newAlloc;					//Update the number of allocated slots
+		iUpdateDisabled = iAllocated/2;//The number of Remove() calls before the object update (free list, HWM,...)
+
+		//Connect all newly allocated slots into the list and set 'index' to point to the first one.
+		index=newAlloc-1;
+		pA[index].nextEmpty = -1;
+		while (iHighWaterMark <= --index) 
+			pA[index].nextEmpty=index+1;
+		index++;
+		}
+
+	//At this point, 'index' variable points to the slot that will be used for the new entry.
+	//It also represents the first element in the list of empty slots.
+
+	SObjectIxRec *pS=iObjects+index; // pS points to the object that will be used for the new entry.
+	iFree=pS->nextEmpty;			 // Update iFree to point to the next empty slot. 
+	
+	//Initialize data of the new element of the array.
+	pS->obj=anObj;
+	pS->str.uniqueID=(TUint16)anObj->UniqueID();
+	pS->str.instance=(TUint16)instanceLimit(iNextInstance);
+	
+	iNextInstance++;
+	
+	if (index>=iHighWaterMark)	//Update HWM to points to the slot after the last in use.
+		iHighWaterMark=index+1;
+	
+	++iNumEntries;
+
+	__ASSERT_DEBUG( (iFree==-1 && iAllocated==iHighWaterMark && iAllocated==iNumEntries)
+				  ||(iFree!=-1 && iAllocated>iNumEntries),Panic(EObjInconsistent));
+	
+	return(makeHandle(index,pS->str.instance)); //Create and return the handle
+	}
+
+
+
+
+/**
+Removes the reference counting object identified by handle number from this 
+object index and closes it.
+
+If the reference counting object cannot be closed, because CObjectIx::ENoClose 
+is ORed into the handle number, then it is neither removed from the object 
+index nor closed.
+
+@param aHandle The handle number of the reference counting object to be removed 
+               and closed.
+               
+@panic E32USER-CBase 37 if aHandle does not represent an object known to this
+                        object index.
+*/
+EXPORT_C void CObjectIx::Remove(TInt aHandle)
+	{
+	if (aHandle&ENoClose)
+		return;
+	TInt i=index(aHandle);
+	__ASSERT_ALWAYS(i<iHighWaterMark,Panic(EObjRemoveBadHandle));
+	SObjectIxRec* pR=iObjects+i;
+	CObject *pO=pR->obj;
+	if (!pO || pR->str.instance!=instance(aHandle) || pR->str.uniqueID!=pO->UniqueID())
+		Panic(EObjRemoveBadHandle);
+	pO->Close();
+	pR->obj=NULL;
+
+	if(--iNumEntries)
+		{	
+		// Add the entry onto the free list
+		pR->nextEmpty=iFree;
+		iFree=i;
+
+		if(iUpdateDisabled) 
+			iUpdateDisabled--; //Count down till state update is enabled again.
+
+		if (									 //Update the states(HWM, resort free list & memory shrink) if:
+			(!iUpdateDisabled) &&				 //There were a number of Remove() calls since the last ReAlloc
+			(iAllocated>=2*KObjectIxGranularity))//Allocated memory is above the limit.
+			{
+			UpdateState();
+			iUpdateDisabled = iAllocated/2;//The number of Remove() calls before the next update comes.
+			}
+		}
+	else
+		{
+		//There is no any CObject left. Reset the object to initial state (except iNextInstance)
+		delete iObjects;
+		iObjects=NULL;
+		iAllocated=0;
+		iHighWaterMark=0;
+		iFree=-1;		  //Empty free list
+		}
+
+	//This is internal checking of the object consistency
+	__ASSERT_DEBUG( (iFree==-1 && iAllocated==iHighWaterMark && iAllocated==iNumEntries)
+				  ||(iFree!=-1 && iAllocated>iNumEntries),Panic(EObjInconsistent));
+	}
+
+
+//1. Reorder free list.
+//2. Update iHighWaterMark. This is the only place where HWM is decreased, while it can be increased during AddL().
+//3. Shrinks the heap memory (pointed by iObjects) if it can be at least halved.
+//The function is entered with at least one occupied slot in iObjects array.
+//The array is searched from its end. Special care is given to the  case where
+//HWM is less then KObjectIxGranularity as the size of the arrey does not go below it.
+void CObjectIx::UpdateState()
+	{
+	TBool toShrink = EFalse;
+	TBool foundFreeBelowLimit = EFalse;//Used to handle spacial case when HWM is below the minimum alloc. limit
+	TInt newHWM = 0;
+
+	//Start from the HWM as all slots beyond are free and sorted already.
+	TInt current = iHighWaterMark;
+	TInt prevFreeSlot = iHighWaterMark == iAllocated ? -1 : iHighWaterMark;
+	while (--current>=0)
+		{
+		if (iObjects[current].obj)
+			{
+			//This is the slot with the valid entry. Check if this is the last in the array.
+			if(!newHWM)
+				{
+				//This is the first occupied slot we found => It is new HWM.
+				newHWM=current+1;
+				if (current < iAllocated/2)
+					{
+					//At this point we decide to shrink memory.
+					toShrink = ETrue;
+					//Once we find HWM and decide to shrink, all slots after that point should be removed
+					//from the free list as that memory will be freed. The exception is the case when HWM is below
+					//the minimum of allocated memory (8 slots as the moment).
+					if((current >= KObjectIxGranularity) || (!foundFreeBelowLimit))
+						prevFreeSlot = -1; //The next free slot to find will be the last one in the list.
+					}
+				}
+			}
+		else
+			{
+			//This is the free slot.
+			if ((!newHWM) && (!foundFreeBelowLimit) &&(current<KObjectIxGranularity))
+				{
+				//The special case. 
+				//We just reached the first free slot below minimum alloc. size and still we found no occupied slots.
+				iObjects[current].nextEmpty = -1; //This will be the end of free list.
+				foundFreeBelowLimit = ETrue; //Mark that we found the special case
+				}
+			else
+				{
+				iObjects[current].nextEmpty = prevFreeSlot;//Link the empty slot in the free list.
+				}
+			prevFreeSlot = current;
+			}
+		}
+
+	iHighWaterMark = newHWM;
+	iFree = prevFreeSlot;
+
+	if (toShrink)
+		{
+		//Do not reallocate less then the initial value.
+		iAllocated = Max(newHWM,KObjectIxGranularity);
+		//Update member data and re-allocate memory. ReAlloc cannot return NULL as we are asking for less memory.
+		iObjects=(SObjectIxRec*)User::ReAlloc(iObjects,iAllocated*sizeof(SObjectIxRec));
+		}
+	}
+
+
+
+/**
+Gets the number of occurrences of the specified reference counting object
+within this object index.
+
+Note that the same reference counting object can be added to an object index 
+more than once.
+
+@param anObject The reference counting object.
+
+@return The number of occurrences.
+*/
+EXPORT_C TInt CObjectIx::Count(CObject* anObject) const
+	{
+
+	TInt n=0;
+	if (iHighWaterMark)
+		{
+		SObjectIxRec* pS=iObjects;
+		SObjectIxRec* pE=pS+iHighWaterMark;
+		do
+			{
+			if (pS->obj==anObject)
+				n++;
+			} while (++pS<pE);
+		}
+	return n;
+	}
+
+
+
+
+#ifndef __COBJECT_MACHINE_CODED__
+/**
+Gets a pointer to the reference counting object with the specified handle
+number and matching unique ID.
+
+@param aHandle   The handle number of the reference counting object.
+@param aUniqueID The unique ID.
+
+@return A pointer to the reference counting object. If there is no matching 
+        object, then this is NULL.
+*/
+EXPORT_C CObject *CObjectIx::At(TInt aHandle,TInt aUniqueID)
+	{
+	TInt i=index(aHandle);
+	if (i>=iHighWaterMark)
+		return NULL;
+	SObjectIxRec *pS=iObjects+i;
+	if (pS->str.instance!=instance(aHandle) || pS->str.uniqueID!=aUniqueID)
+		return NULL;
+	return pS->obj;
+	}
+
+
+
+
+/**
+Gets a pointer to the reference counting object with the specified
+handle number.
+
+@param aHandle The handle number of the reference counting object.
+
+@return A pointer to the reference counting object. If there is no matching 
+        object, then this is NULL.
+*/
+EXPORT_C CObject *CObjectIx::At(TInt aHandle)
+	{
+	TInt i=index(aHandle);
+	if (i>=iHighWaterMark)
+		return NULL;
+	SObjectIxRec *pS=iObjects+i;
+	if (pS->str.instance!=instance(aHandle))
+		return NULL;
+	return pS->obj;
+	}
+#endif
+
+
+
+
+
+/**
+Constructs and returns the handle number representing the specified reference 
+counting object within this object index.
+	
+@param anObj The reference counting object.
+
+@return The handle number representing the reference counting object;
+        KErrNotFound, if the reference counting object could not be found
+        within the object index.
+*/
+EXPORT_C TInt CObjectIx::At(const CObject* anObj) const
+	{
+
+	if (iHighWaterMark)
+		{
+		SObjectIxRec* pS=iObjects;
+		SObjectIxRec* pE=pS+iHighWaterMark;
+		TInt i=0;
+		while(pS<pE && pS->obj!=anObj)
+			pS++, i++;
+		if (pS<pE)
+			return(makeHandle(i,pS->str.instance));
+		}
+	return KErrNotFound;
+	}
+
+
+
+
+/**
+Gets a pointer to the reference counting object with the specified handle
+number and matching unique ID.
+
+@param aHandle   The handle number of the reference counting object.
+@param aUniqueID The unique ID.
+
+@return A pointer to the reference counting object.
+
+@leave KErrBadHandle if there is no matching object.
+*/
+EXPORT_C CObject *CObjectIx::AtL(TInt aHandle,TInt aUniqueID)
+	{
+
+	CObject* pO=At(aHandle,aUniqueID);
+	if (!pO)
+		User::Leave(KErrBadHandle);
+	return pO;
+	}
+
+
+
+
+/**
+Gets a pointer to the reference counting object with the specified handle
+number.
+
+@param aHandle The handle number of the reference counting object.
+
+@return A pointer to the reference counting object.
+
+@leave KErrBadHandle if there is no matching object.
+*/
+EXPORT_C CObject *CObjectIx::AtL(TInt aHandle)
+	{
+
+	CObject* pO=At(aHandle);
+	if (!pO)
+		User::Leave(KErrBadHandle);
+	return pO;
+	}
+
+
+
+
+#ifndef __COBJECT_MACHINE_CODED__
+/**
+Gets a pointer to a reference counting object located at the specified offset 
+within the object index.
+
+@param anIndex The offset of the reference counting object within the object 
+               index. Offset is relative to zero. 
+               
+@return A pointer to the reference counting object.
+
+@panic E32USER-CBase 21 if the value of anIndex is negative or is greater than
+                        or equal to the total number of objects held by
+                        the index.
+*/
+EXPORT_C CObject* CObjectIx::operator[](TInt anIndex)
+	{
+
+	__ASSERT_ALWAYS(anIndex>=0 && anIndex<iHighWaterMark,Panic(EArrayIndexOutOfRange));
+	return iObjects[anIndex].obj;
+	}
+#else
+GLDEF_C void PanicCObjectIxIndexOutOfRange(void)
+	{
+	Panic(EArrayIndexOutOfRange);
+	}
+#endif
+
+
+
+
+/**
+Creates an object container.
+
+Open code rarely, if ever, explicitly calls this function. Instead, call the 
+CreateL() member function of the container index, CObjectConIx, which uses 
+this function in its implementation.
+
+@return A pointer to the new object container.
+
+@see CObjectConIx::CreateL
+*/
+EXPORT_C CObjectCon* CObjectCon::NewL()
+	{
+
+	return new(ELeave) CObjectCon(ENotOwnerID);
+	}
+
+
+
+
+/**
+Constructor taking a unique Id. 
+
+@param aUniqueID The unique Id value.
+*/
+EXPORT_C CObjectCon::CObjectCon(TInt aUniqueID)
+	: iUniqueID(aUniqueID)
+	{
+//	iAllocated=0;
+//	iCount=0;
+//	iObjects=NULL;
+	}
+
+
+
+
+/**
+Destructor.
+
+Frees all resources owned by the object container, prior to its destruction.
+
+In particular, it destroys all contained reference counting objects.
+
+@see CObject
+*/
+EXPORT_C CObjectCon::~CObjectCon()
+	{
+
+	if (iUniqueID!=ENotOwnerID && iCount)
+		{
+		// Careful here in case deleting one object causes other objects in the array
+		// to be removed and Count to change.
+		TInt i=-1;
+		while(++i<iCount)
+			{
+			CObject* pS=iObjects[i];
+			delete pS;
+			}
+		}
+	delete iObjects;
+	}
+
+
+
+
+/**
+Adds a reference counting object to this object container.
+
+If the specified reference counting object has a name, it must be valid,
+otherwise the function leaves with KErrBadName; in addition, the reference
+counting object's full name must be unique to this object container, otherwise
+the function leaves with KErrAlreadyExists.
+
+If the specified reference counting object has no name, then the object itself 
+must be unique to the object container, i.e. the object container should not 
+already contain the same reference counting object, otherwise the function 
+leaves with KErrAlreadyExists.
+
+@param anObj A pointer to the reference counting object to be added.
+*/
+EXPORT_C void CObjectCon::AddL(CObject* anObj)
+	{
+
+	User::LeaveIfError(CheckUniqueFullName(anObj));
+	if (iCount==iAllocated)
+		{
+		TInt newAlloc;
+		if (iAllocated==0)
+			newAlloc = KObjectConMinSize;
+		else
+			{
+			// increase in sequence 8, 12, 16, 24, ... , 2^n, 3*2^n-1, ...
+			// can't get sign problems since iAllocated can't exceed 0x20000000
+			newAlloc = iAllocated + (iAllocated>>1) - ((iAllocated&(iAllocated-1))>>2);
+			}
+		iObjects=(CObject**)User::ReAllocL(iObjects, newAlloc*sizeof(CObject*));
+		iAllocated=newAlloc;
+		}
+	iObjects[iCount++]=anObj;
+	if (iUniqueID!=ENotOwnerID)
+		anObj->iContainer=this;
+	}
+
+
+
+
+/**
+Removes a reference counting object from this object container.
+
+The specified reference counting object is destroyed on removal.
+
+@param anObj A pointer to the reference counting object to be removed.
+
+@panic E32USER-CBase 35 if the reference counting object is not held by this
+                        object container.
+*/
+EXPORT_C void CObjectCon::Remove(CObject *anObj)
+	{
+	CObject** pS=iObjects;
+	CObject** pE=pS+iCount;
+	while(pS<pE)
+		{
+		if (*pS==anObj)
+			{
+			Mem::Move((TAny*)pS,(TAny*)(pS+1),TInt(pE)-TInt(pS)-sizeof(CObject*));
+			TInt used = --iCount;
+			if (used)	// if now empty, free all memory
+				{
+				if (iAllocated > KObjectConMinSize)	// don't shrink below minimum size
+					{
+					// calculate next size down
+					TInt newAlloc = iAllocated - (iAllocated>>2) - ((iAllocated&(iAllocated-1))>>3);
+
+					// shrink if half full or 64 less than next size down, whichever comes first
+					if (used <= Max(iAllocated>>1, newAlloc-64))
+						{
+						iObjects=(CObject**)User::ReAlloc(iObjects,newAlloc*sizeof(CObject*));
+						iAllocated=newAlloc;
+						}
+					}
+				}
+			else
+				{
+				delete iObjects;
+				iObjects=NULL;
+				iAllocated=0;
+				}
+			if (iUniqueID!=ENotOwnerID && anObj->iContainer)
+				{
+//
+// An object's destructor can scan the container so its best
+// to remove the object from the container before destroying it.
+//
+				anObj->iContainer=NULL;
+				delete anObj;
+				}
+			return;
+			}
+		pS++;
+		}
+	Panic(EObjRemoveObjectNotFound);
+	}
+
+
+
+
+#ifndef __COBJECT_MACHINE_CODED__
+/**
+Gets a pointer to the reference counting object located at the specified offset 
+within the object container.
+
+@param anIndex The offset of the reference counting object within the object 
+               container. Offset is relative to zero.
+
+@return A pointer to the owning reference counting object.
+
+@panic E32USER-CBase 21 if anIndex is negative or is greater than or equal to
+                        the total number of objects held by the container.
+*/
+EXPORT_C CObject *CObjectCon::operator[](TInt anIndex)
+	{
+	__ASSERT_ALWAYS(anIndex>=0 && anIndex<iCount, Panic(EArrayIndexOutOfRange));
+	return iObjects[anIndex];
+	}
+
+
+
+
+/**
+Gets a pointer to the reference counting object with the specified find-handle 
+number.
+
+A find-handle number is an integer which uniquely identifies a reference
+counting object with respect to its object container.
+
+@param aFindHandle The find-handle number of the reference counting object. 
+                   The unique Id part of this number must be the same as the
+                   unique Id of this container.
+                   The index part of the find-handle number must be
+                   a valid index. 
+
+@return A pointer to the reference counting object.
+
+@panic E32User-CBase 38 if the unique Id part of aFindHandle is not the same as
+                        the unique Id of this container.
+@panic E32User-CBase 39 if the index part of aFindHandle is negative or greater
+                        than or equal to the total number of reference counting
+                        objects held by this object container.
+*/
+EXPORT_C CObject *CObjectCon::At(TInt aFindHandle) const
+	{
+
+	__ASSERT_ALWAYS(uniqueID(aFindHandle)==iUniqueID,Panic(EObjFindBadHandle));
+	TInt ix=index(aFindHandle);
+	__ASSERT_ALWAYS(ix<iCount,Panic(EObjFindIndexOutOfRange));
+	return iObjects[ix];
+	}
+
+
+
+
+/**
+Gets a pointer to the reference counting object with the specified find-handle 
+number, and leaves on error..
+
+A find-handle number is an integer which uniquely identifies a reference
+counting object with respect to its object container.
+
+@param aFindHandle The find-handle number of the reference counting object. 
+                   The unique Id part of this number must be the same as
+                   the unique Id of this container.
+                   The index part of the find-handle number must be
+                   a valid index. 
+
+@return A pointer to the reference counting object.
+
+@leave KErrBadHandle if the unique Id part of aFindHandle is not the same as
+                     the unique Id of this container.
+@leave KErrArgument if the index part of aFindHandle is negative or greater
+                    than or equal to the total number of reference counting
+                    objects held by this object container.
+*/
+EXPORT_C CObject *CObjectCon::AtL(TInt aFindHandle) const
+	{
+
+	__ASSERT_ALWAYS(uniqueID(aFindHandle)==iUniqueID,User::Leave(KErrBadHandle));
+	TInt ix=index(aFindHandle);
+	__ASSERT_ALWAYS(ix<iCount,User::Leave(KErrArgument));
+	return iObjects[ix];
+	}
+#else
+GLDEF_C void PanicCObjectConFindBadHandle(void)
+	{
+	Panic(EObjFindBadHandle);
+	}
+
+
+
+
+
+GLDEF_C void PanicCObjectConFindIndexOutOfRange(void)
+	{
+	Panic(EObjFindIndexOutOfRange);
+	}
+
+GLDEF_C void PanicCObjectConIndexOutOfRange(void)
+	{
+	Panic(EArrayIndexOutOfRange);
+	}
+#endif
+
+
+
+
+/**
+Checks whether a specified name is a valid CObject name.
+
+A name is deemed to be invalid, if it contains any of the characters:
+"*", "?", ":" i.e. the characters: asterisk, question mark and single colon.
+
+@param aName A reference to the descriptor containing the name to be checked.
+
+@return KErrBadName, if the name is invalid. KErrNone, otherwise.
+
+@see CObject
+*/
+EXPORT_C TInt User::ValidateName(const TDesC &aName)
+	{
+#ifdef _UNICODE
+	TUint16* pName = const_cast<TUint16*>(aName.Ptr());
+#else
+	TUint8*	pName = const_cast<TUint8*>(aName.Ptr());
+#endif
+	TInt pNameLen = aName.Length();
+	for(;pNameLen;pName++,pNameLen--)
+		if(*pName>0x7e || *pName<0x20 || *pName=='*' || *pName=='?' || *pName==':')
+			return(KErrBadName);
+	return(KErrNone);
+	}
+
+
+
+
+/**
+Checks that a name will be unique.
+
+The function checks that no reference counting object exists in this object
+container with the same full name as that generated from the specified name
+and the specified owning reference counting object.
+
+This is a useful test to ensure that the name for a potential new reference
+counting object will result in a unique full name.
+
+@param anOwner A pointer to a potential owning reference counting object.
+@param aName   The name for a potential new reference counting object.
+
+@return KErrNone, if the full name does not already exist in this
+        object container;
+        KErrBadName, if the specified name is invalid;
+        KErrAlreadyExists, if a reference counting object with the same
+        fullname as the generated one already exists in this object container.
+*/
+EXPORT_C TInt CObjectCon::CheckUniqueFullName(const CObject *anOwner,const TDesC &aName) const
+	{
+
+	TInt r=User::ValidateName(aName);
+	if (r==KErrNone)
+		{
+		TFullName n;
+		makeFullName(n,anOwner,aName);
+		TFullName res;
+		TInt h=0;
+		if (FindByFullName(h,n,res)==KErrNone)
+			r=KErrAlreadyExists;
+		}
+	return(r);
+	}
+
+
+
+
+/**
+@internalComponent
+
+protected recursive function for use by CheckUniqueFullName
+*/
+TBool CObjectCon::NamesMatch(const CObject* anObject, const CObject* aCurrentObject) const
+	{
+
+	if (aCurrentObject->iName==NULL) // current object has no name, therefore not the same
+		return(EFalse);
+	if ((anObject->Name()).Compare(aCurrentObject->Name())!=0) // short names are different, therefore not the same
+		return(EFalse);
+	if ((aCurrentObject->Owner()==NULL)&&(anObject->Owner()==NULL)) // same short name, no owners = same
+		return (ETrue);
+	if ((aCurrentObject->Owner()==NULL)||(anObject->Owner()==NULL)) // one has no owner, therefore not the same
+		return(EFalse);
+	return(NamesMatch(anObject->Owner(),aCurrentObject->Owner())); // go recursive
+	}
+
+/**
+@internalComponent
+
+protected recursive function for use by CheckUniqueFullName
+*/
+TBool CObjectCon::NamesMatch(const CObject* anObject, const TName& anObjectName, const CObject* aCurrentObject) const
+	{
+
+	if (aCurrentObject->iName==NULL) // current object has no name, therefore not the same
+		return(EFalse);
+	if (anObjectName.Compare(aCurrentObject->Name())!=0) // short names are different, therefore not the same
+		return(EFalse);
+	if ((aCurrentObject->Owner()==NULL)&&(anObject->Owner()==NULL)) // same short name, no owners = same
+		return (ETrue);
+	if ((aCurrentObject->Owner()==NULL)||(anObject->Owner()==NULL)) // one has no owner, therefore not the same
+		return(EFalse);
+	return(NamesMatch(anObject->Owner(),aCurrentObject->Owner())); // go recursive
+	}
+
+
+
+
+/**
+Checks that the specified reference counting object does not already exist in 
+this object container.
+
+Uniqueness is decided by name, if the object has a name, otherwise by pointer.
+
+If the reference counting object has a name, then it is unique only if there 
+is no other reference counting object in the container with the same full 
+name.
+
+If the reference counting object has no name, then it is unique only if there 
+is no other reference counting object in the container with the same pointer.
+
+@param anObject A pointer to the reference counting object to be checked.
+
+@return KErrNone, if the reference counting object does not already exist in 
+        this object container;
+        KErrBadName, if the name of the reference counting 
+        object is invalid;
+        KErrAlreadyExists, if the reference counting object already exists.
+*/
+EXPORT_C TInt CObjectCon::CheckUniqueFullName(const CObject* anObject) const
+	{
+
+	TName name(anObject->Name());
+	TInt r=User::ValidateName(name);
+	if (r!=KErrNone)
+		return r;
+
+	if (!iCount)
+		return KErrNone;
+
+	CObject** pS=iObjects;
+	CObject** pE=pS+iCount;
+
+	// if it's name is null, just need to check it's not already there
+	if (!anObject->iName)
+		{
+		do
+			{
+			if (*pS==anObject)
+				return KErrAlreadyExists;
+			} while(++pS<pE);
+		return KErrNone;
+		}
+
+	do
+		{
+		if (NamesMatch(anObject,name,*pS))
+			return KErrAlreadyExists;
+		} while(++pS<pE);
+	return KErrNone;
+	}
+
+
+
+
+/**
+Searches for the reference counting object whose name matches the specified 
+match pattern.
+
+The search starts at the reference counting object following the one associated 
+with the specified find-handle number. If the specified find-handle number 
+is zero, then searching starts at the beginning of the object container.
+
+Notes:
+
+1. names are folded for the purpose of pattern matching
+
+2. if the specified find-handle number is non-zero, then the unique Id part of 
+   the number must be the same as the unique Id of this container.
+
+@param aFindHandle On entry, contains the find-handle number of a reference 
+                   counting object from where searching is to start, or zero.
+                   On return, if an object is found, then this is set to the
+                   find-handle number of that object; 
+                   if no object is found, then this is set to a generated
+                   number, the index part of which has the value 0x7fff.
+                   If the object container is empty, then this 
+                   reference is not changed.
+@param aMatch      The match pattern.
+@param aName       A modifiable buffer descriptor with a defined maximum 
+                   length. On return, if an object is found, then this
+                   contains the name of that object; if no object is found,
+                   then the length of this descriptor is set to zero. 
+                   If the object container is empty, then this reference is
+                   not changed.
+                   
+@return KErrNone, if a matching reference counting object is found;
+        KErrNotFound, if no matching reference counting object can be found or
+        the object container is empty.
+
+@panic E32User-CBase 38 if aFindHandle is non-zero and the unique Id part of 
+                        it is not the same as the unique Id of this container.
+*/
+EXPORT_C TInt CObjectCon::FindByName(TInt &aFindHandle,const TDesC &aMatch,TName &aName) const
+	{
+
+	if (!iCount)
+		return KErrNotFound;
+	TInt ix=0;
+	if (aFindHandle!=0)
+		{
+		__ASSERT_ALWAYS(uniqueID(aFindHandle)==iUniqueID,Panic(EObjFindBadHandle));
+		ix=index(aFindHandle)+1;
+		};
+	CObject** pS=iObjects;
+	CObject** pE=pS+iCount;
+	pS+=ix;
+	while(pS<pE)
+		{
+		aName=(*pS++)->Name();
+		if (aName.MatchF(aMatch)!=KErrNotFound)
+			{
+			aFindHandle=makeFindHandle(ix,iUniqueID);
+			return KErrNone;
+			}
+		ix++;
+		}
+	aName.Zero();
+	aFindHandle=makeFindHandle(KObjectMaxIndex,iUniqueID);
+	return KErrNotFound;
+	}
+
+
+
+
+/**
+Searches for the reference counting object whose full name matches the
+specified match pattern.
+
+The search starts at the reference counting object following the one associated 
+with the specified find-handle number. If the specified find-handle number 
+is zero, then searching starts at the beginning of the object container.
+
+Notes:
+
+1. names are folded for the purpose of pattern matching
+
+2. if the specified find-handle number is non-zero, then the unique Id part of 
+   the number must be the same as the unique Id of this container.
+
+@param aFindHandle On entry, contains the find-handle number of a reference 
+                   counting object from where searching is to start or zero.
+                   On return, if an object is found, then this is set to the
+                   find-handle number of that object; 
+                   if no object is found, then this is set to a generated
+                   number, the index part of which has the value 0x7fff.
+                   If the object container is empty, then this reference is
+                   not changed.
+@param aMatch      The match pattern.
+@param aFullName   A modifiable buffer descriptor with a defined maximum length. 
+                   On return, if an object is found, then this contains the
+                   full name of that object;
+                   if no object is found, then the length of this descriptor
+                   is set to zero.
+                   If the object container is empty, then this reference is not
+                   changed.
+                   
+@return KErrNone, if a matching reference counting object is found;
+        KErrNotFound, if no matching reference counting object can be found or
+        the object container is empty.
+
+@panic E32User-CBase 38 if aFindHandle is non-zero and the unique Id part of 
+                        it is not the same as the unique Id of this container.
+*/
+EXPORT_C TInt CObjectCon::FindByFullName(TInt &aFindHandle,const TDesC &aMatch,TFullName &aFullName) const
+	{
+
+	if (!iCount)
+		return KErrNotFound;
+	TInt ix=0;
+	if (aFindHandle!=0)
+		{
+		__ASSERT_ALWAYS(uniqueID(aFindHandle)==iUniqueID,Panic(EObjFindBadHandle));
+		ix=index(aFindHandle)+1;
+		};
+	CObject** pS=iObjects;
+	CObject** pE=pS+iCount;
+	pS+=ix;
+	while(pS<pE)
+		{
+		aFullName=(*pS++)->FullName();
+		if (aFullName.MatchF(aMatch)!=KErrNotFound)
+			{
+			aFindHandle=makeFindHandle(ix,iUniqueID);
+			return KErrNone;
+			}
+		ix++;
+		}
+	aFullName.Zero();
+	aFindHandle=makeFindHandle(KObjectMaxIndex,UniqueID());
+	return KErrNotFound;
+	}
+
+
+
+
+/**
+Creates a new container index.
+
+@return A pointer to the newly created container index.
+*/
+EXPORT_C CObjectConIx* CObjectConIx::NewL()
+	{
+
+	return new(ELeave) CObjectConIx;
+	}
+
+
+
+
+/**
+Default constructor.
+*/
+EXPORT_C CObjectConIx::CObjectConIx()
+	: iNextUniqueID(1)
+	{
+	}
+
+
+
+
+/**
+Destructor.
+
+Frees all resources owned by the container index, prior to its destruction.
+
+In particular, it destroys all of its contained object containers.
+*/
+EXPORT_C CObjectConIx::~CObjectConIx()
+	{
+	if (iCount)
+		{
+		TInt i=-1;
+		while(++i<iCount)
+			{
+			CObjectCon* pS=iContainers[i];
+			delete pS;
+			}
+		}
+	delete iContainers;
+	}
+
+
+
+
+/**
+@internalComponent
+
+Actually create the container
+*/
+EXPORT_C void CObjectConIx::CreateContainerL(CObjectCon*& aContainer)
+	{
+
+	aContainer=CObjectCon::NewL();
+	if (iUniqueIDHasWrapped)
+		{
+		// Must search for next free id
+		while (LookupByUniqueId(iNextUniqueID) != NULL)
+			{
+			++iNextUniqueID;
+			if (iNextUniqueID == 0)
+				iNextUniqueID = 1;
+			}
+		}
+	aContainer->iUniqueID=iNextUniqueID;
+	if (iCount==iAllocated)
+		{
+		TInt newAlloc=iAllocated+KObjectConIxGranularity;
+		iContainers=(CObjectCon**)User::ReAllocL(iContainers, newAlloc*sizeof(CObjectCon*));
+		iAllocated=newAlloc;
+		}
+	iContainers[iCount++]=aContainer;
+	}
+
+
+
+
+/**
+Creates a new object container and adds it into this container
+index's collection.
+
+In addition to creating the object container, the function assigns
+the next available unique ID to it.
+
+@return A pointer to the new object container.
+*/
+EXPORT_C CObjectCon* CObjectConIx::CreateL()
+	{
+
+	if (iCount == KObjectConIxMaxSize)
+		User::Leave(KErrOverflow);
+	CObjectCon* pC=NULL;
+	TRAPD(r,CreateContainerL(pC))
+	if (r!=KErrNone)
+		{
+		delete pC;
+		User::Leave(r);
+		}
+	++iNextUniqueID;
+	if (iNextUniqueID == 0)
+		{
+		iNextUniqueID = 1;
+		iUniqueIDHasWrapped = 1;
+		}
+	return pC;
+	}
+
+
+
+
+/**
+Removes the specified object container from this container index and
+deletes it.
+
+@param aCon A pointer to the object container to be removed. If the pointer is NULL,
+            the function just returns.
+
+@panic E32USER-CBASE 36 if the object container cannnot be found.
+*/
+EXPORT_C void CObjectConIx::Remove(CObjectCon* aCon)
+	{
+	if (!aCon)
+		return;
+	CObjectCon** pS=iContainers;
+	CObjectCon** pE=pS+iCount;
+	while(pS<pE)
+		{
+		if (*pS==aCon)
+			{
+			Mem::Move((TAny*)pS,(TAny*)(pS+1),TInt(pE)-TInt(pS)-sizeof(CObjectCon*));
+			TInt newAlloc=--iCount;
+			if (iCount == 0)
+				iUniqueIDHasWrapped = 0;
+			newAlloc=(newAlloc+(KObjectConIxGranularity-1))&~(KObjectConIxGranularity-1);
+			if (newAlloc!=iAllocated)
+				{
+				if (newAlloc)
+					iContainers=(CObjectCon**)User::ReAlloc(iContainers,newAlloc*sizeof(CObjectCon*));
+				else
+					{
+					delete iContainers;
+					iContainers=NULL;
+					}
+				iAllocated=newAlloc;
+				}
+			delete aCon;
+			return;
+			}
+		pS++;
+		}
+	Panic(EObjRemoveContainerNotFound);
+	}
+
+
+
+
+/**
+Gets a pointer to the object container with the specified unique ID, or NULL.
+*/
+CObjectCon* CObjectConIx::LookupByUniqueId(TInt aUniqueId) const
+	{
+	
+	CObjectCon** pS=iContainers;
+	CObjectCon** pE=pS+iCount;
+	while(pS<pE)
+		{
+		CObjectCon *pO=*pS++;
+		if (pO->iUniqueID==aUniqueId)
+			return pO;
+		}
+	return NULL;
+	}
+
+
+
+
+/**
+Gets a pointer to the object container with the unique ID from the specified
+find handle.
+
+@param aFindHandle The find handle.
+
+@return A pointer to the object container with a matching unique ID. If no 
+        matching object container can be found, then this is NULL.
+*/
+EXPORT_C CObjectCon* CObjectConIx::Lookup(TInt aFindHandle) const
+	{
+
+	return LookupByUniqueId(uniqueID(aFindHandle));
+	}
+