diff --git a/ChangeLog b/ChangeLog index 8409dba5..83ec4bc6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,35 @@ +2009-03-28 Tatsuhiro Tsujikawa + + 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 Made accepted socket non-block. diff --git a/src/BitfieldMan.cc b/src/BitfieldMan.cc index 444e93a0..74ebe56b 100644 --- a/src/BitfieldMan.cc +++ b/src/BitfieldMan.cc @@ -34,11 +34,13 @@ /* copyright --> */ #include "BitfieldMan.h" +#include #include #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(&bitfield[i*size])); - } - for(size_t i = len-len%size; i < len; i++) { - count += Util::countBit(static_cast(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 -bool BitfieldMan::getAllMissingIndexes(std::deque& 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& indexes) const +bool BitfieldMan::getAllMissingIndexes(unsigned char* misbitfield, size_t len) + const { + assert(len == bitfieldLength); array_fun 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& 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& indexes, if(filterEnabled) { bf = array_and(bf, filterBitfield); } - return getAllMissingIndexes(indexes, bf, bitfieldLength); + return copyBitfield(misbitfield, bf, blocks); } -bool BitfieldMan::getAllMissingUnusedIndexes(std::deque& 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& 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 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 bitfield::test(bitfield, blocks, index); } -bool BitfieldMan::isBitSet(size_t index) const { - return isBitSetInternal(bitfield, 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; diff --git a/src/BitfieldMan.h b/src/BitfieldMan.h index 7150337d..8d51df76 100644 --- a/src/BitfieldMan.h +++ b/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&indexes) const; + bool getAllMissingIndexes(unsigned char* misbitfield, size_t mislen) const; /** * affected by filter */ - bool getAllMissingIndexes(std::deque& indexes, + bool getAllMissingIndexes(unsigned char* misbitfield, size_t mislen, const unsigned char* bitfield, size_t len) const; /** * affected by filter */ - bool getAllMissingUnusedIndexes(std::deque& indexes, + bool getAllMissingUnusedIndexes(unsigned char* misbitfield, size_t mislen, const unsigned char* bitfield, size_t len) const; /** diff --git a/src/DefaultBtRequestFactory.cc b/src/DefaultBtRequestFactory.cc index 2a272437..8330efeb 100644 --- a/src/DefaultBtRequestFactory.cc +++ b/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 misbitfield(new unsigned char[mislen]); + + piece->getAllMissingBlockIndexes(misbitfield, mislen); + std::deque 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::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", diff --git a/src/DefaultPieceStorage.cc b/src/DefaultPieceStorage.cc index 4ad8d922..ff6e7877 100644 --- a/src/DefaultPieceStorage.cc +++ b/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 indexes; + const size_t mislen = bitfieldMan->getBitfieldLength(); + array_ptr 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; } diff --git a/src/DefaultPieceStorage.h b/src/DefaultPieceStorage.h index b8415f27..66f7eb84 100644 --- a/src/DefaultPieceStorage.h +++ b/src/DefaultPieceStorage.h @@ -84,7 +84,7 @@ private: SharedHandle _pieceSelector; bool getMissingPieceIndex(size_t& index, - const unsigned char* bitfield, size_t& length); + const unsigned char* bitfield, size_t length); SharedHandle getMissingPiece(const unsigned char* bitfield, size_t length); diff --git a/src/LongestSequencePieceSelector.cc b/src/LongestSequencePieceSelector.cc index 6e57ead5..e1582cca 100644 --- a/src/LongestSequencePieceSelector.cc +++ b/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& candidateIndexes) const +static size_t getStartIndex +(size_t from, const unsigned char* bitfield, size_t nbits) { - std::pair::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; } } diff --git a/src/LongestSequencePieceSelector.h b/src/LongestSequencePieceSelector.h index 28838f0d..232b313d 100644 --- a/src/LongestSequencePieceSelector.h +++ b/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& candidateIndexes) const; + (size_t& index, const unsigned char* bitfield, size_t nbits) const; virtual void addPieceStats(size_t index); diff --git a/src/Makefile.am b/src/Makefile.am index c8e94f3f..1ce87d27 100644 --- a/src/Makefile.am +++ b/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 diff --git a/src/Makefile.in b/src/Makefile.in index 33ecc216..35b9bef3 100644 --- a/src/Makefile.in +++ b/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@\ diff --git a/src/Piece.cc b/src/Piece.cc index b06a8eb9..3339410c 100644 --- a/src/Piece.cc +++ b/src/Piece.cc @@ -197,8 +197,10 @@ bool Piece::getFirstMissingBlockIndexWithoutLock(size_t& index) const return bitfield->getFirstMissingIndex(index); } -bool Piece::getAllMissingBlockIndexes(std::deque& 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 { diff --git a/src/Piece.h b/src/Piece.h index d0940320..caa5b1d4 100644 --- a/src/Piece.h +++ b/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& indexes) const; + bool getAllMissingBlockIndexes(unsigned char* misbitfield, + size_t mislen) const; void completeBlock(size_t blockIndex); void cancelBlock(size_t blockIndex); diff --git a/src/PieceSelector.h b/src/PieceSelector.h index b887d61b..0b229258 100644 --- a/src/PieceSelector.h +++ b/src/PieceSelector.h @@ -48,7 +48,7 @@ public: virtual ~PieceSelector() {} virtual bool select - (size_t& index, const std::deque& candidateIndexes) const = 0; + (size_t& index, const unsigned char* bitfield, size_t nbits) const = 0; virtual void addPieceStats(size_t index) = 0; diff --git a/src/RarestPieceSelector.cc b/src/RarestPieceSelector.cc index fe5ca304..0b7aabb5 100644 --- a/src/RarestPieceSelector.cc +++ b/src/RarestPieceSelector.cc @@ -34,6 +34,7 @@ /* copyright --> */ #include "RarestPieceSelector.h" +#include #include #include "SimpleRandomizer.h" @@ -121,23 +122,26 @@ RarestPieceSelector::RarestPieceSelector(size_t pieceNum, bool randomShuffle): class FindRarestPiece { private: - const std::deque& _indexes; + const unsigned char* _misbitfield; + size_t _numbits; public: - FindRarestPiece(const std::deque& 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& candidateIndexes) const +(size_t& index, const unsigned char* bitfield, size_t nbits) const { std::vector::const_iterator i = std::find_if(_sortedPieceStatIndexes.begin(), _sortedPieceStatIndexes.end(), - FindRarestPiece(candidateIndexes)); + FindRarestPiece(bitfield, nbits)); if(i == _sortedPieceStatIndexes.end()) { return false; } else { diff --git a/src/RarestPieceSelector.h b/src/RarestPieceSelector.h index 4c7e168c..431ed406 100644 --- a/src/RarestPieceSelector.h +++ b/src/RarestPieceSelector.h @@ -69,7 +69,7 @@ public: RarestPieceSelector(size_t pieceNum, bool randomShuffle); virtual bool select - (size_t& index, const std::deque& candidateIndexes) const; + (size_t& index, const unsigned char* bitfield, size_t nbits) const; virtual void addPieceStats(size_t index); diff --git a/src/Util.cc b/src/Util.cc index 21ce6d37..64810ff4 100644 --- a/src/Util.cc +++ b/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; diff --git a/src/Util.h b/src/Util.h index b1b5005d..6adac2df 100644 --- a/src/Util.h +++ b/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); diff --git a/src/bitfield.h b/src/bitfield.h new file mode 100644 index 00000000..8b1b8d4f --- /dev/null +++ b/src/bitfield.h @@ -0,0 +1,115 @@ +/* */ +#ifndef _D_BITFIELD_H_ +#define _D_BITFIELD_H_ + +#include "common.h" + +#include +#include + +#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(&bitfield[i*size])); + } + for(size_t i = len-len%size; i < len-1; ++i) { + count += countBit32(static_cast(bitfield[i])); + } + if(nbits%32 != 0) { + count += + countBit32(static_cast(bitfield[len-1]&lastByteMask(nbits))); + } + return count; +} + +} // namespace bitfield + +} // namespace aria2 + +#endif // _D_BITFIELD_H_ diff --git a/test/BitfieldManTest.cc b/test/BitfieldManTest.cc index d7d6bf9c..0acd76ea 100644 --- a/test/BitfieldManTest.cc +++ b/test/BitfieldManTest.cc @@ -5,6 +5,7 @@ #include #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 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 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 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 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 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 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() diff --git a/test/LongestSequencePieceSelectorTest.cc b/test/LongestSequencePieceSelectorTest.cc index d3b85593..23739a42 100644 --- a/test/LongestSequencePieceSelectorTest.cc +++ b/test/LongestSequencePieceSelectorTest.cc @@ -3,6 +3,7 @@ #include #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 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 zeroindexes; - CPPUNIT_ASSERT(!selector.select(index, zeroindexes)); + bf.clearAllBit(); + CPPUNIT_ASSERT(!selector.select(index, bf.getBitfield(), bf.countBlock())); - std::deque 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); } diff --git a/test/Makefile.am b/test/Makefile.am index 7bda5b09..0bdfedc6 100644 --- a/test/Makefile.am +++ b/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 diff --git a/test/Makefile.in b/test/Makefile.in index bbd12d90..0a881e1d 100644 --- a/test/Makefile.in +++ b/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 $@ $< diff --git a/test/RarestPieceSelectorTest.cc b/test/RarestPieceSelectorTest.cc index c8d22ccc..0549aca9 100644 --- a/test/RarestPieceSelectorTest.cc +++ b/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 diff --git a/test/UtilTest.cc b/test/UtilTest.cc index 15697eab..051696e1 100644 --- a/test/UtilTest.cc +++ b/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")); diff --git a/test/bitfieldTest.cc b/test/bitfieldTest.cc new file mode 100644 index 00000000..b6b95e77 --- /dev/null +++ b/test/bitfieldTest.cc @@ -0,0 +1,60 @@ +#include "bitfield.h" + +#include + +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