// Copyright (c) 1997-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_bma.cpp
//
//
#include "ub_std.h"
const TInt KBitsPerInt=32;
const TInt KBitsPerIntMask=(KBitsPerInt-1);
const TInt KBitsPerIntShift=5;
inline TInt FindLeastSignificantZero(register TUint n)
{
register TInt i=0;
n=~n;
if (n<<16==0) n>>=16, i+=16;
if (n<<24==0) n>>=8, i+=8;
if (n<<28==0) n>>=4, i+=4;
if (n<<30==0) n>>=2, i+=2;
if (n<<31==0) n>>=1, i+=1;
return i;
}
inline TInt FindLeastSignificantZero(register TUint n, TUint aFrom)
{
n |= ((1<<aFrom)-1);
return FindLeastSignificantZero(n);
}
inline TInt FindLeastSignificantOne(register TUint n)
{
register TInt i=0;
if (n<<16==0) n>>=16, i+=16;
if (n<<24==0) n>>=8, i+=8;
if (n<<28==0) n>>=4, i+=4;
if (n<<30==0) n>>=2, i+=2;
if (n<<31==0) n>>=1, i+=1;
return i;
}
inline TInt FindMostSignificantZero(register TUint n)
{
register TInt i=31;
n=~n;
if (n<0x00010000) n<<=16, i-=16;
if (n<0x01000000) n<<=8, i-=8;
if (n<0x10000000) n<<=4, i-=4;
if (n<0x40000000) n<<=2, i-=2;
if (n<0x80000000) n<<=1, i-=1;
return i;
}
EXPORT_C CBitMapAllocator::CBitMapAllocator(TInt aSize,TInt aLength)
//
// Constructor
//
: iAvail(aSize),iSize(aSize),iLength(aLength)
{
TInt rem=aSize&KBitsPerIntMask;
if (rem)
{
TInt last=(aSize-1)>>KBitsPerIntShift;
iMap[last]=0xFFFFFFFFu<<rem;
}
}
EXPORT_C CBitMapAllocator::~CBitMapAllocator()
//
// Destructor
//
{
}
EXPORT_C CBitMapAllocator *CBitMapAllocator::New(TInt aSize)
//
// Create a new bit map allocator.
//
{
__ASSERT_ALWAYS(aSize>0,Panic(EBmaSizeLessOrEqualToZero));
TInt sz=((aSize+KBitsPerIntMask)>>KBitsPerIntShift)-1;
return(new(sz*sizeof(TUint)) CBitMapAllocator(aSize,sz+1));
}
EXPORT_C CBitMapAllocator *CBitMapAllocator::NewL(TInt aSize)
//
// Create a new bit map allocator. Leave on any error.
//
{
CBitMapAllocator *pA=New(aSize);
User::LeaveIfNull(pA);
return(pA);
}
EXPORT_C TInt CBitMapAllocator::Alloc()
//
// Allocate the next position.
//
{
if (iAvail)
{
TUint *pS=iMap;
TUint *pE=pS+iLength;
do {
register TUint n=*pS++;
if (n!=0xFFFFFFFFu)
{
iAvail--;
TInt bit=FindLeastSignificantZero(n);
*--pS=n|(1<<bit);
return((TInt(pS-iMap)<<KBitsPerIntShift)+bit);
}
} while(pS<pE);
Panic(EBmaInconsistentState);
}
return(KErrNoMemory);
}
EXPORT_C TInt CBitMapAllocator::AllocFrom(TInt aPos)
//
// Allocate the next position after aPos.
//
{
__ASSERT_ALWAYS((aPos>=0 && aPos<iSize),Panic(EBmaAllocFromOutOfRange));
if (iAvail)
{
TUint *pS=iMap+(aPos>>KBitsPerIntShift);
TUint *pE=iMap+iLength;
TInt start=aPos&KBitsPerIntMask;
register TUint n;
if (start)
{
n=*pS++ | ~(0xFFFFFFFFu<<start);
if (n!=0xFFFFFFFFu)
goto found;
}
while(pS<pE)
{
n=*pS++;
if (n!=0xFFFFFFFFu)
{
found:
iAvail--;
TInt bit=FindLeastSignificantZero(n);
*--pS |= (1<<bit);
return((TInt(pS-iMap)<<KBitsPerIntShift)+bit);
}
}
}
return(KErrNoMemory);
}
EXPORT_C TInt CBitMapAllocator::AllocFromTop()
//
// Allocate the next position.
//
{
if (iAvail)
{
TUint *pS=iMap;
TUint *pE=pS+iLength;
do {
register TUint n=*--pE;
if (n!=0xFFFFFFFFu)
{
iAvail--;
TInt bit=FindMostSignificantZero(n);
*pE=n|(1<<bit);
return((TInt(pE-pS)<<KBitsPerIntShift)+bit);
}
} while(pE>pS);
Panic(EBmaInconsistentState);
}
return(KErrNoMemory);
}
EXPORT_C TInt CBitMapAllocator::AllocFromTopFrom(TInt aPos)
//
// Allocate the next position after aPos.
//
{
__ASSERT_ALWAYS((aPos>=0 && aPos<iSize),Panic(EBmaAllocFromTopFromOutOfRange));
if (iAvail)
{
TUint *pS=iMap;
TUint *pE=pS+((aPos+1)>>KBitsPerIntShift);
TInt start=(aPos+1)&KBitsPerIntMask;
register TUint n;
if (start)
{
n=*pE | (0xFFFFFFFFu<<start);
if (n!=0xFFFFFFFFu)
goto found;
}
while(pE>pS)
{
n=*--pE;
if (n!=0xFFFFFFFFu)
{
found:
iAvail--;
TInt bit=FindMostSignificantZero(n);
*pE|=(1<<bit);
return((TInt(pE-pS)<<KBitsPerIntShift)+bit);
}
}
}
return(KErrNoMemory);
}
EXPORT_C TInt CBitMapAllocator::Alloc(TInt aCount, TInt& aConsecutive)
{
__ASSERT_ALWAYS((aCount>0),Panic(EBmaAllocCountNegative));
TInt initPos;
if (iAvail)
{
TUint *pS=iMap;
TUint *pE=pS+iLength;
register TUint n;
do {
n=*pS++;
if (n!=0xFFFFFFFFu)
goto found;
} while(pS<pE);
Panic(EBmaInconsistentState);
found:
register TInt c;
pS--;
TInt bit=FindLeastSignificantZero(n);
initPos=(TInt(pS-iMap)<<KBitsPerIntShift)+bit;
n>>=bit;
if (n)
{
c=FindLeastSignificantOne(n);
if (aCount<c) c=aCount;
*pS |= ~(0xFFFFFFFFu<<c)<<bit;
iAvail-=c;
aConsecutive=c;
return initPos;
}
c=KBitsPerInt-bit;
if (c>=aCount)
{
c=aCount;
if (c<KBitsPerInt)
*pS |= ~(0xFFFFFFFFu<<c)<<bit;
else
*pS |= 0xFFFFFFFFu<<bit;
iAvail-=c;
aConsecutive=c;
return initPos;
}
c=aCount-c;
*pS=0xFFFFFFFFu;
while(++pS<pE && (n=*pS)==0 && c>=KBitsPerInt)
*pS=0xFFFFFFFFu, c-=KBitsPerInt;
if (c && pS<pE && n!=0xFFFFFFFFu)
{
bit=n?FindLeastSignificantOne(n):KBitsPerInt;
if (bit>c) bit=c;
*pS |= ~(0xFFFFFFFFu<<bit);
c-=bit;
}
aConsecutive=aCount-c;
iAvail-=aConsecutive;
return initPos;
}
aConsecutive=0;
return KErrNoMemory;
}
LOCAL_D const TUint AlignedSearchMask[] =
{0x00000000,0xAAAAAAAA,0xEEEEEEEE,0xFEFEFEFE,0xFFFEFFFE};
EXPORT_C TInt CBitMapAllocator::AllocAligned(TInt anAlignment)
{
__ASSERT_ALWAYS((anAlignment>=0 && anAlignment<32),Panic(EBmaAllAlgnOutOfRange));
if (iAvail==0)
return KErrNoMemory;
TUint mask;
TInt step;
if (anAlignment>=KBitsPerIntShift)
{
mask=0xFFFFFFFEu;
step=1<<(anAlignment-KBitsPerIntShift);
}
else
{
mask=AlignedSearchMask[anAlignment];
step=1;
}
TUint *pM=iMap;
TUint *pE=pM+iLength;
do {
register TUint n=*pM | mask;
if (n!=0xFFFFFFFFu)
{
iAvail--;
TInt bit=(mask==0xFFFFFFFEu)?0:FindLeastSignificantZero(n);
*pM |= (1<<bit);
return((TInt(pM-iMap)<<KBitsPerIntShift)+bit);
}
pM+=step;
} while(pM<pE);
return KErrNoMemory;
}
EXPORT_C TInt CBitMapAllocator::AllocAlignedBlock(TInt anAlignment)
{
__ASSERT_ALWAYS((anAlignment>=0 && anAlignment<32),Panic(EBmaAllAlgnBOutOfRange));
if (iAvail==0)
return KErrNoMemory;
TInt blocksz=1<<anAlignment;
TUint mask;
TUint block;
TInt step;
if (anAlignment>=KBitsPerIntShift)
{
mask=0xFFFFFFFEu;
step=1<<(anAlignment-KBitsPerIntShift);
block=0xFFFFFFFFu;
}
else
{
mask=AlignedSearchMask[anAlignment];
step=1;
block=~(0xFFFFFFFFu<<blocksz);
}
TUint *pM=iMap;
TUint *pE=pM+iLength;
do {
register TUint n=*pM | mask;
if (n!=0xFFFFFFFFu)
{
if (blocksz>=KBitsPerInt)
{
n=0;
TUint *pS=pM+step;
if (pS<=pE)
{
do n|=*pM++; while(pM<pS);
pM-=step;
if (n==0)
{
iAvail-=blocksz;
do *pM++=0xFFFFFFFFu; while(pM<pS);
pM-=step;
return (TInt(pM-iMap)<<KBitsPerIntShift);
}
}
}
else
{
TInt bit=FindLeastSignificantZero(n);
mask=block<<bit;
n=*pM;
do {
if ((n&mask)==0)
{
*pM |= mask;
iAvail-=blocksz;
return((TInt(pM-iMap)<<KBitsPerIntShift)+bit);
}
bit+=blocksz;
mask<<=blocksz;
} while(mask);
}
}
pM+=step;
} while(pM<pE);
return KErrNoMemory;
}
EXPORT_C void CBitMapAllocator::AllocAt(TInt aPos)
//
// Allocate a required position.
//
{
__ASSERT_ALWAYS(aPos>=0 && aPos<iSize,Panic(EBmaAllocOutOfRange));
TUint *pM=iMap+(aPos>>KBitsPerIntShift);
TUint mask=1<<(aPos&KBitsPerIntMask);
__ASSERT_ALWAYS(!(*pM&mask),Panic(EBmaAllocAtAlreadyAllocated));
*pM |= mask;
iAvail--;
}
EXPORT_C void CBitMapAllocator::AllocAt(TInt aPos, TInt aCount)
{
__ASSERT_ALWAYS((aPos>=0 && (aPos+aCount)<=iSize),Panic(EBmaAllocBlkOutOfRange));
TUint *pM=iMap+(aPos>>KBitsPerIntShift);
TInt c=aPos&KBitsPerIntMask;
TUint m;
if (aCount<(KBitsPerInt-c))
{
m=~(0xFFFFFFFFu<<aCount)<<c;
if (*pM & m)
Panic(EBmaAllocBlkNotFree);
*pM |= m;
iAvail-=aCount;
return;
}
m=0xFFFFFFFFu<<c;
if (*pM & m)
Panic(EBmaAllocBlkNotFree);
*pM++ |= m;
c=aCount-KBitsPerInt+c;
while(c>=KBitsPerInt)
{
if (*pM)
Panic(EBmaAllocBlkNotFree);
*pM++=0xFFFFFFFFu;
c-=KBitsPerInt;
}
if (c)
{
m=0xFFFFFFFFu>>(KBitsPerInt-c);
if (*pM & m)
Panic(EBmaAllocBlkNotFree);
*pM++ |= m;
}
iAvail-=aCount;
}
EXPORT_C TInt CBitMapAllocator::ExtractRamPages(TInt aConsecutive,TInt& aPageNo)
{
if(iAvail<aConsecutive)
return KErrNoMemory;
TUint *pS=iMap;
TUint *pE=pS+iLength;
do {
register TUint n=*pS++;
if (n!=0xFFFFFFFFu)
{
TInt x = 0;
do
{
TInt bit=FindLeastSignificantZero(n,x);
TInt pos=(TInt((pS-1)-iMap)<<KBitsPerIntShift)+bit;
if(pos+aConsecutive > iSize)
return KErrNoMemory;
if(IsFree(pos,aConsecutive))
{
AllocAt(pos,aConsecutive);
aPageNo=pos;
return KErrNone;
}
else
{
x = bit+2;
}
}
while (x < KBitsPerInt);
}
} while(pS<pE);
return KErrNoMemory;
}
EXPORT_C TBool CBitMapAllocator::IsFree(TInt aPos)
//
// Check a required position is available
//
{
__ASSERT_ALWAYS(aPos>=0 && aPos<iSize,Panic(EBmaFreeOutOfRange));
TUint n=iMap[aPos>>KBitsPerIntShift];
return !(n>>(aPos&KBitsPerIntMask)&1);
}
EXPORT_C TBool CBitMapAllocator::IsFree(TInt aPos, TInt aCount)
{
__ASSERT_ALWAYS((aPos>=0 && (aPos+aCount)<=iSize),Panic(EBmaChkBlkOutOfRange));
TUint *pM=iMap+(aPos>>KBitsPerIntShift);
TUint m=*pM++;
TInt c=aPos&KBitsPerIntMask;
m>>=c;
if (aCount<(KBitsPerInt-c))
{
return !(m&~(0xFFFFFFFFu<<aCount));
}
aCount-=(KBitsPerInt-c);
while(aCount>=KBitsPerInt)
{
m |= *pM++;
aCount-=KBitsPerInt;
}
if (aCount)
{
m|=(*pM<<(KBitsPerInt-aCount));
}
return(!m);
}
EXPORT_C void CBitMapAllocator::Free(TInt aPos)
//
// Free a position.
//
{
__ASSERT_ALWAYS(aPos>=0 && aPos<iSize,Panic(EBmaFreeOutOfRange));
TUint *pM=iMap+(aPos>>KBitsPerIntShift);
TUint mask=1<<(aPos&KBitsPerIntMask);
__ASSERT_ALWAYS((*pM&mask),Panic(EBmaFreeNotAllocated));
*pM &= ~mask;
iAvail++;
}
EXPORT_C void CBitMapAllocator::Free(TInt aPos, TInt aCount)
{
__ASSERT_ALWAYS((aPos>=0 && (aPos+aCount)<=iSize),Panic(EBmaFreeBlkOutOfRange));
TUint *pM=iMap+(aPos>>KBitsPerIntShift);
TInt c=aPos&KBitsPerIntMask;
TUint m;
if (aCount<(KBitsPerInt-c))
{
m=~(0xFFFFFFFFu<<aCount)<<c;
if ((*pM & m)!=m)
Panic(EBmaFreeBlkNotAllocated);
*pM &= ~m;
iAvail+=aCount;
return;
}
m=0xFFFFFFFFu<<c;
if ((*pM & m)!=m)
Panic(EBmaFreeBlkNotAllocated);
*pM++ &= ~m;
c=aCount-KBitsPerInt+c;
while(c>=KBitsPerInt)
{
if (*pM!=0xFFFFFFFF)
Panic(EBmaFreeBlkNotAllocated);
*pM++=0;
c-=KBitsPerInt;
}
if (c)
{
m=0xFFFFFFFFu>>(KBitsPerInt-c);
if ((*pM & m)!=m)
Panic(EBmaFreeBlkNotAllocated);
*pM++ &= ~m;
}
iAvail+=aCount;
}
EXPORT_C TInt CBitMapAllocator::Avail()
//
// Get the available blocks count.
//
{
return(iAvail);
}
EXPORT_C TInt CBitMapAllocator::Size()
//
// Get the size of all available blocks.
//
{
return(iSize);
}