mirror of
https://github.com/ksherlock/profuse.git
synced 2026-03-12 02:41:41 +00:00
git-svn-id: https://profuse.googlecode.com/svn/branches/v2@68 aa027e90-d47c-11dd-86d7-074df07e0730
This commit is contained in:
197
Bitmap.cpp
Normal file
197
Bitmap.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
#include "Bitmap.h"
|
||||
#include <cstring>
|
||||
|
||||
#include "auto.h"
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Bitmap::Bitmap(unsigned blocks)
|
||||
{
|
||||
_blocks = _freeBlocks = blocks;
|
||||
|
||||
_bitmapBlocks = (blocks + 4095) / 4096;
|
||||
_freeIndex = 0;
|
||||
|
||||
unsigned bitmapSize = _bitmapBlocks * 512;
|
||||
unsigned blockSize = blocks / 8;
|
||||
|
||||
auto_array bitmap(new uint8_t[bitmapSize]);
|
||||
|
||||
// mark overflow in use, everything else free.
|
||||
|
||||
std::memset(bitmap, 0xff, blocks / 8);
|
||||
std::memset(bitmap + blockSize, 0x00, bitmapSize - blockSize);
|
||||
|
||||
// edge case
|
||||
unsigned tmp = blocks & 0x07;
|
||||
|
||||
bitmap[blocks / 8] = ~(0xff >> tmp);
|
||||
|
||||
_bitmap = bitmap.release();
|
||||
|
||||
|
||||
}
|
||||
|
||||
Bitmap::Bitmap(BlockDevice *device, unsigned keyPointer, unsigned blocks)
|
||||
{
|
||||
_blocks = blocks;
|
||||
_freeBlocks = 0;
|
||||
_freeIndex = 0;
|
||||
|
||||
_bitmapBlocks = (blocks + 4095) / 4096;
|
||||
|
||||
unsigned bitmapSize = _bitmapBlocks * 512;
|
||||
unsigned blockSize = blocks / 8;
|
||||
|
||||
auto_array bitmap(new uint8_t[bitmapSize]);
|
||||
|
||||
for (unsigned i = 0; i < blockSize; ++i)
|
||||
{
|
||||
device->readBlock(keyPointer + i, bitmap + 512 * i);
|
||||
}
|
||||
|
||||
// make sure all trailing bits are marked in use.
|
||||
|
||||
// edge case
|
||||
unsigned tmp = blocks & 0x07;
|
||||
|
||||
bitmap[blocks / 8] &= ~(0xff >> tmp);
|
||||
|
||||
std::memset(bitmap + blockSize, 0x00, bitmapSize - blockSize);
|
||||
|
||||
// set _freeBlocks and _freeIndex;
|
||||
for (unsigned i = 0; i < (blocks + 7) / 8; ++i)
|
||||
{
|
||||
_freeBlocks += popCount(bitmap[i]);
|
||||
}
|
||||
|
||||
if (_freeblocks)
|
||||
{
|
||||
for (unsigned i = 0; i < (blocks + 7) / 8; ++i)
|
||||
{
|
||||
if (tmp[i])
|
||||
{
|
||||
_freeIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_bitmap = bitmap.release();
|
||||
}
|
||||
|
||||
Bitmap::~Bitmap()
|
||||
{
|
||||
if (_bitmap) delete []_bitmap;
|
||||
}
|
||||
|
||||
|
||||
void Bitmap::freeBlock(unsigned block)
|
||||
{
|
||||
if (block >= _blocks) return;
|
||||
|
||||
unsigned index = block / 8;
|
||||
unsigned offset = block & 0x07;
|
||||
unsigned mask = 0x80 >> offset;
|
||||
|
||||
uint8_t tmp = _bitmap[index];
|
||||
|
||||
if ((tmp & mask) == 0)
|
||||
{
|
||||
++_freeBlocks;
|
||||
_bitmap[index] = tmp | mask;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int Bitmap::allocBlock(unsigned block)
|
||||
{
|
||||
if (block >= _blocks) return -1;
|
||||
|
||||
|
||||
unsigned index = block / 8;
|
||||
unsigned offset = block & 0x07;
|
||||
unsigned mask = 0x80 >> offset;
|
||||
|
||||
uint8_t tmp = _bitmap[index];
|
||||
|
||||
if ((tmp & mask))
|
||||
{
|
||||
--_freeBlocks;
|
||||
_bitmap[index] = tmp & ~mask;
|
||||
return block;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int Bitmap::allocBlock()
|
||||
{
|
||||
if (!_freeBlocks) return -1;
|
||||
|
||||
unsigned firstIndex = _firstIndex;
|
||||
unsigned maxIndex = (_blocks + 7) / 8;
|
||||
|
||||
|
||||
for (unsigned index = _firstIndex; index < maxIndex; ++index)
|
||||
{
|
||||
uint8_t tmp = _bitmap[index];
|
||||
if (!tmp) continue;
|
||||
|
||||
unsigned mask = 0x80;
|
||||
for (unsigned offset = 0; offset < 8; ++offset)
|
||||
{
|
||||
if (tmp & mask)
|
||||
{
|
||||
_firstIndex = index;
|
||||
_bitmap[index] = tmp & ~mask;
|
||||
--_freeBlocks;
|
||||
return index * 8 + offset;
|
||||
}
|
||||
mask = mask >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned index = 0; index < _firstIndex; ++index)
|
||||
{
|
||||
uint8_t tmp = _bitmap[index];
|
||||
if (!tmp) continue;
|
||||
|
||||
unsigned mask = 0x80;
|
||||
for (unsigned offset = 0; offset < 8; ++offset)
|
||||
{
|
||||
if (tmp & mask)
|
||||
{
|
||||
_firstIndex = index;
|
||||
_bitmap[index] = tmp & ~mask;
|
||||
--_freeBlocks;
|
||||
return index * 8 + offset;
|
||||
}
|
||||
mask = mask >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// should never happen...
|
||||
return -1;
|
||||
}
|
||||
Reference in New Issue
Block a user