Pārlūkot izejas kodu

BitfieldMan: Rewrite getCompletedLength and countMissingBlockNow

Rewritten so that no memory allocation is required for these
functions.
Tatsuhiro Tsujikawa 12 gadi atpakaļ
vecāks
revīzija
211f685add
2 mainītis faili ar 70 papildinājumiem un 50 dzēšanām
  1. 27 28
      src/BitfieldMan.cc
  2. 43 22
      src/bitfield.h

+ 27 - 28
src/BitfieldMan.cc

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

+ 43 - 22
src/bitfield.h

@@ -72,31 +72,32 @@ inline bool test(const Array& bitfield, size_t nbits, size_t index)
   return (bitfield[index/8]&mask) != 0;
 }
 
+const int cntbits[] = {
+  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,
+  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+  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,
+};
+
 inline size_t countBit32(uint32_t n)
 {
-  static const int nbits[] = {
-    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,
-    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-    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,
-  };
   return
-    nbits[n&0xffu]+
-    nbits[(n >> 8)&0xffu]+
-    nbits[(n >> 16)&0xffu]+
-    nbits[(n >> 24)&0xffu];
+    cntbits[n&0xffu]+
+    cntbits[(n >> 8)&0xffu]+
+    cntbits[(n >> 16)&0xffu]+
+    cntbits[(n >> 24)&0xffu];
 }
 
 // Counts set bit in bitfield.
@@ -125,6 +126,26 @@ inline size_t countSetBit(const unsigned char* bitfield, size_t nbits)
   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);
 
 // Stores first set bit index of bitfield to index.  bitfield contains