Browse Source

2009-03-28 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	BitfieldMan::getMissingIndexes family functions now takes
	unsigned char* bitfield instead of stl container for efficiency.
	PieceSelector::select now takes this
	bitfield. RarestPieceSelector::select now also performs
	efficiently for this change.  bitfield namespace is introduced
	and it has several helper functions to handle basic bitfield
	operations such as test, count set bits, etc.
	* src/BitfieldMan.cc
	* src/BitfieldMan.h
	* src/DefaultBtRequestFactory.cc
	* src/DefaultPieceStorage.cc
	* src/DefaultPieceStorage.h
	* src/LongestSequencePieceSelector.cc
	* src/LongestSequencePieceSelector.h
	* src/Makefile.am
	* src/Piece.cc
	* src/Piece.h
	* src/PieceSelector.h
	* src/RarestPieceSelector.cc
	* src/RarestPieceSelector.h
	* src/Util.cc
	* src/Util.h
	* src/bitfield.h
	* test/BitfieldManTest.cc
	* test/LongestSequencePieceSelectorTest.cc
	* test/Makefile.am
	* test/RarestPieceSelectorTest.cc
	* test/UtilTest.cc
	* test/bitfieldTest.cc
Tatsuhiro Tsujikawa 16 years ago
parent
commit
a6b02840fa

+ 32 - 0
ChangeLog

@@ -1,3 +1,35 @@
+2009-03-28  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	BitfieldMan::getMissingIndexes family functions now takes unsigned
+	char* bitfield instead of stl container for efficiency.
+	PieceSelector::select now takes this
+	bitfield. RarestPieceSelector::select now also performs
+	efficiently for this change.  bitfield namespace is introduced and
+	it has several helper functions to handle basic bitfield
+	operations such as test, count set bits, etc.
+	* src/BitfieldMan.cc
+	* src/BitfieldMan.h
+	* src/DefaultBtRequestFactory.cc
+	* src/DefaultPieceStorage.cc
+	* src/DefaultPieceStorage.h
+	* src/LongestSequencePieceSelector.cc
+	* src/LongestSequencePieceSelector.h
+	* src/Makefile.am
+	* src/Piece.cc
+	* src/Piece.h
+	* src/PieceSelector.h
+	* src/RarestPieceSelector.cc
+	* src/RarestPieceSelector.h
+	* src/Util.cc
+	* src/Util.h
+	* src/bitfield.h
+	* test/BitfieldManTest.cc
+	* test/LongestSequencePieceSelectorTest.cc
+	* test/Makefile.am
+	* test/RarestPieceSelectorTest.cc
+	* test/UtilTest.cc
+	* test/bitfieldTest.cc
+	
 2009-03-28  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Made accepted socket non-block.

+ 39 - 85
src/BitfieldMan.cc

@@ -34,11 +34,13 @@
 /* copyright --> */
 #include "BitfieldMan.h"
 
+#include <cassert>
 #include <cstring>
 
 #include "Randomizer.h"
 #include "Util.h"
 #include "array_fun.h"
+#include "bitfield.h"
 
 namespace aria2 {
 
@@ -159,19 +161,6 @@ size_t BitfieldMan::getBlockLength(size_t index) const
   }
 }
 
