BitfieldMan: Rewrite getCompletedLength and countMissingBlockNow

Rewritten so that no memory allocation is required for these
functions.
pull/103/head
Tatsuhiro Tsujikawa 2013-07-03 22:40:28 +09:00
parent 0d85fb0df3
commit 211f685add
2 changed files with 70 additions and 50 deletions

View File

@ -516,13 +516,9 @@ size_t BitfieldMan::countMissingBlock() const {
size_t BitfieldMan::countMissingBlockNow() const { size_t BitfieldMan::countMissingBlockNow() const {
if(filterEnabled_) { if(filterEnabled_) {
array_ptr<unsigned char> temp(new unsigned char[bitfieldLength_]); return bitfield::countSetBit(filterBitfield_, blocks_) -
for(size_t i = 0; i < bitfieldLength_; ++i) { bitfield::countSetBitSlow(array(bitfield_)&array(filterBitfield_),
temp[i] = bitfield_[i]&filterBitfield_[i]; blocks_);
}
size_t count = bitfield::countSetBit(filterBitfield_, blocks_)-
bitfield::countSetBit(temp, blocks_);
return count;
} else { } else {
return blocks_-bitfield::countSetBit(bitfield_, blocks_); return blocks_-bitfield::countSetBit(bitfield_, blocks_);
} }
@ -749,36 +745,39 @@ int64_t BitfieldMan::getFilteredTotalLengthNow() const {
} }
} }
int64_t BitfieldMan::getCompletedLength(bool useFilter) const { namespace {
unsigned char* temp; template<typename Array, typename CountFun>
if(useFilter) { int64_t computeCompletedLength(const Array& bitfield,
temp = new unsigned char[bitfieldLength_]; const BitfieldMan* btman,
for(size_t i = 0; i < bitfieldLength_; ++i) { CountFun cntfun)
temp[i] = bitfield_[i]; {
if(filterEnabled_) { size_t nbits = btman->countBlock();
temp[i] &= filterBitfield_[i]; size_t completedBlocks = cntfun(bitfield, nbits);
}
}
} else {
temp = bitfield_;
}
size_t completedBlocks = bitfield::countSetBit(temp, blocks_);
int64_t completedLength = 0; int64_t completedLength = 0;
if(completedBlocks == 0) { if(completedBlocks == 0) {
completedLength = 0; completedLength = 0;
} else { } else {
if(bitfield::test(temp, blocks_, blocks_-1)) { if(bitfield::test(bitfield, nbits, nbits - 1)) {
completedLength = completedLength = ((int64_t)completedBlocks-1)*btman->getBlockLength() +
((int64_t)completedBlocks-1)*blockLength_+getLastBlockLength(); btman->getLastBlockLength();
} else { } else {
completedLength = ((int64_t)completedBlocks)*blockLength_; completedLength = ((int64_t)completedBlocks)*btman->getBlockLength();
} }
} }
if(useFilter) {
delete [] temp;
}
return completedLength; return completedLength;
} }
} // namespace
int64_t BitfieldMan::getCompletedLength(bool useFilter) const {
if(useFilter && filterEnabled_) {
auto arr = array(bitfield_)&array(filterBitfield_);
return computeCompletedLength(arr,
this,
&bitfield::countSetBitSlow<decltype(arr)>);
} else {
return computeCompletedLength(bitfield_, this, &bitfield::countSetBit);
}
}
int64_t BitfieldMan::getCompletedLengthNow() const { int64_t BitfieldMan::getCompletedLengthNow() const {
return getCompletedLength(false); return getCompletedLength(false);

View File

@ -72,9 +72,7 @@ inline bool test(const Array& bitfield, size_t nbits, size_t index)
return (bitfield[index/8]&mask) != 0; return (bitfield[index/8]&mask) != 0;
} }
inline size_t countBit32(uint32_t n) const int cntbits[] = {
{
static const int nbits[] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
@ -91,12 +89,15 @@ inline size_t countBit32(uint32_t n)
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
}; };
inline size_t countBit32(uint32_t n)
{
return return
nbits[n&0xffu]+ cntbits[n&0xffu]+
nbits[(n >> 8)&0xffu]+ cntbits[(n >> 8)&0xffu]+
nbits[(n >> 16)&0xffu]+ cntbits[(n >> 16)&0xffu]+
nbits[(n >> 24)&0xffu]; cntbits[(n >> 24)&0xffu];
} }
// Counts set bit in bitfield. // Counts set bit in bitfield.
@ -125,6 +126,26 @@ inline size_t countSetBit(const unsigned char* bitfield, size_t nbits)
return count; return count;
} }
// Counts set bit in bitfield. This is a bit slower than countSetBit
// but can accept array template expression as bitfield.
template<typename Array>
size_t countSetBitSlow(const Array& bitfield, size_t nbits)
{
if(nbits == 0) {
return 0;
}
size_t count = 0;
size_t to = (nbits+7)/8;
if(to > 1) {
for(size_t i = 0; i < to - 1; ++i) {
count += cntbits[static_cast<unsigned char>(bitfield[i])];
}
}
count +=
cntbits[static_cast<unsigned char>(bitfield[to - 1])&lastByteMask(nbits)];
return count;
}
void flipBit(unsigned char* data, size_t length, size_t bitIndex); void flipBit(unsigned char* data, size_t length, size_t bitIndex);
// Stores first set bit index of bitfield to index. bitfield contains // Stores first set bit index of bitfield to index. bitfield contains