// Copyright (c) 1995-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\include\nkern\nklib.h
// 
// WARNING: This file contains some APIs which are internal and are subject
//          to change without notice. Such APIs should therefore not be used
//          outside the Kernel and Hardware Services package.
//

#ifndef __NKLIB_H__
#define __NKLIB_H__
#include <e32err.h>
#include <nk_cpu.h>

#ifndef __KERNEL_MODE__
#error Including kernel header in user code
#endif

#if defined(__GCC32__)




/**
@publishedPartner
@released

64-bit signed integer type.
*/
typedef long long Int64;




/**
@publishedPartner
@released
	
64-bit unsigned integer type.	
*/
typedef unsigned long long Uint64;




#elif defined(__VC32__)
typedef __int64 Int64;
typedef unsigned __int64 Uint64;
#elif defined(__CW32__)
#pragma longlong on
typedef long long Int64;
typedef unsigned long long Uint64;
#endif




/**
@publishedPartner
@released
	
Defines a 64-bit time value. 
*/
typedef Int64 TTimeK;




#if defined(__VC32__) || defined(__CW32__)
extern "C"
/** @internalComponent */
__NORETURN__ void abort();
#endif

#ifndef __PLACEMENT_NEW_INLINE
#define __PLACEMENT_NEW_INLINE
// Global placement operator new
/** @internalComponent */
inline TAny* operator new(TUint /*aSize*/, TAny* aBase) __NO_THROW
	{return aBase;}

// Global placement operator delete
/** @internalComponent */
inline void operator delete(TAny* /*aPtr*/, TAny* /*aBase*/) __NO_THROW
	{}
#endif //__PLACEMENT_NEW_INLINE

#ifndef __PLACEMENT_VEC_NEW_INLINE
#define __PLACEMENT_VEC_NEW_INLINE
// Global placement operator new[]
/** @internalComponent */
inline TAny* operator new[](TUint /*aSize*/, TAny* aBase) __NO_THROW
	{return aBase;}

// Global placement operator delete[]
/** @internalComponent */
inline void operator delete[](TAny* /*aPtr*/, TAny* /*aBase*/) __NO_THROW
	{}
#endif //__PLACEMENT_VEC_NEW_INLINE

/**
	Macro to offset a SDblQueLink pointer back to the base of a class containing it
	@publishedPartner
	@released
*/
#define _LOFF(p,T,f) ((T*)(((TUint8*)(p))-_FOFF(T,f)))

#ifdef _DEBUG

/** @internalComponent */
#define KILL_LINK_VALUE (SDblQueLink*)0xdfdfdfdf

/** @internalComponent */
#define KILL_LINK(l)	(l)->iNext=(l)->iPrev=KILL_LINK_VALUE

#else

#define KILL_LINK(l)

#endif


#ifdef __ARMCC__
#define FORCE_INLINE __forceinline
#else
#define FORCE_INLINE inline
#endif


/**
@publishedPartner
@released

An object that forms part of a doubly linked list.

SDblQueLink can also be embedded within another object so that that object
can form part of the doubly linked list.

@see SDblQue
*/
struct SDblQueLink
	{
	
#ifdef _DEBUG
    /**
    Default constructor; only defined for debug builds.
    
    It initialises the link pointers.
    */
	FORCE_INLINE SDblQueLink() {iNext=iPrev=NULL;}
#endif


    /**
    Removes this link item from the doubly linked list.
    
    @return A pointer to this link item.
    */
	FORCE_INLINE SDblQueLink* Deque()
		{
		SDblQueLink* next = iNext;
		SDblQueLink* prev = iPrev;
		next->iPrev=prev;
		prev->iNext=next;
		KILL_LINK(this);
		return this;
		}


    /**
    Inserts this link item into the list so that it precedes the specified link item.
    
    @param aL A pointer to the link item which is to follow this link item.
    */
	FORCE_INLINE void InsertBefore(SDblQueLink* aL)
		{
		SDblQueLink* prev = aL->iPrev;
		iNext=aL;
		iPrev=prev;
		prev->iNext=this;
		aL->iPrev=this;
		}
	
		
	/**
	Inserts this link item into the list so that it follows the specified link item.
    
    @param aL A pointer to the link item which is to precede this link item.
    */
	FORCE_INLINE void InsertAfter(SDblQueLink* aL)
		{
		SDblQueLink* next = aL->iNext;
		iPrev=aL;
		iNext=next;
		next->iPrev=this;
		aL->iNext=this;
		}
	
	
	/**
	Tests whether this is the only link item in the list.
	
	@return True, if this is the only link item in the list; false, otherwise.
    */
	inline TBool Alone() const
		{ return (iNext==iPrev); }
    
    
    /**
    Pointer to the next link item in the list.
    */
	SDblQueLink* iNext;
	
	/**
    Pointer to the previous link item in the list.
    */
	SDblQueLink* iPrev;
	};