-size_t BitfieldMan::countSetBit(const unsigned char* bitfield, size_t len) const {
-  size_t count = 0;
-  size_t size = sizeof(uint32_t);
-  size_t to = len/size;
-  for(size_t i = 0; i < to; ++i) {
-    count += Util::countBit(*reinterpret_cast<const uint32_t*>(&bitfield[i*size]));
-  }
-  for(size_t i = len-len%size; i < len; i++) {
-    count += Util::countBit(static_cast<uint32_t>(bitfield[i]));
-  }
-  return count;
-}
-
 size_t
 BitfieldMan::getNthBitIndex(const unsigned char bitfield, size_t nth) const
 {
@@ -195,20 +184,10 @@ bool BitfieldMan::getMissingIndexRandomly(size_t& index,
 					  size_t bitfieldLength) const
 {
   size_t byte = randomizer->getRandomNumber(bitfieldLength);
-
-  unsigned char lastMask = 0;
-  // the number of bytes in the last byte of bitfield
-  size_t lastByteLength = totalLength%(blockLength*8);
-  // the number of block in the last byte of bitfield
-  size_t lastBlockCount = DIV_FLOOR(lastByteLength, blockLength);
-  for(size_t i = 0; i < lastBlockCount; ++i) {
-    lastMask >>= 1;
-    lastMask |= 0x80;
-  }
   for(size_t i = 0; i < bitfieldLength; ++i) {
     unsigned char mask;
     if(byte == bitfieldLength-1) {
-      mask = lastMask;
+      mask = bitfield::lastByteMask(blocks);
     } else {
       mask = 0xff;
     }
@@ -218,7 +197,7 @@ bool BitfieldMan::getMissingIndexRandomly(size_t& index,
       index = byte*8+getNthBitIndex(bits, 1);
       return true;
     }
-    byte++;
+    ++byte;
     if(byte == bitfieldLength) {
       byte = 0;
     }
@@ -322,27 +301,6 @@ bool BitfieldMan::getMissingUnusedIndex(size_t& index) const
   return getMissingIndexRandomly(index, bf, bitfieldLength);
 }
 
-// [startIndex, endIndex)
-class Range {
-public:
-  size_t startIndex;
-  size_t endIndex;
-  Range(size_t startIndex = 0, size_t endIndex = 0):startIndex(startIndex),
-						    endIndex(endIndex) {}
-  
-  size_t getSize() const {
-    return endIndex-startIndex;
-  }
-
-  size_t getMidIndex() const {
-    return (endIndex-startIndex)/2+startIndex;
-  }
-
-  bool operator<(const Range& range) const {
-    return getSize() < range.getSize();
-  }
-};
-
 size_t BitfieldMan::getStartIndex(size_t index) const {
   while(index < blocks && (isUseBitSet(index) || isBitSet(index))) {
     index++;
@@ -393,36 +351,35 @@ bool BitfieldMan::getSparseMissingUnusedIndex(size_t& index) const {
 }
 
 template<typename Array>
-bool BitfieldMan::getAllMissingIndexes(std::deque<size_t>& indexes,
-				       const Array& bitfield,
-				       size_t bitfieldLength) const
+static bool copyBitfield(unsigned char* dst, const Array& src, size_t blocks)
 {
-  for(size_t i = 0; i < bitfieldLength; ++i) {
-    unsigned char bits = bitfield[i];
-    unsigned char mask = 128;
-    size_t index = i*8;
-    for(size_t bi = 0; bi < 8 && index < blocks; ++bi, mask >>= 1, ++index) {
-      if(bits & mask) {
-	indexes.push_back(index);
-      }
-    }
+  unsigned char bits = 0;
+  size_t len = (blocks+7)/8;
+  for(size_t i = 0; i < len-1; ++i) {
+    dst[i] = src[i];
+    bits |= dst[i];
   }
-  return !indexes.empty();
+  dst[len-1] = src[len-1]&bitfield::lastByteMask(blocks);
+  bits |= dst[len-1];
+  return bits != 0;
 }
 
-bool BitfieldMan::getAllMissingIndexes(std::deque<size_t>& indexes) const
+bool BitfieldMan::getAllMissingIndexes(unsigned char* misbitfield, size_t len)
+  const
 {
+  assert(len == bitfieldLength);
   array_fun<unsigned char> bf = array_negate(bitfield);
   if(filterEnabled) {
     bf = array_and(bf, filterBitfield);
   }
-  return getAllMissingIndexes(indexes, bf, bitfieldLength);
+  return copyBitfield(misbitfield, bf, blocks);
 }
 
-bool BitfieldMan::getAllMissingIndexes(std::deque<size_t>& indexes,
+bool BitfieldMan::getAllMissingIndexes(unsigned char* misbitfield, size_t len,
 				       const unsigned char* peerBitfield,
 				       size_t peerBitfieldLength) const
 {
+  assert(len == bitfieldLength);
   if(bitfieldLength != peerBitfieldLength) {
     return false;
   }
@@ -431,13 +388,15 @@ bool BitfieldMan::getAllMissingIndexes(std::deque<size_t>& indexes,
   if(filterEnabled) {
     bf = array_and(bf, filterBitfield);
   }
-  return getAllMissingIndexes(indexes, bf, bitfieldLength);
+  return copyBitfield(misbitfield, bf, blocks);
 }
 
-bool BitfieldMan::getAllMissingUnusedIndexes(std::deque<size_t>& indexes,
+bool BitfieldMan::getAllMissingUnusedIndexes(unsigned char* misbitfield,
+					     size_t len,
 					     const unsigned char* peerBitfield,
 					     size_t peerBitfieldLength) const
 {
+  assert(len == bitfieldLength);
   if(bitfieldLength != peerBitfieldLength) {
     return false;
   }
@@ -447,7 +406,7 @@ bool BitfieldMan::getAllMissingUnusedIndexes(std::deque<size_t>& indexes,
   if(filterEnabled) {
     bf = array_and(bf, filterBitfield);
   }
-  return getAllMissingIndexes(indexes, bf, bitfieldLength);
+  return copyBitfield(misbitfield, bf, blocks);
 }
 
 size_t BitfieldMan::countMissingBlock() const {
@@ -456,16 +415,15 @@ size_t BitfieldMan::countMissingBlock() const {
 
 size_t BitfieldMan::countMissingBlockNow() const {
   if(filterEnabled) {
-    unsigned char* temp = new unsigned char[bitfieldLength];
+    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 =  countSetBit(filterBitfield, bitfieldLength)-
-      countSetBit(temp, bitfieldLength);
-    delete [] temp;
+    size_t count =  bitfield::countSetBit(filterBitfield, blocks)-
+      bitfield::countSetBit(temp, blocks);
     return count;
   } else {
-    return blocks-countSetBit(bitfield, bitfieldLength);
+    return blocks-bitfield::countSetBit(bitfield, blocks);
   }
 }
 
@@ -479,7 +437,7 @@ size_t BitfieldMan::countBlock() const {
 
 size_t BitfieldMan::countFilteredBlockNow() const {
   if(filterEnabled) {
-    return countSetBit(filterBitfield, bitfieldLength);
+    return bitfield::countSetBit(filterBitfield, blocks);
   } else {
     return 0;
   }
@@ -550,18 +508,14 @@ bool BitfieldMan::isAllBitSet() const {
   return true;
 }
 
-bool BitfieldMan::isBitSetInternal(const unsigned char* bitfield, size_t index) const {
-  if(index < 0 || blocks <= index) { return false; }
-  unsigned char mask = 128 >> index%8;
-  return (bitfield[index/8] & mask) != 0;
-}
-
-bool BitfieldMan::isBitSet(size_t index) const {
-  return isBitSetInternal(bitfield, index);
+bool BitfieldMan::isBitSet(size_t index) const
+{
+  return bitfield::test(bitfield, blocks, index);
 }
 
-bool BitfieldMan::isUseBitSet(size_t index) const {
-  return isBitSetInternal(useBitfield, index);
+bool BitfieldMan::isUseBitSet(size_t index) const
+{
+  return bitfield::test(useBitfield, blocks, index);
 }
 
 void BitfieldMan::setBitfield(const unsigned char* bitfield, size_t bitfieldLength) {
@@ -656,11 +610,11 @@ uint64_t BitfieldMan::getFilteredTotalLengthNow() const {
   if(!filterBitfield) {
     return 0;
   }
-  size_t filteredBlocks = countSetBit(filterBitfield, bitfieldLength);
+  size_t filteredBlocks = bitfield::countSetBit(filterBitfield, blocks);
   if(filteredBlocks == 0) {
     return 0;
   }
-  if(isBitSetInternal(filterBitfield, blocks-1)) {
+  if(bitfield::test(filterBitfield, blocks, blocks-1)) {
     return ((uint64_t)filteredBlocks-1)*blockLength+getLastBlockLength();
   } else {
     return ((uint64_t)filteredBlocks)*blockLength;
@@ -679,12 +633,12 @@ uint64_t BitfieldMan::getCompletedLength(bool useFilter) const {
   } else {
     memcpy(temp, bitfield, bitfieldLength);
   }
-  size_t completedBlocks = countSetBit(temp, bitfieldLength);
+  size_t completedBlocks = bitfield::countSetBit(temp, blocks);
   uint64_t completedLength = 0;
   if(completedBlocks == 0) {
     completedLength = 0;
   } else {
-    if(isBitSetInternal(temp, blocks-1)) {
+    if(bitfield::test(temp, blocks, blocks-1)) {
       completedLength = ((uint64_t)completedBlocks-1)*blockLength+getLastBlockLength();
     } else {
       completedLength = ((uint64_t)completedBlocks)*blockLength;

+ 24 - 5
src/BitfieldMan.h

@@ -62,7 +62,6 @@ private:
   uint64_t cachedFilteredComletedLength;
   uint64_t cachedFilteredTotalLength;
 
-  size_t countSetBit(const unsigned char* bitfield, size_t len) const;
   size_t getNthBitIndex(const unsigned char bit, size_t nth) const;
   bool getMissingIndexRandomly(size_t& index, const unsigned char* bitfield, size_t len) const;
 
@@ -77,7 +76,6 @@ private:
 			    const Array& bitfield,
 			    size_t bitfieldLength) const;
 
-  bool isBitSetInternal(const unsigned char* bitfield, size_t index) const;
   bool setBitInternal(unsigned char* bitfield, size_t index, bool on);
   bool setFilterBit(size_t index);
 
@@ -85,6 +83,27 @@ private:
   size_t getEndIndex(size_t index) const;
 
   uint64_t getCompletedLength(bool useFilter) const;
+
+  // [startIndex, endIndex)
+  class Range {
+  public:
+    size_t startIndex;
+    size_t endIndex;
+    Range(size_t startIndex = 0, size_t endIndex = 0):startIndex(startIndex),
+						      endIndex(endIndex) {}
+  
+    size_t getSize() const {
+      return endIndex-startIndex;
+    }
+
+    size_t getMidIndex() const {
+      return (endIndex-startIndex)/2+startIndex;
+    }
+
+    bool operator<(const Range& range) const {
+      return getSize() < range.getSize();
+    }
+  };
 public:
   BitfieldMan(size_t blockLength, uint64_t totalLength);
   BitfieldMan(const BitfieldMan& bitfieldMan);
@@ -139,16 +158,16 @@ public:
   /**
    * affected by filter
    */
-  bool getAllMissingIndexes(std::deque<size_t>&indexes) const;
+  bool getAllMissingIndexes(unsigned char* misbitfield, size_t mislen) const;
   /**
    * affected by filter
    */
-  bool getAllMissingIndexes(std::deque<size_t>& indexes,
+  bool getAllMissingIndexes(unsigned char* misbitfield, size_t mislen,
 			    const unsigned char* bitfield, size_t len) const;
   /**
    * affected by filter
    */
-  bool getAllMissingUnusedIndexes(std::deque<size_t>& indexes,
+  bool getAllMissingUnusedIndexes(unsigned char* misbitfield, size_t mislen,
 				  const unsigned char* bitfield,
 				  size_t len) const;
   /**

+ 17 - 2
src/DefaultBtRequestFactory.cc

@@ -47,6 +47,7 @@
 #include "BtMessage.h"
 #include "a2functional.h"
 #include "SimpleRandomizer.h"
+#include "array_fun.h"
 
 namespace aria2 {
 
@@ -170,13 +171,27 @@ void DefaultBtRequestFactory::createRequestMessagesOnEndGame
   for(Pieces::iterator itr = pieces.begin();
       itr != pieces.end() && requests.size() < max; ++itr) {
     PieceHandle& piece = *itr;
+    const size_t mislen = piece->getBitfieldLength();
+    array_ptr<unsigned char> misbitfield(new unsigned char[mislen]);
+
+    piece->getAllMissingBlockIndexes(misbitfield, mislen);
+
     std::deque<size_t> missingBlockIndexes;
-    piece->getAllMissingBlockIndexes(missingBlockIndexes);
+    size_t blockIndex = 0;
+    for(size_t i = 0; i < mislen; ++i) {
+      unsigned char bits = misbitfield[i];
+      unsigned char mask = 128;
+      for(size_t bi = 0; bi < 8; ++bi, mask >>= 1, ++blockIndex) {
+	if(bits & mask) {
+	  missingBlockIndexes.push_back(blockIndex);
+	}
+      }
+    }
     std::random_shuffle(missingBlockIndexes.begin(), missingBlockIndexes.end(),
 			*(SimpleRandomizer::getInstance().get()));
     for(std::deque<size_t>::const_iterator bitr = missingBlockIndexes.begin();
 	bitr != missingBlockIndexes.end() && requests.size() < max; bitr++) {
-      size_t blockIndex = *bitr;
+      const size_t& blockIndex = *bitr;
       if(!dispatcher->isOutstandingRequest(piece->getIndex(),
 					   blockIndex)) {
       _logger->debug("Creating RequestMessage index=%u, begin=%u, blockIndex=%u",

+ 9 - 5
src/DefaultPieceStorage.cc

@@ -57,6 +57,7 @@
 #include "Option.h"
 #include "StringFormat.h"
 #include "RarestPieceSelector.h"
+#include "array_fun.h"
 
 namespace aria2 {
 
@@ -97,18 +98,21 @@ bool DefaultPieceStorage::isEndGame()
 
 bool DefaultPieceStorage::getMissingPieceIndex(size_t& index,
 					       const unsigned char* bitfield,
-					       size_t& length)
+					       size_t length)
 {
-  std::deque<size_t> indexes;
+  const size_t mislen = bitfieldMan->getBitfieldLength();
+  array_ptr<unsigned char> misbitfield(new unsigned char[mislen]);
   bool r;
   if(isEndGame()) {
-    r = bitfieldMan->getAllMissingIndexes(indexes, bitfield, length);
+    r = bitfieldMan->getAllMissingIndexes(misbitfield, mislen,
+					  bitfield, length);
   } else {
-    r = bitfieldMan->getAllMissingUnusedIndexes(indexes, bitfield, length);
+    r = bitfieldMan->getAllMissingUnusedIndexes(misbitfield, mislen,
+						bitfield, length);
   }
   if(r) {
     // We assume indexes is sorted using comparator less.
-    return _pieceSelector->select(index, indexes);
+    return _pieceSelector->select(index, misbitfield,bitfieldMan->countBlock());
   } else {
     return false;
   }

+ 1 - 1
src/DefaultPieceStorage.h

@@ -84,7 +84,7 @@ private:
   SharedHandle<PieceSelector> _pieceSelector;
 
   bool getMissingPieceIndex(size_t& index,
-			    const unsigned char* bitfield, size_t& length);
+			    const unsigned char* bitfield, size_t length);
 
   SharedHandle<Piece> getMissingPiece(const unsigned char* bitfield,
 				      size_t length);

+ 43 - 9
src/LongestSequencePieceSelector.cc

@@ -33,21 +33,55 @@
  */
 /* copyright --> */
 #include "LongestSequencePieceSelector.h"
-#include "a2algo.h"
+#include "bitfield.h"
 
 namespace aria2 {
 
-bool LongestSequencePieceSelector::select
-(size_t& index,
- const std::deque<size_t>& candidateIndexes) const
+static size_t getStartIndex
+(size_t from, const unsigned char* bitfield, size_t nbits)
 {
-  std::pair<std::deque<size_t>::const_iterator, size_t> p = 
-    max_sequence(candidateIndexes.begin(), candidateIndexes.end());
-  if(p.second == 0) {
-    return false;
+  while(from < nbits && !bitfield::test(bitfield, nbits, from)) {
+    ++from;
+  }
+  if(nbits <= from) {
+    return nbits;
   } else {
-    index = *(p.first)+p.second-1;
+    return from;
+  }
+}
+
+static size_t getEndIndex
+(size_t from, const unsigned char* bitfield, size_t nbits)
+{
+  while(from < nbits && bitfield::test(bitfield, nbits, from)) {
+    ++from;
+  }
+  return from;
+}
+
+bool LongestSequencePieceSelector::select
+(size_t& index, const unsigned char* bitfield, size_t nbits) const
+{
+  size_t mstartindex = 0;
+  size_t mendindex = 0;
+  size_t nextIndex = 0;
+  while(nextIndex < nbits) {
+    size_t startindex = getStartIndex(nextIndex, bitfield, nbits);
+    if(startindex == nbits) {
+      break;
+    }
+    size_t endindex = getEndIndex(startindex, bitfield, nbits);
+    if(mendindex-mstartindex < endindex-startindex) {
+      mstartindex = startindex;
+      mendindex = endindex;
+    }
+    nextIndex = endindex;
+  }
+  if(mendindex-mstartindex > 0) {
+    index = mendindex-1;
     return true;
+  } else {
+    return false;
   }
 }
 

+ 2 - 2
src/LongestSequencePieceSelector.h

@@ -42,11 +42,11 @@ namespace aria2 {
 class LongestSequencePieceSelector:public PieceSelector {
 public:
   // Returns the last index of longest continuous sequence in candidateIndexes.
-  // For example, if candidateIndexes is
+  // For example, if indexes of set bits in bitfield are
   // { 1,2,3,4,7,10,11,12,13,14,15,100,112,113,114 }, then
   // returns 15 because { 10, 11, 12, 13, 14, 15 } is the longest sequence.
   virtual bool select
-  (size_t& index, const std::deque<size_t>& candidateIndexes) const;
+  (size_t& index, const unsigned char* bitfield, size_t nbits) const;
 
   virtual void addPieceStats(size_t index);
 

+ 2 - 1
src/Makefile.am

@@ -205,7 +205,8 @@ SRCS =  Socket.h\
 	HttpServerResponseCommand.cc HttpServerResponseCommand.h\
 	HttpServer.cc HttpServer.h\
 	PieceSelector.h\
-	LongestSequencePieceSelector.cc LongestSequencePieceSelector.h
+	LongestSequencePieceSelector.cc LongestSequencePieceSelector.h\
+	bitfield.h
 
 if HAVE_POSIX_FALLOCATE
 SRCS += FallocFileAllocationIterator.cc FallocFileAllocationIterator.h

+ 14 - 13
src/Makefile.in

@@ -417,11 +417,12 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 	HttpServerCommand.h HttpServerResponseCommand.cc \
 	HttpServerResponseCommand.h HttpServer.cc HttpServer.h \
 	PieceSelector.h LongestSequencePieceSelector.cc \
-	LongestSequencePieceSelector.h FallocFileAllocationIterator.cc \
-	FallocFileAllocationIterator.h EpollEventPoll.cc \
-	EpollEventPoll.h TLSContext.h LibgnutlsTLSContext.cc \
-	LibgnutlsTLSContext.h LibsslTLSContext.cc LibsslTLSContext.h \
-	GZipDecoder.cc GZipDecoder.h Sqlite3MozCookieParser.cc \
+	LongestSequencePieceSelector.h bitfield.h \
+	FallocFileAllocationIterator.cc FallocFileAllocationIterator.h \
+	EpollEventPoll.cc EpollEventPoll.h TLSContext.h \
+	LibgnutlsTLSContext.cc LibgnutlsTLSContext.h \
+	LibsslTLSContext.cc LibsslTLSContext.h GZipDecoder.cc \
+	GZipDecoder.h Sqlite3MozCookieParser.cc \
 	Sqlite3MozCookieParser.h AsyncNameResolver.cc \
 	AsyncNameResolver.h IteratableChunkChecksumValidator.cc \
 	IteratableChunkChecksumValidator.h \
@@ -1157,14 +1158,14 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \
 	HttpServerCommand.h HttpServerResponseCommand.cc \
 	HttpServerResponseCommand.h HttpServer.cc HttpServer.h \
 	PieceSelector.h LongestSequencePieceSelector.cc \
-	LongestSequencePieceSelector.h $(am__append_1) $(am__append_2) \
-	$(am__append_3) $(am__append_4) $(am__append_5) \
-	$(am__append_6) $(am__append_7) $(am__append_8) \
-	$(am__append_9) $(am__append_10) $(am__append_11) \
-	$(am__append_12) $(am__append_13) $(am__append_14) \
-	$(am__append_15) $(am__append_16) $(am__append_17) \
-	$(am__append_18) $(am__append_19) $(am__append_20) \
-	$(am__append_21) $(am__append_22)
+	LongestSequencePieceSelector.h bitfield.h $(am__append_1) \
+	$(am__append_2) $(am__append_3) $(am__append_4) \
+	$(am__append_5) $(am__append_6) $(am__append_7) \
+	$(am__append_8) $(am__append_9) $(am__append_10) \
+	$(am__append_11) $(am__append_12) $(am__append_13) \
+	$(am__append_14) $(am__append_15) $(am__append_16) \
+	$(am__append_17) $(am__append_18) $(am__append_19) \
+	$(am__append_20) $(am__append_21) $(am__append_22)
 noinst_LIBRARIES = libaria2c.a
 libaria2c_a_SOURCES = $(SRCS)
 aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\

+ 4 - 2
src/Piece.cc

@@ -197,8 +197,10 @@ bool Piece::getFirstMissingBlockIndexWithoutLock(size_t& index) const
   return bitfield->getFirstMissingIndex(index);
 }
 
-bool Piece::getAllMissingBlockIndexes(std::deque<size_t>& indexes) const {
-  return bitfield->getAllMissingIndexes(indexes);
+bool Piece::getAllMissingBlockIndexes
+(unsigned char* misbitfield, size_t mislen) const
+{
+  return bitfield->getAllMissingIndexes(misbitfield, mislen);
 }
 
 std::string Piece::toString() const {

+ 2 - 1
src/Piece.h

@@ -89,7 +89,8 @@ public:
   bool getMissingUnusedBlockIndex(size_t& index) const;
   bool getMissingBlockIndex(size_t& index) const;
   bool getFirstMissingBlockIndexWithoutLock(size_t& index) const;
-  bool getAllMissingBlockIndexes(std::deque<size_t>& indexes) const;
+  bool getAllMissingBlockIndexes(unsigned char* misbitfield,
+				 size_t mislen) const;
   void completeBlock(size_t blockIndex);
   void cancelBlock(size_t blockIndex);
 

+ 1 - 1
src/PieceSelector.h

@@ -48,7 +48,7 @@ public:
   virtual ~PieceSelector() {}
 
   virtual bool select
-  (size_t& index, const std::deque<size_t>& candidateIndexes) const = 0;
+  (size_t& index, const unsigned char* bitfield, size_t nbits) const = 0;
 
   virtual void addPieceStats(size_t index) = 0;
 

+ 10 - 6
src/RarestPieceSelector.cc

@@ -34,6 +34,7 @@
 /* copyright --> */
 #include "RarestPieceSelector.h"
 
+#include <cassert>
 #include <algorithm>
 
 #include "SimpleRandomizer.h"
@@ -121,23 +122,26 @@ RarestPieceSelector::RarestPieceSelector(size_t pieceNum, bool randomShuffle):
 class FindRarestPiece
 {
 private:
-  const std::deque<size_t>& _indexes;
+  const unsigned char* _misbitfield;
+  size_t _numbits;
 public:
-  FindRarestPiece(const std::deque<size_t>& indexes):_indexes(indexes) {}
+  FindRarestPiece(const unsigned char* misbitfield, size_t numbits):
+    _misbitfield(misbitfield), _numbits(numbits) {}
 
   bool operator()(const size_t& index)
   {
-    return std::binary_search(_indexes.begin(), _indexes.end(), index);
+    assert(index < _numbits);
+    unsigned char mask = (128 >> (index%8));
+    return _misbitfield[index/8]&mask;
   }
 };
 
 bool RarestPieceSelector::select
-(size_t& index,
- const std::deque<size_t>& candidateIndexes) const
+(size_t& index, const unsigned char* bitfield, size_t nbits) const
 {
   std::vector<size_t>::const_iterator i =
     std::find_if(_sortedPieceStatIndexes.begin(), _sortedPieceStatIndexes.end(),
-		 FindRarestPiece(candidateIndexes));
+		 FindRarestPiece(bitfield, nbits));
   if(i == _sortedPieceStatIndexes.end()) {
     return false;
   } else {

+ 1 - 1
src/RarestPieceSelector.h

@@ -69,7 +69,7 @@ public:
   RarestPieceSelector(size_t pieceNum, bool randomShuffle);
 
   virtual bool select
-  (size_t& index, const std::deque<size_t>& candidateIndexes) const;
+  (size_t& index, const unsigned char* bitfield, size_t nbits) const;
 
   virtual void addPieceStats(size_t index);
 

+ 0 - 27
src/Util.cc

@@ -574,33 +574,6 @@ std::string Util::getContentDispositionFilename(const std::string& header) {
   }
 }
 
-static 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, 
-};
-
-unsigned int Util::countBit(uint32_t n) {
-  return
-    nbits[n&0xffu]+
-    nbits[(n >> 8)&0xffu]+
-    nbits[(n >> 16)&0xffu]+
-    nbits[(n >> 24)&0xffu];
-}
-
 std::string Util::randomAlpha(size_t length, const RandomizerHandle& randomizer) {
   static const char *random_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
   std::string str;

+ 0 - 2
src/Util.h

@@ -212,8 +212,6 @@ public:
   // this function temporarily put here
   static std::string getContentDispositionFilename(const std::string& header);
 
-  static unsigned int countBit(uint32_t n);
-  
   static std::string randomAlpha(size_t length,
 				 const SharedHandle<Randomizer>& randomizer);
   

+ 115 - 0
src/bitfield.h

@@ -0,0 +1,115 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_BITFIELD_H_
+#define _D_BITFIELD_H_
+
+#include "common.h"
+
+#include <cassert>
+#include <cstdlib>
+
+#include "Util.h"
+
+namespace aria2 {
+
+namespace bitfield {
+
+// Returns the bit mask for the last byte. For example, nbits = 9,
+// then 0x80 is returned. nbits = 12, then 0xf0 is returned.
+inline unsigned char lastByteMask(size_t nbits)
+{
+  return -256 >> (8-((nbits+7)/8*8-nbits));
+}
+
+// Returns true if index-th bits is set. Otherwise returns false.
+inline bool test(const unsigned char* bitfield, size_t nbits, size_t index)
+{
+  assert(index < nbits);
+  unsigned char mask = 128 >> (index%8);
+  return (bitfield[index/8]&mask) != 0;
+}
+
+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];
+}
+
+// Counts set bit in bitfield.
+inline size_t countSetBit(const unsigned char* bitfield, size_t nbits)
+{
+  size_t count = 0;
+  size_t size = sizeof(uint32_t);
+  size_t len = (nbits+7)/8;
+  size_t to = len/size;
+  for(size_t i = 0; i < to; ++i) {
+    count += countBit32(*reinterpret_cast<const uint32_t*>(&bitfield[i*size]));
+  }
+  for(size_t i = len-len%size; i < len-1; ++i) {
+    count += countBit32(static_cast<uint32_t>(bitfield[i]));
+  }
+  if(nbits%32 != 0) {
+    count +=
+      countBit32(static_cast<uint32_t>(bitfield[len-1]&lastByteMask(nbits)));
+  }
+  return count;
+}
+
+} // namespace bitfield
+
+} // namespace aria2
+
+#endif // _D_BITFIELD_H_

+ 50 - 43
test/BitfieldManTest.cc

@@ -5,6 +5,7 @@
 #include <cppunit/extensions/HelperMacros.h>
 
 #include "FixedNumberRandomizer.h"
+#include "bitfield.h"
 
 namespace aria2 {
 
@@ -25,6 +26,7 @@ class BitfieldManTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testSetBitRange);
   CPPUNIT_TEST(testGetAllMissingIndexes);
   CPPUNIT_TEST(testGetAllMissingIndexes_noarg);
+  CPPUNIT_TEST(testGetAllMissingIndexes_checkLastByte);
   CPPUNIT_TEST(testGetAllMissingUnusedIndexes);
   CPPUNIT_TEST(testGetMissingUnusedIndex);
   CPPUNIT_TEST(testGetMissingIndex_noarg);
@@ -54,6 +56,7 @@ public:
   void testGetMissingUnusedIndex_noarg();
   void testGetAllMissingIndexes();
   void testGetAllMissingIndexes_noarg();
+  void testGetAllMissingIndexes_checkLastByte();
   void testGetAllMissingUnusedIndexes();
   
   void testIsAllBitSet();
@@ -607,83 +610,87 @@ void BitfieldManTest::testGetAllMissingIndexes_noarg()
 {
   size_t blockLength = 16*1024;
   uint64_t totalLength = 1024*1024;
+  size_t nbits = (totalLength+blockLength-1)/blockLength;
   BitfieldMan bf(blockLength, totalLength);
+  unsigned char misbitfield[8];
+  CPPUNIT_ASSERT(bf.getAllMissingIndexes(misbitfield, sizeof(misbitfield)));
+  CPPUNIT_ASSERT_EQUAL((size_t)64, bitfield::countSetBit(misbitfield, nbits));
 
-  {
-    std::deque<size_t> indexes;
-    CPPUNIT_ASSERT(bf.getAllMissingIndexes(indexes));
-    CPPUNIT_ASSERT_EQUAL((size_t)64, indexes.size());
-  }
   for(size_t i = 0; i < 63; ++i) {
     bf.setBit(i);
   }
-  {
-    std::deque<size_t> indexes;
-    CPPUNIT_ASSERT(bf.getAllMissingIndexes(indexes));
-    CPPUNIT_ASSERT_EQUAL((size_t)1, indexes.size());
-    CPPUNIT_ASSERT_EQUAL((size_t)63, indexes.front());
-  }
+  CPPUNIT_ASSERT(bf.getAllMissingIndexes(misbitfield, sizeof(misbitfield)));
+  CPPUNIT_ASSERT_EQUAL((size_t)1, bitfield::countSetBit(misbitfield, nbits));
+  CPPUNIT_ASSERT(bitfield::test(misbitfield, nbits, 63));
+}
+
+// See garbage bits of last byte are 0
+void BitfieldManTest::testGetAllMissingIndexes_checkLastByte()
+{
+  size_t blockLength = 16*1024;
+  uint64_t totalLength = blockLength*2;
+  size_t nbits = (totalLength+blockLength-1)/blockLength;
+  BitfieldMan bf(blockLength, totalLength);
+  unsigned char misbitfield[1];
+  CPPUNIT_ASSERT(bf.getAllMissingIndexes(misbitfield, sizeof(misbitfield)));
+  CPPUNIT_ASSERT_EQUAL((size_t)2, bitfield::countSetBit(misbitfield, nbits));
+  CPPUNIT_ASSERT(bitfield::test(misbitfield, nbits, 0));
+  CPPUNIT_ASSERT(bitfield::test(misbitfield, nbits, 1));
 }
 
 void BitfieldManTest::testGetAllMissingIndexes()
 {
   size_t blockLength = 16*1024;
   uint64_t totalLength = 1024*1024;
+  size_t nbits = (totalLength+blockLength-1)/blockLength;
   BitfieldMan bf(blockLength, totalLength);
   BitfieldMan peerBf(blockLength, totalLength);
   peerBf.setAllBit();
+  unsigned char misbitfield[8];
 
-  {
-    std::deque<size_t> indexes;
-    CPPUNIT_ASSERT(bf.getAllMissingIndexes(indexes,
-					   peerBf.getBitfield(),
-					   peerBf.getBitfieldLength()));
-    CPPUNIT_ASSERT_EQUAL((size_t)64, indexes.size());
-  }
+  CPPUNIT_ASSERT(bf.getAllMissingIndexes(misbitfield, sizeof(misbitfield),
+					 peerBf.getBitfield(),
+					 peerBf.getBitfieldLength()));
+  CPPUNIT_ASSERT_EQUAL((size_t)64, bitfield::countSetBit(misbitfield, nbits));
   for(size_t i = 0; i < 62; ++i) {
     bf.setBit(i);
   }
   peerBf.unsetBit(62);
-  {
-    std::deque<size_t> indexes;
-    CPPUNIT_ASSERT(bf.getAllMissingIndexes(indexes,
-					   peerBf.getBitfield(),
-					   peerBf.getBitfieldLength()));
-    
-    CPPUNIT_ASSERT_EQUAL((size_t)1, indexes.size());
-    CPPUNIT_ASSERT_EQUAL((size_t)63, indexes.front());
-  }
+
+  CPPUNIT_ASSERT(bf.getAllMissingIndexes(misbitfield, sizeof(misbitfield),
+					 peerBf.getBitfield(),
+					 peerBf.getBitfieldLength()));
+  CPPUNIT_ASSERT_EQUAL((size_t)1, bitfield::countSetBit(misbitfield, nbits));
+  CPPUNIT_ASSERT(bitfield::test(misbitfield, nbits, 63));
 }
 
 void BitfieldManTest::testGetAllMissingUnusedIndexes()
 {
   size_t blockLength = 16*1024;
   uint64_t totalLength = 1024*1024;
+  size_t nbits = (totalLength+blockLength-1)/blockLength;
   BitfieldMan bf(blockLength, totalLength);
   BitfieldMan peerBf(blockLength, totalLength);
   peerBf.setAllBit();
+  unsigned char misbitfield[8];
+
+  CPPUNIT_ASSERT(bf.getAllMissingUnusedIndexes(misbitfield,
+					       sizeof(misbitfield),
+					       peerBf.getBitfield(),
+					       peerBf.getBitfieldLength()));
+  CPPUNIT_ASSERT_EQUAL((size_t)64, bitfield::countSetBit(misbitfield, nbits));
 
-  {
-    std::deque<size_t> indexes;
-    CPPUNIT_ASSERT(bf.getAllMissingUnusedIndexes(indexes,
-						 peerBf.getBitfield(),
-						 peerBf.getBitfieldLength()));
-    CPPUNIT_ASSERT_EQUAL((size_t)64, indexes.size());
-  }
   for(size_t i = 0; i < 61; ++i) {
     bf.setBit(i);
   }
   bf.setUseBit(61);
   peerBf.unsetBit(62);
-  {
-    std::deque<size_t> indexes;
-    CPPUNIT_ASSERT(bf.getAllMissingUnusedIndexes(indexes,
-						 peerBf.getBitfield(),
-						 peerBf.getBitfieldLength()));
-    
-    CPPUNIT_ASSERT_EQUAL((size_t)1, indexes.size());
-    CPPUNIT_ASSERT_EQUAL((size_t)63, indexes.front());
-  }
+  CPPUNIT_ASSERT(bf.getAllMissingUnusedIndexes(misbitfield,
+					       sizeof(misbitfield),
+					       peerBf.getBitfield(),
+					       peerBf.getBitfieldLength()));
+  CPPUNIT_ASSERT_EQUAL((size_t)1, bitfield::countSetBit(misbitfield, nbits));
+  CPPUNIT_ASSERT(bitfield::test(misbitfield, nbits, 63));
 }
 
 void BitfieldManTest::testGetMissingUnusedIndex()

+ 11 - 6
test/LongestSequencePieceSelectorTest.cc

@@ -3,6 +3,7 @@
 #include <cppunit/extensions/HelperMacros.h>
 
 #include "array_fun.h"
+#include "BitfieldMan.h"
 
 namespace aria2 {
 
@@ -25,19 +26,23 @@ CPPUNIT_TEST_SUITE_REGISTRATION(LongestSequencePieceSelectorTest);
 void LongestSequencePieceSelectorTest::testSelect()
 {
   size_t A[] = { 1,2,3,4,7,10,11,12,13,14,15,100,112,113,114 };
-  std::deque<size_t> indexes(&A[0], &A[arrayLength(A)]);
+  BitfieldMan bf(1024, 1024*256);
+  for(size_t i = 0; i < arrayLength(A); ++i) {
+    bf.setBit(A[i]);
+  }
 
   LongestSequencePieceSelector selector;
   size_t index;
 
-  CPPUNIT_ASSERT(selector.select(index, indexes));
+  CPPUNIT_ASSERT(selector.select(index, bf.getBitfield(), bf.countBlock()));
   CPPUNIT_ASSERT_EQUAL((size_t)15, index);
 
-  std::deque<size_t> zeroindexes;
-  CPPUNIT_ASSERT(!selector.select(index, zeroindexes));
+  bf.clearAllBit();
+  CPPUNIT_ASSERT(!selector.select(index, bf.getBitfield(), bf.countBlock()));
 
-  std::deque<size_t> oneseq(&A[0], &A[4]);
-  CPPUNIT_ASSERT(selector.select(index, oneseq));
+  // See it works in just one range
+  bf.setBitRange(1, 4);
+  CPPUNIT_ASSERT(selector.select(index, bf.getBitfield(), bf.countBlock()));
   CPPUNIT_ASSERT_EQUAL((size_t)4, index);
 }
 

+ 2 - 1
test/Makefile.am

@@ -67,7 +67,8 @@ aria2c_SOURCES = AllTest.cc\
 	SequentialPickerTest.cc\
 	RarestPieceSelectorTest.cc\
 	LongestSequencePieceSelectorTest.cc\
-	a2algoTest.cc
+	a2algoTest.cc\
+	bitfieldTest.cc
 
 if HAVE_POSIX_FALLOCATE
 aria2c_SOURCES += FallocFileAllocationIteratorTest.cc

+ 10 - 7
test/Makefile.in

@@ -194,8 +194,9 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \
 	SimpleDNSCacheTest.cc DownloadHelperTest.cc BencodeTest.cc \
 	SequentialPickerTest.cc RarestPieceSelectorTest.cc \
 	LongestSequencePieceSelectorTest.cc a2algoTest.cc \
-	FallocFileAllocationIteratorTest.cc GZipDecoderTest.cc \
-	Sqlite3MozCookieParserTest.cc MessageDigestHelperTest.cc \
+	bitfieldTest.cc FallocFileAllocationIteratorTest.cc \
+	GZipDecoderTest.cc Sqlite3MozCookieParserTest.cc \
+	MessageDigestHelperTest.cc \
 	IteratableChunkChecksumValidatorTest.cc \
 	IteratableChecksumValidatorTest.cc BtAllowedFastMessageTest.cc \
 	BtBitfieldMessageTest.cc BtCancelMessageTest.cc \
@@ -364,9 +365,9 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) TestUtil.$(OBJEXT) \
 	SequentialPickerTest.$(OBJEXT) \
 	RarestPieceSelectorTest.$(OBJEXT) \
 	LongestSequencePieceSelectorTest.$(OBJEXT) \
-	a2algoTest.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
-	$(am__objects_3) $(am__objects_4) $(am__objects_5) \
-	$(am__objects_6)
+	a2algoTest.$(OBJEXT) bitfieldTest.$(OBJEXT) $(am__objects_1) \
+	$(am__objects_2) $(am__objects_3) $(am__objects_4) \
+	$(am__objects_5) $(am__objects_6)
 aria2c_OBJECTS = $(am_aria2c_OBJECTS)
 am__DEPENDENCIES_1 =
 aria2c_DEPENDENCIES = ../src/libaria2c.a ../src/download_helper.o \
@@ -591,8 +592,9 @@ aria2c_SOURCES = AllTest.cc TestUtil.cc TestUtil.h SocketCoreTest.cc \
 	SimpleDNSCacheTest.cc DownloadHelperTest.cc BencodeTest.cc \
 	SequentialPickerTest.cc RarestPieceSelectorTest.cc \
 	LongestSequencePieceSelectorTest.cc a2algoTest.cc \
-	$(am__append_1) $(am__append_2) $(am__append_3) \
-	$(am__append_4) $(am__append_5) $(am__append_6)
+	bitfieldTest.cc $(am__append_1) $(am__append_2) \
+	$(am__append_3) $(am__append_4) $(am__append_5) \
+	$(am__append_6)
 
 #aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
 #aria2c_LDFLAGS = ${CPPUNIT_LIBS}
@@ -828,6 +830,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/a2algoTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/a2functionalTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/array_funTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitfieldTest.Po@am__quote@
 
 .cc.o:
 @am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<

+ 22 - 0
test/RarestPieceSelectorTest.cc

@@ -7,6 +7,7 @@
 
 #include "Exception.h"
 #include "Util.h"
+#include "BitfieldMan.h"
 
 namespace aria2 {
 
@@ -17,6 +18,7 @@ class RarestPieceSelectorTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testAddPieceStats_bitfield);
   CPPUNIT_TEST(testUpdatePieceStats);
   CPPUNIT_TEST(testSubtractPieceStats);
+  CPPUNIT_TEST(testSelect);
   CPPUNIT_TEST_SUITE_END();
 public:
   void setUp() {}
@@ -27,6 +29,7 @@ public:
   void testAddPieceStats_bitfield();
   void testUpdatePieceStats();
   void testSubtractPieceStats();
+  void testSelect();
 };
 
 
@@ -189,5 +192,24 @@ void RarestPieceSelectorTest::testSubtractPieceStats()
   }
 }
 
+void RarestPieceSelectorTest::testSelect()
+{
+  RarestPieceSelector selector(10, false);
+  BitfieldMan bf(1024, 10*1024);
+  bf.setBitRange(0, 2);
+  size_t index;
+
+  selector.addPieceStats(0);
+
+  CPPUNIT_ASSERT(selector.select(index, bf.getBitfield(),
+				 bf.countBlock()));
+  CPPUNIT_ASSERT_EQUAL((size_t)1, index);
+
+  selector.addPieceStats(1);
+
+  CPPUNIT_ASSERT(selector.select(index, bf.getBitfield(),
+				 bf.countBlock()));
+  CPPUNIT_ASSERT_EQUAL((size_t)2, index);
+}
 
 } // namespace aria2

+ 0 - 7
test/UtilTest.cc

@@ -30,7 +30,6 @@ class UtilTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testToUpper);
   CPPUNIT_TEST(testToLower);
   CPPUNIT_TEST(testUrldecode);
-  CPPUNIT_TEST(testCountBit);
   CPPUNIT_TEST(testGetRealSize);
   CPPUNIT_TEST(testAbbrevSize);
   CPPUNIT_TEST(testToStream);
@@ -75,7 +74,6 @@ public:
   void testToUpper();
   void testToLower();
   void testUrldecode();
-  void testCountBit();
   void testGetRealSize();
   void testAbbrevSize();
   void testToStream();
@@ -338,11 +336,6 @@ void UtilTest::testUrldecode() {
   CPPUNIT_ASSERT_EQUAL(std::string("/"), Util::urldecode(src6));
 }
 
-void UtilTest::testCountBit() {
-  CPPUNIT_ASSERT_EQUAL((unsigned int)32, Util::countBit(UINT32_MAX));
-  CPPUNIT_ASSERT_EQUAL((unsigned int)8, Util::countBit(255));
-}
-
 void UtilTest::testGetRealSize()
 {
   CPPUNIT_ASSERT_EQUAL((int64_t)4294967296LL, Util::getRealSize("4096M"));

+ 60 - 0
test/bitfieldTest.cc

@@ -0,0 +1,60 @@
+#include "bitfield.h"
+
+#include <cppunit/extensions/HelperMacros.h>
+
+namespace aria2 {
+
+class bitfieldTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(bitfieldTest);
+  CPPUNIT_TEST(testTest);
+  CPPUNIT_TEST(testCountBit32);
+  CPPUNIT_TEST(testCountSetBit);
+  CPPUNIT_TEST(testLastByteMask);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void testTest();
+  void testCountBit32();
+  void testCountSetBit();
+  void testLastByteMask();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION( bitfieldTest );
+
+void bitfieldTest::testTest()
+{
+  unsigned char bitfield[] = { 0xaa };
+
+  CPPUNIT_ASSERT(bitfield::test(bitfield, 8, 0));
+  CPPUNIT_ASSERT(!bitfield::test(bitfield, 8, 1));
+}
+
+void bitfieldTest::testCountBit32()
+{
+  CPPUNIT_ASSERT_EQUAL((size_t)32, bitfield::countBit32(UINT32_MAX));
+  CPPUNIT_ASSERT_EQUAL((size_t)8, bitfield::countBit32(255));
+}
+
+void bitfieldTest::testCountSetBit()
+{
+  unsigned char bitfield[] = { 0xff, 0xff, 0xff, 0xf0, 0xff, 0x01 };
+
+  CPPUNIT_ASSERT_EQUAL((size_t)37, bitfield::countSetBit(bitfield, 48));
+  CPPUNIT_ASSERT_EQUAL((size_t)36, bitfield::countSetBit(bitfield, 47));
+  CPPUNIT_ASSERT_EQUAL((size_t)28, bitfield::countSetBit(bitfield, 32));
+}
+
+void bitfieldTest::testLastByteMask()
+{
+  CPPUNIT_ASSERT_EQUAL((unsigned int)128,
+		       (unsigned int)bitfield::lastByteMask(9));
+  CPPUNIT_ASSERT_EQUAL((unsigned int)240,
+		       (unsigned int)bitfield::lastByteMask(12));
+  CPPUNIT_ASSERT_EQUAL((unsigned int)255,
+		       (unsigned int)bitfield::lastByteMask(16));
+}
+
+} // namespace aria2