mirror of
https://github.com/ksherlock/profuse.git
synced 2024-12-25 23:33:15 +00:00
197 lines
3.9 KiB
C++
197 lines
3.9 KiB
C++
#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;
|
|
} |