/**
@publishedPartner
@released

Anchor for a doubly linked list of SDblQueLink items.

@see SDblQueLink
*/
struct SDblQue
	{
	
	
	/**
	Default constructor.
	*/
	FORCE_INLINE SDblQue()
		{ iA.iNext=iA.iPrev=&iA; }
		
	
	/**
	Moves link items from the specified list onto this list, and clears the specified list
	
	@param aQ The source linked list. This list must not be empty.
	*/	
	inline SDblQue(SDblQue* aQ, TInt)		// move entries from aQ onto this queue and clear aQ - aQ must not be empty
		{ new (this) SDblQue(*aQ); iA.iNext->iPrev=&iA; iA.iPrev->iNext=&iA; new (aQ) SDblQue; }
		
		
	/**
	Tests whether this doubly linked list is empty.
	
	@return True, if the list is empty; false, otherwise.
	*/
	FORCE_INLINE TBool IsEmpty() const
		{ return (iA.iNext==&iA); }
	
		
    /**
    Gets a pointer to the first item in this doubly linked list.
    
    @return A pointer to the first item.
    */		
	FORCE_INLINE SDblQueLink* First() const
		{ return iA.iNext; }
	
		
    /**
    Gets a pointer to the last item in this doubly linked list.
    
    @return A pointer to the last item.
    */		
	FORCE_INLINE SDblQueLink* Last() const
		{ return iA.iPrev; }
	
		
	/**
	Adds the specified link item onto the end of this doubly linked list.
	
	@param aL A pointer to the link item to be added.
	*/
	FORCE_INLINE void Add(SDblQueLink* aL)
		{
		SDblQueLink* prev = iA.iPrev;
		aL->iNext=&iA;
		aL->iPrev=prev;
		prev->iNext=aL;
		iA.iPrev=aL;
		}
	
		
	/**
	Adds the specified link item onto the front of this doubly linked list.
	
	@param aL A pointer to the link item to be added.
	*/
	FORCE_INLINE void AddHead(SDblQueLink* aL)
		{
		SDblQueLink* next = iA.iNext;
		aL->iNext=next;
		aL->iPrev=&iA;
		next->iPrev=aL;
		iA.iNext=aL;
		}
	
		
	/**
    Removes the last link item from the linked list and adds it to the front
    of the list. 
	*/
	inline void Rotate()
		{ SDblQueLink* pL=iA.iPrev; pL->Deque(); AddHead(pL); }
		
		
	/**
	Gets the first link item in the linked list.
	
	@return The first link item in the list; NULL, if the list is empty.
	*/
	inline SDblQueLink* GetFirst()
		{ if (IsEmpty()) return NULL; else return First()->Deque(); }


	/**
	Gets the last link item in the linked list.
	
	@return The last link item in the list; NULL, if the list is empty.
	*/
	inline SDblQueLink* GetLast()
		{ if (IsEmpty()) return NULL; else return Last()->Deque(); }


	/**
	Appends entries from the specified linked list onto this list, and clears
	the specified link list anchor.
	
	@param aQ The source linked list.
	*/
	inline void MoveFrom(SDblQue* aQ)	// append entries from aQ onto this queue and clear aQ
		{ if (!aQ->IsEmpty())
			{iA.iPrev->iNext=aQ->iA.iNext; aQ->iA.iNext->iPrev=iA.iPrev; iA.iPrev=aQ->iA.iPrev; iA.iPrev->iNext=&iA; new (aQ) SDblQue; }
		}


    /**
    The anchor point for the doubly linked list.
    */
	SDblQueLink iA;
	};




