mirror of
https://github.com/ksherlock/profuse.git
synced 2025-03-30 19:34:14 +00:00
Untested bitmap enhancements
git-svn-id: https://profuse.googlecode.com/svn/trunk@59 aa027e90-d47c-11dd-86d7-074df07e0730
This commit is contained in:
parent
4360263a1a
commit
dd0703bd09
183
Bitmap.cpp
183
Bitmap.cpp
@ -4,15 +4,58 @@
|
||||
|
||||
namespace ProDOS {
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
// returns # of 1-bits set (0-8)
|
||||
inline static unsigned popCount(uint8_t x)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
return __builtin_popcount(x);
|
||||
#endif
|
||||
|
||||
// Brian Kernighan / Peter Wegner in CACM 3 (1960), 322.
|
||||
|
||||
unsigned count;
|
||||
for (count = 0; x; ++count)
|
||||
{
|
||||
x &= x - 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
inline static unsigned countLeadingZeros(uint8_t x)
|
||||
{
|
||||
if (x == 0) return sizeof(uint8_t);
|
||||
#ifdef __GNUC__
|
||||
return __builtin_clz(x) + sizeof(uint8_t) - sizeof(unsigned);
|
||||
#endif
|
||||
|
||||
unsigned rv = 0;
|
||||
if ((x & 0xf0) == 0) { x <<= 4; rv = 4; }
|
||||
if (x & 0x80) return rv;
|
||||
if (x & 0x40) return rv + 1;
|
||||
if (x & 0x20) return rv + 2;
|
||||
if (x & 0x10) return rv + 3;
|
||||
// unreachable
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline static unsigned countLeadingOnes(uint8_t x)
|
||||
{
|
||||
return countLeadingZeros(~x);
|
||||
}
|
||||
|
||||
Bitmap::Bitmap(unsigned blocks) :
|
||||
_bitmap(NULL), _blocks(blocks),
|
||||
_bitmapSize((blocks + 4096 - 1) >> 12)
|
||||
_blocks(blocks),
|
||||
_freeBlocks(blocks),
|
||||
_bitmapSize((blocks + 4096 - 1) >> 12),
|
||||
_bitmap(NULL)
|
||||
{
|
||||
// 1 block = 512 bytes = 4096 bits
|
||||
_bitmap = new uint8_t[_bitmapSize];
|
||||
@ -55,12 +98,146 @@ bool Bitmap::markBlock(unsigned block, bool inUse)
|
||||
unsigned mask = BlockMask(block);
|
||||
uint8_t data = _bitmap[index];
|
||||
|
||||
_freeBlocks -= popCount(data);
|
||||
|
||||
if (inUse) data &= ~mask;
|
||||
else data |= mask;
|
||||
|
||||
_bitmap[index] = data;
|
||||
|
||||
_freeBlocks += popCount(data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// find the first block starting from (and including) the
|
||||
// startingBlock
|
||||
|
||||
int Bitmap::firstFreeBlock(unsigned startingBlock) const
|
||||
{
|
||||
if (startingBlock >= _blocks) return -1;
|
||||
if (!_freeBlocks) return -1;
|
||||
|
||||
unsigned index = BlockIndex(startingBlock);
|
||||
unsigned bit = startingBlock & 0x0f;
|
||||
unsigned bytes = (_blocks + 7) >> 3;
|
||||
|
||||
// special case for first (partial) bitmap
|
||||
if (bit != 0)
|
||||
{
|
||||
uint8_t data = _bitmap[index];
|
||||
unsigned mask = BlockMask(startingBlock);
|
||||
// 0 0 1 0 0 0 0 0 -> 0 0 1 1 1 1 1 1
|
||||
mask = (mask - 1) | mask;
|
||||
data &= mask;
|
||||
if (data) return (index << 3) + countLeadingZeros(data);
|
||||
++index;
|
||||
}
|
||||
|
||||
for ( ; index < bytes; ++index)
|
||||
{
|
||||
uint8_t data = _bitmap[index];
|
||||
if (!data) continue;
|
||||
|
||||
return (index << 3) + countLeadingZeros(data);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// count the number of unused blocks.... (including startingBlock)
|
||||
int Bitmap::countUnusedBlocks(unsigned startingBlock, unsigned maxSearch) const
|
||||
{
|
||||
if (startingBlock >= _blocks) return -1;
|
||||
if (!_freeBlocks) return -1;
|
||||
|
||||
unsigned count = 0;
|
||||
|
||||
unsigned index = BlockIndex(startingBlock);
|
||||
unsigned bit = startingBlock & 0x0f;
|
||||
|
||||
unsigned bytes = (_blocks + 7) >> 3;
|
||||
|
||||
|
||||
// special case for the first (partial) byte.
|
||||
if (bit)
|
||||
{
|
||||
uint8_t data = _bitmap[index];
|
||||
if (data == 0) return 0;
|
||||
unsigned mask = BlockMask(startingBlock);
|
||||
// 0 0 1 0 0 0 0 0 -> 1 1 0 0 0 0 0 0
|
||||
mask = ~ ((mask - 1) | mask);
|
||||
data = data | mask;
|
||||
|
||||
if (data == 0xff)
|
||||
{
|
||||
count = 8 - bit;
|
||||
if (count >= maxSearch) return count;
|
||||
++index;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return countLeadingOnes(data) - bit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
for ( ; index < bytes; ++index)
|
||||
{
|
||||
uint8_t data = _bitmap[index];
|
||||
|
||||
// no free blocks = end search
|
||||
if (data == 0) break;
|
||||
|
||||
// all free = continue (if necessary)
|
||||
if (data == 0xff)
|
||||
{
|
||||
count += 8;
|
||||
if (count >= maxSearch) break;
|
||||
continue;
|
||||
}
|
||||
|
||||
// otherwise, add on any leading free and terminate.
|
||||
count += countLeadingOnes(data);
|
||||
break;
|
||||
}
|
||||
|
||||
return count;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// finds the first free block (with a possible range).
|
||||
int Bitmap::freeBlock(unsigned count) const
|
||||
{
|
||||
if (count == 0 || count > freeBlocks()) return -1;
|
||||
|
||||
// we could keep a linked list/etc of
|
||||
// free ranges
|
||||
// for now, scan the entire bitmap.
|
||||
|
||||
|
||||
int startBlock = 0;
|
||||
--count;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
startBlock = firstFreeBlock(startBlock);
|
||||
if (startBlock < 0) return -1;
|
||||
|
||||
if (count == 0) return startBlock;
|
||||
|
||||
int tmp = countUnusedBlocks(startBlock + 1, count);
|
||||
if (tmp <= 0) break;
|
||||
if (tmp >= count) return startBlock;
|
||||
|
||||
// miss ... jump ahead.
|
||||
startBlock += tmp + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
17
Bitmap.h
17
Bitmap.h
@ -16,13 +16,23 @@ public:
|
||||
unsigned blocks() const;
|
||||
unsigned bitmapBlocks() const;
|
||||
|
||||
unsigned freeBlocks() const;
|
||||
|
||||
int firstFreeBlock(unsigned startingBlock = 0) const;
|
||||
int countUnusedBlocks(unsigned startingBlock = 0, unsigned maxSearch = -1) const;
|
||||
|
||||
int freeBlock(unsigned count = 1) const;
|
||||
|
||||
|
||||
private:
|
||||
static unsigned BlockMask(unsigned block);
|
||||
static unsigned BlockIndex(unsigned block);
|
||||
|
||||
uint8_t *_bitmap;
|
||||
unsigned _blocks;
|
||||
unsigned _freeBlocks;
|
||||
unsigned _bitmapSize;
|
||||
uint8_t *_bitmap;
|
||||
|
||||
};
|
||||
|
||||
inline unsigned Bitmap::blocks() const
|
||||
@ -30,6 +40,11 @@ inline unsigned Bitmap::blocks() const
|
||||
return _blocks;
|
||||
}
|
||||
|
||||
inline unsigned Bitmap::freeBlocks() const
|
||||
{
|
||||
return _blocks;
|
||||
}
|
||||
|
||||
inline unsigned Bitmap::bitmapBlocks() const
|
||||
{
|
||||
return _bitmapSize >> 12;
|
||||
|
Loading…
x
Reference in New Issue
Block a user