diff --git a/src/PieceStatMan.cc b/src/PieceStatMan.cc index a196702a..e869cffd 100644 --- a/src/PieceStatMan.cc +++ b/src/PieceStatMan.cc @@ -34,6 +34,7 @@ /* copyright --> */ #include "PieceStatMan.h" +#include #include #include "SimpleRandomizer.h" @@ -41,138 +42,80 @@ namespace aria2 { -PieceStat::PieceStat(size_t index):order_(0), index_(index), count_(0) {} - -void PieceStat::addCount() -{ - if(count_ < SIZE_MAX) { - ++count_; - } -} - -void PieceStat::subCount() -{ - if(count_ > 0) { - --count_; - } -} - -namespace { -class GenPieceStat { -private: - size_t index_; -public: - GenPieceStat():index_(0) {} - - SharedHandle operator()() - { - return SharedHandle(new PieceStat(index_++)); - } -}; -} // namespace - PieceStatMan::PieceStatMan(size_t pieceNum, bool randomShuffle): - pieceStats_(pieceNum), - sortedPieceStatIndexes_(pieceNum) + order_(pieceNum), + counts_(pieceNum) { - std::generate(pieceStats_.begin(), pieceStats_.end(), GenPieceStat()); - std::vector > sortedPieceStats(pieceStats_); + for(size_t i = 0; i < pieceNum; ++i) { + order_[i] = i; + } // we need some randomness in ordering. if(randomShuffle) { - std::random_shuffle(sortedPieceStats.begin(), sortedPieceStats.end(), + std::random_shuffle(order_.begin(), order_.end(), *(SimpleRandomizer::getInstance().get())); } - { - size_t order = 0; - for(std::vector >::const_iterator i = - sortedPieceStats.begin(), eoi = sortedPieceStats.end(); - i != eoi; ++i) { - sortedPieceStatIndexes_[order] = (*i)->getIndex(); - (*i)->setOrder(order++); - } - } } PieceStatMan::~PieceStatMan() {} namespace { -class PieceStatRarer { -private: - const std::vector >& pieceStats_; -public: - PieceStatRarer(const std::vector >& ps): - pieceStats_(ps) {} - - bool operator()(size_t lhs, size_t rhs) const - { - return *pieceStats_[lhs] < *pieceStats_[rhs]; +void inc(int& x) +{ + if(x < std::numeric_limits::max()) { + ++x; } -}; +} +} // namespace + +namespace { +void sub(int& x) +{ + if(x > 0) { + --x; + } +} } // namespace void PieceStatMan::addPieceStats(const unsigned char* bitfield, size_t bitfieldLength) { - const size_t nbits = pieceStats_.size(); - assert(nbits <= bitfieldLength*8); - for(size_t i = 0; i < nbits; ++i) { + for(size_t i = 0, nbits = counts_.size(); i < nbits; ++i) { if(bitfield::test(bitfield, nbits, i)) { - pieceStats_[i]->addCount(); + inc(counts_[i]); } } - std::sort(sortedPieceStatIndexes_.begin(), sortedPieceStatIndexes_.end(), - PieceStatRarer(pieceStats_)); } void PieceStatMan::subtractPieceStats(const unsigned char* bitfield, size_t bitfieldLength) { - const size_t nbits = pieceStats_.size(); - assert(nbits <= bitfieldLength*8); - for(size_t i = 0; i < nbits; ++i) { + for(size_t i = 0, nbits = counts_.size(); i < nbits; ++i) { if(bitfield::test(bitfield, nbits, i)) { - pieceStats_[i]->subCount(); + sub(counts_[i]); } } - std::sort(sortedPieceStatIndexes_.begin(), sortedPieceStatIndexes_.end(), - PieceStatRarer(pieceStats_)); } void PieceStatMan::updatePieceStats(const unsigned char* newBitfield, size_t newBitfieldLength, const unsigned char* oldBitfield) { - const size_t nbits = pieceStats_.size(); - assert(nbits <= newBitfieldLength*8); - for(size_t i = 0; i < nbits; ++i) { + for(size_t i = 0, nbits = counts_.size(); i < nbits; ++i) { bool inNew = bitfield::test(newBitfield, nbits, i); bool inOld = bitfield::test(oldBitfield, nbits, i); if(inNew) { if(!inOld) { - pieceStats_[i]->addCount(); + inc(counts_[i]); } } else if(inOld) { - pieceStats_[i]->subCount(); + sub(counts_[i]); } } - std::sort(sortedPieceStatIndexes_.begin(), sortedPieceStatIndexes_.end(), - PieceStatRarer(pieceStats_)); } void PieceStatMan::addPieceStats(size_t index) { - std::vector::iterator cur = - std::lower_bound(sortedPieceStatIndexes_.begin(), - sortedPieceStatIndexes_.end(), - index, PieceStatRarer(pieceStats_)); - - pieceStats_[index]->addCount(); - - std::vector::iterator to = - std::upper_bound(cur+1, sortedPieceStatIndexes_.end(), - index, PieceStatRarer(pieceStats_)); - - std::rotate(cur, cur+1, to); + inc(counts_[index]); } } // namespace aria2 diff --git a/src/PieceStatMan.h b/src/PieceStatMan.h index 1f1931a0..32020ab2 100644 --- a/src/PieceStatMan.h +++ b/src/PieceStatMan.h @@ -43,53 +43,10 @@ namespace aria2 { -class PieceStat { -private: - size_t order_; - size_t index_; - size_t count_; -public: - PieceStat(size_t index); - - bool operator<(const PieceStat& pieceStat) const - { - if(count_ == pieceStat.count_) { - return order_ < pieceStat.order_; - } else { - return count_ < pieceStat.count_; - } - } - - void addCount(); - void subCount(); - - size_t getOrder() const - { - return order_; - } - - void setOrder(size_t order) - { - order_ = order; - } - - size_t getIndex() const - { - return index_; - } - - size_t getCount() const - { - return count_; - } - -}; - class PieceStatMan { private: - std::vector > pieceStats_; - - std::vector sortedPieceStatIndexes_; + std::vector order_; + std::vector counts_; public: PieceStatMan(size_t pieceNum, bool randomShuffle); @@ -107,17 +64,15 @@ public: size_t newBitfieldLength, const unsigned char* oldBitfield); - // Returns piece index in rarest first order. - const std::vector& getRarerPieceIndexes() const + const std::vector& getOrder() const { - return sortedPieceStatIndexes_; + return order_; } - const std::vector >& getPieceStats() const + const std::vector& getCounts() const { - return pieceStats_; + return counts_; } - }; } // namespace aria2 diff --git a/src/RarestPieceSelector.cc b/src/RarestPieceSelector.cc index 715a9f23..3cc78077 100644 --- a/src/RarestPieceSelector.cc +++ b/src/RarestPieceSelector.cc @@ -34,47 +34,35 @@ /* copyright --> */ #include "RarestPieceSelector.h" -#include +#include #include #include "PieceStatMan.h" +#include "bitfield.h" namespace aria2 { RarestPieceSelector::RarestPieceSelector (const SharedHandle& pieceStatMan):pieceStatMan_(pieceStatMan) {} -namespace { -class FindRarestPiece -{ -private: - const unsigned char* misbitfield_; - size_t numbits_; -public: - FindRarestPiece(const unsigned char* misbitfield, size_t numbits): - misbitfield_(misbitfield), numbits_(numbits) {} - - bool operator()(const size_t& index) - { - assert(index < numbits_); - unsigned char mask = (128 >> (index%8)); - return misbitfield_[index/8]&mask; - } -}; -} // namespace - bool RarestPieceSelector::select (size_t& index, const unsigned char* bitfield, size_t nbits) const { - const std::vector& pieceIndexes = - pieceStatMan_->getRarerPieceIndexes(); - std::vector::const_iterator i = - std::find_if(pieceIndexes.begin(), pieceIndexes.end(), - FindRarestPiece(bitfield, nbits)); - if(i == pieceIndexes.end()) { + const std::vector& order = pieceStatMan_->getOrder(); + const std::vector& counts = pieceStatMan_->getCounts(); + int min = std::numeric_limits::max(); + size_t bestIdx = nbits; + for(size_t i = 0; i < nbits; ++i) { + size_t idx = order[i]; + if(bitfield::test(bitfield, nbits, idx) && counts[idx] < min) { + min = counts[idx]; + bestIdx = idx; + } + } + if(bestIdx == nbits) { return false; } else { - index = *i; + index = bestIdx; return true; } } diff --git a/test/PieceStatManTest.cc b/test/PieceStatManTest.cc index 3ddcdb4f..b66e142a 100644 --- a/test/PieceStatManTest.cc +++ b/test/PieceStatManTest.cc @@ -31,56 +31,33 @@ void PieceStatManTest::testAddPieceStats_index() PieceStatMan pieceStatMan(10, false); pieceStatMan.addPieceStats(1); { - size_t indexes[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 1 }; - size_t counts[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; - - const std::vector& statsidx(pieceStatMan.getRarerPieceIndexes()); - const std::vector >& stats - (pieceStatMan.getPieceStats()); - - CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size()); - + int ans[] = { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; + const std::vector& order(pieceStatMan.getOrder()); + const std::vector& counts(pieceStatMan.getCounts()); for(size_t i = 0; i < 10; ++i) { - CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]); - CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount()); + CPPUNIT_ASSERT_EQUAL(i, order[i]); + CPPUNIT_ASSERT_EQUAL(ans[i], counts[i]); } } - pieceStatMan.addPieceStats(1); - { - size_t indexes[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 1 }; - size_t counts[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 }; - - const std::vector& statsidx(pieceStatMan.getRarerPieceIndexes()); - const std::vector >& stats - (pieceStatMan.getPieceStats()); - + int ans[] = { 0, 2, 0, 0, 0, 0, 0, 0, 0, 0 }; + const std::vector& counts(pieceStatMan.getCounts()); for(size_t i = 0; i < 10; ++i) { - CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]); - CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount()); + CPPUNIT_ASSERT_EQUAL(ans[i], counts[i]); } } - pieceStatMan.addPieceStats(3); pieceStatMan.addPieceStats(9); pieceStatMan.addPieceStats(3); pieceStatMan.addPieceStats(0); - { - size_t indexes[] = { 2, 4, 5, 6, 7, 8, 0, 9, 1, 3 }; - size_t counts[] = { 0, 0, 0, 0, 0, 0, 1, 1, 2, 2 }; - - const std::vector& statsidx(pieceStatMan.getRarerPieceIndexes()); - const std::vector >& stats - (pieceStatMan.getPieceStats()); - + int ans[] = { 1, 2, 0, 2, 0, 0, 0, 0, 0, 1 }; + const std::vector& counts(pieceStatMan.getCounts()); for(size_t i = 0; i < 10; ++i) { - CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]); - CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount()); + CPPUNIT_ASSERT_EQUAL(ans[i], counts[i]); } } - } void PieceStatManTest::testAddPieceStats_bitfield() @@ -89,36 +66,18 @@ void PieceStatManTest::testAddPieceStats_bitfield() const unsigned char bitfield[] = { 0xaa, 0x80 }; pieceStatMan.addPieceStats(bitfield, sizeof(bitfield)); { - size_t indexes[] = { 1, 3, 5, 7, 9, 0, 2, 4, 6, 8 }; - size_t counts[] = { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 }; - - const std::vector& statsidx(pieceStatMan.getRarerPieceIndexes()); - const std::vector >& stats - (pieceStatMan.getPieceStats()); - - CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size()); - + int ans[] = { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 }; + const std::vector& counts(pieceStatMan.getCounts()); for(size_t i = 0; i < 10; ++i) { - CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]); - CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount()); + CPPUNIT_ASSERT_EQUAL(ans[i], counts[i]); } } - pieceStatMan.addPieceStats(bitfield, sizeof(bitfield)); - { - size_t indexes[] = { 1, 3, 5, 7, 9, 0, 2, 4, 6, 8 }; - size_t counts[] = { 0, 0, 0, 0, 0, 2, 2, 2, 2, 2 }; - - const std::vector& statsidx(pieceStatMan.getRarerPieceIndexes()); - const std::vector >& stats - (pieceStatMan.getPieceStats()); - - CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size()); - + int ans[] = { 2, 0, 2, 0, 2, 0, 2, 0, 2, 0 }; + const std::vector& counts(pieceStatMan.getCounts()); for(size_t i = 0; i < 10; ++i) { - CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]); - CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount()); + CPPUNIT_ASSERT_EQUAL(ans[i], counts[i]); } } } @@ -126,13 +85,10 @@ void PieceStatManTest::testAddPieceStats_bitfield() void PieceStatManTest::testUpdatePieceStats() { PieceStatMan pieceStatMan(10, false); - const unsigned char bitfield[] = { 0xff, 0xc0 }; pieceStatMan.addPieceStats(bitfield, sizeof(bitfield)); - const unsigned char oldBitfield[] = { 0xf0, 0x00 }; const unsigned char newBitfield[] = { 0x1f, 0x00 }; - pieceStatMan.updatePieceStats(newBitfield, sizeof(newBitfield), oldBitfield); { // idx: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 @@ -141,19 +97,10 @@ void PieceStatManTest::testUpdatePieceStats() // new: 0, 0, 0, 1, 1, 1, 1, 1, 0, 0 // --------------------------------- // res: 0, 0, 0, 1, 2, 2, 2, 2, 1, 1 - - size_t indexes[] = { 0, 1, 2, 3, 8, 9, 4, 5, 6, 7 }; - size_t counts[] = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 2 }; - - const std::vector& statsidx(pieceStatMan.getRarerPieceIndexes()); - const std::vector >& stats - (pieceStatMan.getPieceStats()); - - CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size()); - + int ans[] = { 0, 0, 0, 1, 2, 2, 2, 2, 1, 1 }; + const std::vector& counts(pieceStatMan.getCounts()); for(size_t i = 0; i < 10; ++i) { - CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]); - CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount()); + CPPUNIT_ASSERT_EQUAL(ans[i], counts[i]); } } } @@ -161,12 +108,9 @@ void PieceStatManTest::testUpdatePieceStats() void PieceStatManTest::testSubtractPieceStats() { PieceStatMan pieceStatMan(10, false); - const unsigned char bitfield[] = { 0xf0, 0x00 }; pieceStatMan.addPieceStats(bitfield, sizeof(bitfield)); - const unsigned char newBitfield[] = { 0x3f, 0x00 }; - pieceStatMan.subtractPieceStats(newBitfield, sizeof(newBitfield)); { // idx: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 @@ -174,19 +118,10 @@ void PieceStatManTest::testSubtractPieceStats() // new: 0, 0, 1, 1, 1, 1, 1, 1, 0, 0 // --------------------------------- // res: 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 - - size_t indexes[] = { 2, 3, 4, 5, 6, 7, 8, 9, 0, 1 }; - size_t counts[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 }; - - const std::vector& statsidx(pieceStatMan.getRarerPieceIndexes()); - const std::vector >& stats - (pieceStatMan.getPieceStats()); - - CPPUNIT_ASSERT_EQUAL((size_t)10, stats.size()); - + int ans[] = { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; + const std::vector& counts(pieceStatMan.getCounts()); for(size_t i = 0; i < 10; ++i) { - CPPUNIT_ASSERT_EQUAL(indexes[i], statsidx[i]); - CPPUNIT_ASSERT_EQUAL(counts[i], stats[statsidx[i]]->getCount()); + CPPUNIT_ASSERT_EQUAL(ans[i], counts[i]); } } }