/**
@publishedPartner
@released

An object that forms part of a doubly linked list arranged
in descending key order.

@see SOrdQue
*/
struct SOrdQueLink : public SDblQueLink
	{
	
	
	/**
	The key value used to order the link item.
	*/
	TInt iKey;
	};




/**
@publishedPartner
@released

Anchor for a doubly linked list of SOrdQueLink items.

The items in this linked list are in descending key order.

@see SOrdQueLink
*/
struct SOrdQue : public SDblQue
	{
	
	
	/**
	Adds the specified link item into this doubly linked list so that
	the list remains in descending key order.
	
	@param aL A pointer to the link item to be added.
	*/
	inline void Add(SOrdQueLink* aL)
		{
		SOrdQueLink* pQ=(SOrdQueLink*)iA.iNext;
		TInt k=aL->iKey;
		while(pQ!=&iA && (pQ->iKey>=k)) pQ=(SOrdQueLink*)pQ->iNext;
		aL->InsertBefore(pQ);
		}
	};




/**
@publishedPartner
@released

An object that forms part of a doubly linked list arranged
in 'delta' order.

The item represents some value that is an increment, or delta,
on the value represented by a preceding element.

@see SDeltaQue
*/
struct SDeltaQueLink : public SDblQueLink
	{
	/**
	The delta value.
	*/
	TInt iDelta;
	};




/**
@publishedPartner
@released

Anchor for a doubly linked list of SDeltaQueLink items.

An item in this linked list represents a value that is an increment,
or a delta, on the value represented by a preceding element.
The list is ordered so that the head of the queue represents a nominal zero point.

@see SDeltaQueLink
*/
struct SDeltaQue : public SDblQue
	{
	
	
	/**
	Gets the delta value of the first link item in the list.

    @return The delta value.
	*/
	inline TInt FirstDelta() const
		{return ((SDeltaQueLink*)First())->iDelta;}
		
		
    /**
    Decrements the delta value of the first item in the list by the specified value.

    @param aCount The amount by which the delta value is to be reduced.

    @return True, if the resulting delta value is negative or zero;
            false, if the value is positive.
    */		
	inline TBool CountDown(TInt aCount)
		{SDeltaQueLink& l=*(SDeltaQueLink*)First(); return((l.iDelta-=aCount)<=0);}
		
	
	/**
	Adds the specified list item, having the specified 'distance' from
	the nominal zero point, into the list.

    The item is added into the list, the adjacent delta values are adjusted,
    and a suitable delta value assigned to the new item so that
    the new item is at the specified 'distance' from the nominal zero point.

    @param aL     The item to be inserted. 
    @param aDelta The 'distance' of the item from the nominal zero point.
	*/
	inline void Add(SDeltaQueLink* aL, TInt aDelta)
		{
		SDeltaQueLink* pQ=(SDeltaQueLink*)iA.iNext;
		while(pQ!=&iA && aDelta>=pQ->iDelta)
			{ aDelta-=pQ->iDelta; pQ=(SDeltaQueLink*)pQ->iNext; }
		aL->iDelta=aDelta;
		aL->InsertBefore(pQ);
		if (pQ!=&iA) pQ->iDelta-=aDelta;
		}
				
		
	/**
	Removes the specified link item from the list.
	
	The delta value of the item following the removed item is adjusted
	so that its 'distance' from the nominal zero point remains the same.
	
	@param aL The list item to be removed.
	
	@return A pointer to the item removed from the queue.
	*/
	inline SDeltaQueLink* Remove(SDeltaQueLink* aL)
		{
		if (aL->iNext!=&iA)
			{
			SDeltaQueLink& next=*(SDeltaQueLink*)aL->iNext;
			next.iDelta+=aL->iDelta;
			}
		return (SDeltaQueLink*)aL->Deque();
		}
		
		
    /**
    Removes the first item from the linked list if its delta value
    is zero or negative.
    
    @return A pointer to the item removed from the linked list.
            This is NULL, if the first element has a positive delta value,
            and has not been removed from the list.
    */		
	inline SDeltaQueLink* RemoveFirst()
		{
		SDeltaQueLink& l=*(SDeltaQueLink*)First();
		if (l.iDelta<=0)
			return Remove(&l);
		return NULL;
		}
	};




/**
@publishedPartner
@released

An object that forms part of a TPriList, priority ordered lists.

@see TPriListBase
@see TPriList
*/
class TPriListLink : public SDblQueLink
	{
public:

    
    /**
    Default constructor.
    
    Sets the priority value to zero.
    */
	inline TPriListLink() : iPriority(0) {}
	
	
    /**
    Constructor.
    
    Sets the priority to the specified value.
    
    @param aPriority The priority value.
    */
	inline TPriListLink(TInt aPriority) : iPriority((TUint8)aPriority) {}
	
	
	/**
	Tests whether this is a solitary link item.
	
	@return True, if this is a solitary link item; false, otherwise. 
	*/
	inline TBool Alone() const
		{ return (iNext==(SDblQueLink*)this); }
public:

    /** 
    The priority value.
    */
	TUint8 iPriority;
	
	/**
	Reserved for future use.
	*/
	TUint8 iSpare1;
	
		
	/**
	Reserved for future use.
	*/
	TUint8 iSpare2;
	
		
	/**
	Reserved for future use.
	*/
	TUint8 iSpare3;
	};




/**
@publishedPartner
@released

Base class for a TPriList, priority ordered lists.

@see TPriListLink
@see TPriList
*/
class TPriListBase
	{
public:
	IMPORT_C TPriListBase(TInt aNumPriorities);
	IMPORT_C TInt HighestPriority();
	IMPORT_C TPriListLink* First();
	IMPORT_C void Add(TPriListLink* aLink);
	IMPORT_C void AddHead(TPriListLink* aLink);
	IMPORT_C void Remove(TPriListLink* aLink);
	IMPORT_C void ChangePriority(TPriListLink* aLink, TInt aNewPriority);
	
	/**
	Tests whether there are any non-empty lists.
		
	@return True, if there are non-empty lists; false, if all lists are empty.
	*/
	inline TBool NonEmpty() const
		{ return iPresent[0]|iPresent[1]; }
		
	/**
	Tests whether there are any non-empty lists.
		
	@return True, if all lists are empty
	*/
	inline TBool IsEmpty() const
		{ return !iPresent[0] && !iPresent[1]; }
		
	/**
	Tests whether any linked list with priority greater than p is non-empty.

	@param p The priority value (0-63).

	@return True, if any list with priority greater than p is non-empty; false, otherwise.	
	*/
	inline TBool operator>(TInt p) const
		{ return ((p<32) ? (iPresent[1] | (iPresent[0]>>p)>>1) : (iPresent[1]>>(p-32))>>1 ); }
public:

    /**
    64-bit mask to indicate which list is non-empty.

    Bit n in the mask is set if and only if the linked list for priority n is non-empty.
    */
	union
		{
		TUint iPresent[2];
		TUint64 iPresent64;
		};
	
	/**
	Pointer to the first linked list.
	*/
	SDblQueLink* iQueue[1];
	};




template<class T, int n>
/**
@publishedPartner
@released

Anchor for a collection of doubly linked lists, where each list
corresponds to a priority value.

The lists are ordered by priority value, but items within
a list are in chronological order.

The number of lists is defined by the template integer parameter,
and each item in each list is of a class type defined by the template class parameter.
The number of lists must be between 1 and 64 inclusive.

@see TPriListLink
*/
class TPriList : public TPriListBase
	{
public:
    /**
    Constructor.
    */
	inline TPriList() : TPriListBase(n) {}
	
	
	/**
	Finds the highest priority item present on a priority list.
	If multiple items at the same priority are present, return the first to be
	added in chronological order.

	@return	a pointer to the item or NULL if the list is empty.
	*/
	inline T* First() { return (T*)TPriListBase::First(); }
private:
	SDblQueLink* iExtraQueues[n-1];
	};



/** Base for variant interface block
@internalTechnology
@prototype
*/
struct SInterfaceBlockBase
	{
	TUint32	iVer;	// version number
	TUint32	iSize;	// size in bytes
	};
#endif
