introduce a prio_index_t type (#1453)

* introduce a prio_index_t type for indexing into the priority sorted piece list, m_pieces, in piece_picker

* some piece picker simplification

* fix msvc warning for prio_index_t
This commit is contained in:
Arvid Norberg 2016-12-26 08:25:50 -08:00 committed by GitHub
parent 5ed0086b51
commit 42a27b3ebc
4 changed files with 180 additions and 113 deletions

View File

@ -66,6 +66,30 @@ namespace libtorrent { namespace aux {
{ return IndexType(static_cast<underlying_index>(this->size())); }
};
template <typename Iter>
struct iterator_range
{
Iter _begin, _end;
Iter begin() { return _begin; }
Iter end() { return _end; }
};
template <typename T, typename IndexType>
iterator_range<T*> range(vector<T, IndexType>& vec
, IndexType begin, IndexType end)
{
using type = typename IndexType::underlying_type;
return { vec.data() + static_cast<type>(begin), vec.data() + static_cast<type>(end) };
}
template <typename T, typename IndexType>
iterator_range<T const*> range(vector<T, IndexType> const& vec
, IndexType begin, IndexType end)
{
using type = typename IndexType::underlying_type;
return { vec.data() + static_cast<type>(begin), vec.data() + static_cast<type>(end) };
}
}}
#endif

View File

@ -67,6 +67,9 @@ namespace libtorrent
struct counters;
struct torrent_peer;
struct prio_index_tag_t {};
using prio_index_t = aux::strong_typedef<int, prio_index_tag_t>;
class TORRENT_EXTRA_EXPORT piece_picker
{
public:
@ -405,7 +408,7 @@ namespace libtorrent
#if TORRENT_USE_INVARIANT_CHECKS
void check_piece_state() const;
// used in debug mode
void verify_priority(int start, int end, int prio) const;
void verify_priority(prio_index_t start, prio_index_t end, int prio) const;
void verify_pick(std::vector<piece_block> const& picked
, typed_bitfield<piece_index_t> const& bits) const;
@ -569,19 +572,29 @@ namespace libtorrent
std::uint32_t piece_priority : 3;
// index in to the piece_info vector
std::uint32_t index;
prio_index_t index;
#ifdef TORRENT_DEBUG_REFCOUNTS
// all the peers that have this piece
std::set<const torrent_peer*> have_peers;
#endif
#ifdef _MSC_VER
#pragma warning(push, 1)
#pragma warning(disable : 4268)
#endif
// index is set to this to indicate that we have the
// piece. There is no entry for the piece in the
// buckets if this is the case.
constexpr static prio_index_t we_have_index{-1};
#ifdef _MSC_VER
#pragma warning(pop)
#endif
enum : std::uint32_t
{
// index is set to this to indicate that we have the
// piece. There is no entry for the piece in the
// buckets if this is the case.
we_have_index = 0xffffffff,
// the priority value that means the piece is filtered
filter_priority = 0,
// the max number the peer count can hold
@ -590,7 +603,7 @@ namespace libtorrent
bool have() const { return index == we_have_index; }
void set_have() { index = we_have_index; TORRENT_ASSERT(have()); }
void set_not_have() { index = 0; TORRENT_ASSERT(!have()); }
void set_not_have() { index = prio_index_t(0); TORRENT_ASSERT(!have()); }
bool downloading() const { return download_state != piece_open; }
bool filtered() const { return piece_priority == filter_priority; }
@ -663,20 +676,23 @@ namespace libtorrent
void update_pieces() const;
prio_index_t priority_begin(int prio) const;
prio_index_t priority_end(int prio) const;
// fills in the range [start, end) of pieces in
// m_pieces that have priority 'prio'
std::pair<int, int> priority_range(int prio);
std::pair<prio_index_t, prio_index_t> priority_range(int prio) const;
// adds the piece 'index' to m_pieces
void add(piece_index_t index);
// removes the piece with the given priority and the
// elem_index in the m_pieces vector
void remove(int priority, int elem_index);
void remove(int priority, prio_index_t elem_index);
// updates the position of the piece with the given
// priority and the elem_index in the m_pieces vector
void update(int priority, int elem_index);
void update(int priority, prio_index_t elem_index);
// shuffles the given piece inside it's priority range
void shuffle(int priority, int elem_index);
void shuffle(int priority, prio_index_t elem_index);
std::vector<downloading_piece>::iterator add_download_piece(piece_index_t index);
void erase_download_piece(std::vector<downloading_piece>::iterator i);
@ -713,12 +729,12 @@ namespace libtorrent
// this vector contains all piece indices that are pickable
// sorted by priority. Pieces are in random random order
// among pieces with the same priority
mutable std::vector<piece_index_t> m_pieces;
mutable aux::vector<piece_index_t, prio_index_t> m_pieces;
// these are indices to the priority boundaries inside
// the m_pieces vector. priority 0 always start at
// 0, priority 1 starts at m_priority_boundaries[0] etc.
mutable std::vector<int> m_priority_boundaries;
mutable std::vector<prio_index_t> m_priority_boundaries;
// each piece that's currently being downloaded has an entry in this list
// with block allocations. i.e. it says which parts of the piece that is

View File

@ -44,11 +44,15 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent {
namespace aux {
template <typename Tag>
struct difference_tag {};
template<typename UnderlyingType, typename Tag
, typename Cond = typename std::enable_if<std::is_integral<UnderlyingType>::value>::type>
struct strong_typedef
{
using underlying_type = UnderlyingType;
using diff_type = strong_typedef<UnderlyingType, difference_tag<Tag>>;
constexpr strong_typedef(strong_typedef const& rhs) : m_val(rhs.m_val) {}
strong_typedef() = default;
@ -71,6 +75,20 @@ namespace aux {
strong_typedef operator++(int) { return strong_typedef{m_val++}; }
strong_typedef operator--(int) { return strong_typedef{m_val--}; }
friend diff_type operator-(strong_typedef lhs, strong_typedef rhs)
{ return diff_type{lhs.m_val - rhs.m_val}; }
friend strong_typedef operator+(strong_typedef lhs, diff_type rhs)
{ return strong_typedef{lhs.m_val + static_cast<UnderlyingType>(rhs)}; }
friend strong_typedef operator+(diff_type lhs, strong_typedef rhs)
{ return strong_typedef{static_cast<UnderlyingType>(lhs) + rhs.m_val}; }
friend strong_typedef operator-(strong_typedef lhs, diff_type rhs)
{ return strong_typedef{lhs.m_val - static_cast<UnderlyingType>(rhs)}; }
strong_typedef& operator+=(diff_type rhs)
{ m_val += static_cast<UnderlyingType>(rhs); return *this; }
strong_typedef& operator-=(diff_type rhs)
{ m_val -= static_cast<UnderlyingType>(rhs); return *this; }
strong_typedef& operator=(strong_typedef rhs) { m_val = rhs.m_val; return *this; }
private:
UnderlyingType m_val;

View File

@ -65,8 +65,10 @@ namespace libtorrent
std::numeric_limits<piece_index_t>::max()
, std::numeric_limits<int>::max());
constexpr prio_index_t piece_picker::piece_pos::we_have_index;
piece_picker::piece_picker()
: m_priority_boundaries(1, int(m_pieces.size()))
: m_priority_boundaries(1, m_pieces.end_index())
{
#ifdef TORRENT_PICKER_LOG
std::cerr << "[" << this << "] " << "new piece_picker" << std::endl;
@ -105,7 +107,7 @@ namespace libtorrent
{
i->peer_count = 0;
i->download_state = piece_pos::piece_open;
i->index = 0;
i->index = prio_index_t(0);
#ifdef TORRENT_DEBUG_REFCOUNTS
i->have_peers.clear();
#endif
@ -119,10 +121,6 @@ namespace libtorrent
m_reverse_cursor > piece_index_t(0) && (i->have() || i->filtered());
++i, --m_reverse_cursor);
// the piece index is stored in 20 bits, which limits the allowed
// number of pieces somewhat
TORRENT_ASSERT(m_piece_map.size() < piece_pos::we_have_index);
m_blocks_per_piece = std::uint16_t(blocks_per_piece);
m_blocks_in_last_piece = std::uint16_t(blocks_in_last_piece);
if (m_blocks_in_last_piece == 0) m_blocks_in_last_piece = std::uint16_t(blocks_per_piece);
@ -342,16 +340,14 @@ namespace libtorrent
}
}
void piece_picker::verify_priority(int const range_start
, int const range_end
void piece_picker::verify_priority(prio_index_t const range_start
, prio_index_t const range_end
, int const prio) const
{
TORRENT_ASSERT(range_start <= range_end);
TORRENT_ASSERT(range_end <= int(m_pieces.size()));
for (auto i = m_pieces.begin() + range_start
, end(m_pieces.begin() + range_end); i != end; ++i)
TORRENT_ASSERT(range_end <= m_pieces.end_index());
for (auto index : range(m_pieces, range_start, range_end))
{
piece_index_t const index = *i;
int p = m_piece_map[index].priority(this);
TORRENT_ASSERT(p == prio);
}
@ -368,16 +364,14 @@ namespace libtorrent
return;
}
for (int b : m_priority_boundaries)
{
for (prio_index_t b : m_priority_boundaries)
std::cerr << b << " ";
}
std::cerr << std::endl;
int index = 0;
prio_index_t index(0);
std::cerr << "[" << this << "] ";
std::vector<int>::const_iterator j = m_priority_boundaries.begin();
for (auto i = m_pieces.begin()
, end(m_pieces.end()); i != end; ++i, ++index)
auto j = m_priority_boundaries.begin();
for (auto i = m_pieces.begin(), end(m_pieces.end()); i != end; ++i, ++index)
{
if (limit == 0)
{
@ -424,8 +418,8 @@ namespace libtorrent
// make sure the priority boundaries are monotonically increasing. The
// difference between two cursors cannot be negative, but ranges are
// allowed to be empty.
int last = 0;
for (int b : m_priority_boundaries)
prio_index_t last(0);
for (prio_index_t b : m_priority_boundaries)
{
TORRENT_ASSERT(b >= last);
last = b;
@ -545,14 +539,14 @@ namespace libtorrent
{
TORRENT_ASSERT(!m_priority_boundaries.empty());
int prio = 0;
int start = 0;
for (int b : m_priority_boundaries)
prio_index_t start(0);
for (prio_index_t b : m_priority_boundaries)
{
verify_priority(start, b, prio);
++prio;
start = b;
}
TORRENT_ASSERT(m_priority_boundaries.back() == int(m_pieces.size()));
TORRENT_ASSERT(m_priority_boundaries.back() == m_pieces.end_index());
}
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
@ -582,10 +576,9 @@ namespace libtorrent
int num_filtered = 0;
int num_have_filtered = 0;
int num_have = 0;
for (std::vector<piece_pos>::const_iterator i = m_piece_map.begin();
i != m_piece_map.end(); ++i)
piece_index_t piece(0);
for (auto i = m_piece_map.begin(); i != m_piece_map.end(); ++i, ++piece)
{
piece_index_t const index = piece_index_t(int(i - m_piece_map.begin()));
piece_pos const& p = *i;
if (p.filtered())
@ -604,12 +597,12 @@ namespace libtorrent
if (p.index == piece_pos::we_have_index)
{
TORRENT_ASSERT(t == nullptr || t->have_piece(index));
TORRENT_ASSERT(t == nullptr || t->have_piece(piece));
TORRENT_ASSERT(p.downloading() == false);
}
if (t != nullptr)
TORRENT_ASSERT(!t->have_piece(index));
TORRENT_ASSERT(!t->have_piece(piece));
int const prio = p.priority(this);
@ -632,8 +625,8 @@ namespace libtorrent
TORRENT_ASSERT(prio < int(m_priority_boundaries.size()));
if (prio >= 0)
{
TORRENT_ASSERT(p.index < m_pieces.size());
TORRENT_ASSERT(m_pieces[p.index] == index);
TORRENT_ASSERT(p.index < m_pieces.end_index());
TORRENT_ASSERT(m_pieces[p.index] == piece);
}
else
{
@ -641,29 +634,29 @@ namespace libtorrent
// make sure there's no entry
// with this index. (there shouldn't
// be since the priority is -1)
TORRENT_ASSERT(std::count(m_pieces.begin(), m_pieces.end(), index) == 0);
TORRENT_ASSERT(std::count(m_pieces.begin(), m_pieces.end(), piece) == 0);
}
}
int const count_downloading = int(std::count_if(
m_downloads[piece_pos::piece_downloading].begin()
, m_downloads[piece_pos::piece_downloading].end()
, has_index(index)));
, has_index(piece)));
int const count_full = int(std::count_if(
m_downloads[piece_pos::piece_full].begin()
, m_downloads[piece_pos::piece_full].end()
, has_index(index)));
, has_index(piece)));
int const count_finished = int(std::count_if(
m_downloads[piece_pos::piece_finished].begin()
, m_downloads[piece_pos::piece_finished].end()
, has_index(index)));
, has_index(piece)));
int const count_zero = int(std::count_if(
m_downloads[piece_pos::piece_zero_prio].begin()
, m_downloads[piece_pos::piece_zero_prio].end()
, has_index(index)));
, has_index(piece)));
TORRENT_ASSERT(i->download_queue() == piece_pos::piece_open
|| count_zero + count_downloading + count_full
@ -742,15 +735,25 @@ namespace libtorrent
return std::make_pair(min_availability + m_seeds, fraction_part * 1000 / num_pieces);
}
std::pair<int, int> piece_picker::priority_range(int const prio)
prio_index_t piece_picker::priority_begin(int const prio) const
{
TORRENT_ASSERT(prio >= 0);
TORRENT_ASSERT(prio < int(m_priority_boundaries.size()) || m_dirty);
std::pair<int, int> const ret{
prio == 0 ? 0 : m_priority_boundaries[prio-1]
, m_priority_boundaries[prio]};
TORRENT_ASSERT(ret.first <= ret.second);
return ret;
TORRENT_ASSERT(prio < int(m_priority_boundaries.size()));
return prio == 0 ? prio_index_t(0) : m_priority_boundaries[prio-1];
}
prio_index_t piece_picker::priority_end(int const prio) const
{
TORRENT_ASSERT(prio >= 0);
TORRENT_ASSERT(prio < int(m_priority_boundaries.size()));
return m_priority_boundaries[prio];
}
std::pair<prio_index_t, prio_index_t> piece_picker::priority_range(int const prio) const
{
TORRENT_ASSERT(prio >= 0);
TORRENT_ASSERT(prio < int(m_priority_boundaries.size()));
return { priority_begin(prio), priority_end(prio) };
}
void piece_picker::add(piece_index_t index)
@ -765,14 +768,14 @@ namespace libtorrent
if (priority < 0) return;
if (int(m_priority_boundaries.size()) <= priority)
m_priority_boundaries.resize(priority + 1, int(m_pieces.size()));
m_priority_boundaries.resize(priority + 1, m_pieces.end_index());
TORRENT_ASSERT(int(m_priority_boundaries.size()) >= priority);
auto const range = priority_range(priority);
int new_index = (range.second == range.first)
prio_index_t new_index = (range.second == range.first)
? range.first
: random(range.second - range.first) + range.first;
: prio_index_t(random(static_cast<int>(range.second - range.first)) + static_cast<int>(range.first));
#ifdef TORRENT_PICKER_LOG
std::cerr << "[" << this << "] " << "add " << index << " (" << priority << ")" << std::endl;
@ -786,14 +789,14 @@ namespace libtorrent
for (;;)
{
TORRENT_ASSERT(new_index < int(m_pieces.size()));
TORRENT_ASSERT(new_index < m_pieces.end_index());
{
piece_index_t temp = m_pieces[new_index];
m_pieces[new_index] = index;
m_piece_map[index].index = new_index;
index = temp;
}
int temp = -1;
prio_index_t temp(-1);
do
{
temp = m_priority_boundaries[priority]++;
@ -808,11 +811,11 @@ namespace libtorrent
<< std::endl;
#endif
if (priority >= int(m_priority_boundaries.size())) break;
TORRENT_ASSERT(temp >= 0);
TORRENT_ASSERT(temp >= prio_index_t(0));
}
if (index != piece_index_t(-1))
{
TORRENT_ASSERT(new_index == int(m_pieces.size() - 1));
TORRENT_ASSERT(new_index == prev(m_pieces.end_index()));
m_pieces[new_index] = index;
m_piece_map[index].index = new_index;
@ -822,25 +825,23 @@ namespace libtorrent
}
}
void piece_picker::remove(int priority, int elem_index)
void piece_picker::remove(int priority, prio_index_t elem_index)
{
TORRENT_ASSERT(!m_dirty);
TORRENT_ASSERT(priority >= 0);
TORRENT_ASSERT(elem_index < int(m_pieces.size()));
TORRENT_ASSERT(elem_index >= 0);
#ifdef TORRENT_PICKER_LOG
std::cerr << "[" << this << "] " << "remove " << m_pieces[elem_index] << " (" << priority << ")" << std::endl;
#endif
int next_index = elem_index;
prio_index_t next_index = elem_index;
TORRENT_ASSERT(m_piece_map[m_pieces[elem_index]].priority(this) == -1);
for (;;)
{
#ifdef TORRENT_PICKER_LOG
print_pieces();
#endif
TORRENT_ASSERT(elem_index < int(m_pieces.size()));
int temp;
TORRENT_ASSERT(elem_index < m_pieces.end_index());
prio_index_t temp;
do
{
temp = --m_priority_boundaries[priority];
@ -853,14 +854,14 @@ namespace libtorrent
m_pieces[elem_index] = piece;
m_piece_map[piece].index = elem_index;
TORRENT_ASSERT(m_piece_map[piece].priority(this) == priority - 1);
TORRENT_ASSERT(elem_index < int(m_pieces.size() - 1));
TORRENT_ASSERT(elem_index < prev(m_pieces.end_index()));
elem_index = next_index;
if (priority == int(m_priority_boundaries.size()))
break;
}
m_pieces.pop_back();
TORRENT_ASSERT(next_index == int(m_pieces.size()));
TORRENT_ASSERT(next_index == m_pieces.end_index());
#ifdef TORRENT_PICKER_LOG
print_pieces();
#endif
@ -868,11 +869,9 @@ namespace libtorrent
// will update the piece with the given properties (priority, elem_index)
// to place it at the correct position
void piece_picker::update(int priority, int elem_index)
void piece_picker::update(int priority, prio_index_t elem_index)
{
TORRENT_ASSERT(!m_dirty);
TORRENT_ASSERT(elem_index >= 0);
TORRENT_ASSERT(elem_index < int(m_piece_map.size()));
TORRENT_ASSERT(priority >= 0);
TORRENT_ASSERT(int(m_priority_boundaries.size()) > priority);
@ -880,13 +879,13 @@ namespace libtorrent
// priority bucket. If it doesn't, it means this piece changed
// state without updating the corresponding entry in the pieces list
TORRENT_ASSERT(m_priority_boundaries[priority] >= elem_index);
TORRENT_ASSERT(priority == 0 || m_priority_boundaries[priority - 1] <= elem_index);
TORRENT_ASSERT(priority + 1 == int(m_priority_boundaries.size()) || m_priority_boundaries[priority + 1] > elem_index);
TORRENT_ASSERT(elem_index >= priority_begin(priority));
TORRENT_ASSERT(elem_index < priority_end(priority));
piece_index_t const index = m_pieces[elem_index];
// update the piece_map
piece_pos& p = m_piece_map[index];
TORRENT_ASSERT(int(p.index) == elem_index || p.have());
TORRENT_ASSERT(p.index == elem_index || p.have());
int const new_priority = p.priority(this);
@ -899,14 +898,14 @@ namespace libtorrent
}
if (int(m_priority_boundaries.size()) <= new_priority)
m_priority_boundaries.resize(new_priority + 1, int(m_pieces.size()));
m_priority_boundaries.resize(new_priority + 1, m_pieces.end_index());
#ifdef TORRENT_PICKER_LOG
std::cerr << "[" << this << "] " << "update " << index << " (" << priority << "->" << new_priority << ")" << std::endl;
#endif
if (priority > new_priority)
{
int new_index;
prio_index_t new_index;
piece_index_t temp = index;
for (;;)
{
@ -916,14 +915,12 @@ namespace libtorrent
TORRENT_ASSERT(priority > 0);
--priority;
new_index = m_priority_boundaries[priority]++;
TORRENT_ASSERT(new_index >= 0);
TORRENT_ASSERT(new_index < int(m_pieces.size()));
if (temp != m_pieces[new_index])
{
temp = m_pieces[new_index];
m_pieces[elem_index] = temp;
m_piece_map[temp].index = elem_index;
TORRENT_ASSERT(elem_index < int(m_pieces.size()));
TORRENT_ASSERT(elem_index < m_pieces.end_index());
}
elem_index = new_index;
if (priority == new_priority) break;
@ -933,7 +930,7 @@ namespace libtorrent
#endif
m_pieces[elem_index] = index;
m_piece_map[index].index = elem_index;
TORRENT_ASSERT(elem_index < int(m_pieces.size()));
TORRENT_ASSERT(elem_index < m_pieces.end_index());
#ifdef TORRENT_PICKER_LOG
print_pieces();
#endif
@ -945,7 +942,7 @@ namespace libtorrent
}
else
{
int new_index;
prio_index_t new_index;
piece_index_t temp = index;
for (;;)
{
@ -955,14 +952,12 @@ namespace libtorrent
TORRENT_ASSERT(priority >= 0);
TORRENT_ASSERT(priority < int(m_priority_boundaries.size()));
new_index = --m_priority_boundaries[priority];
TORRENT_ASSERT(new_index >= 0);
TORRENT_ASSERT(new_index < int(m_pieces.size()));
if (temp != m_pieces[new_index])
{
temp = m_pieces[new_index];
m_pieces[elem_index] = temp;
m_piece_map[temp].index = elem_index;
TORRENT_ASSERT(elem_index < int(m_pieces.size()));
TORRENT_ASSERT(elem_index < m_pieces.end_index());
}
elem_index = new_index;
++priority;
@ -973,7 +968,7 @@ namespace libtorrent
#endif
m_pieces[elem_index] = index;
m_piece_map[index].index = elem_index;
TORRENT_ASSERT(elem_index < int(m_pieces.size()));
TORRENT_ASSERT(elem_index < m_pieces.end_index());
#ifdef TORRENT_PICKER_LOG
print_pieces();
#endif
@ -985,7 +980,7 @@ namespace libtorrent
}
}
void piece_picker::shuffle(int priority, int elem_index)
void piece_picker::shuffle(int priority, prio_index_t elem_index)
{
#ifdef TORRENT_PICKER_LOG
std::cerr << "[" << this << "] " << "shuffle()" << std::endl;
@ -993,12 +988,12 @@ namespace libtorrent
TORRENT_ASSERT(!m_dirty);
TORRENT_ASSERT(priority >= 0);
TORRENT_ASSERT(elem_index >= 0);
TORRENT_ASSERT(elem_index < int(m_pieces.size()));
TORRENT_ASSERT(elem_index >= prio_index_t(0));
TORRENT_ASSERT(elem_index < m_pieces.end_index());
TORRENT_ASSERT(m_piece_map[m_pieces[elem_index]].priority(this) == priority);
auto const range = priority_range(priority);
int const other_index = random(range.second - range.first - 1) + range.first;
prio_index_t const other_index(random(static_cast<int>(range.second - range.first) - 1) + static_cast<int>(range.first));
if (other_index == elem_index) return;
@ -1429,19 +1424,23 @@ namespace libtorrent
void piece_picker::update_pieces() const
{
TORRENT_ASSERT(m_dirty);
if (m_priority_boundaries.empty()) m_priority_boundaries.resize(1, 0);
if (m_priority_boundaries.empty()) m_priority_boundaries.resize(1, prio_index_t(0));
#ifdef TORRENT_PICKER_LOG
std::cerr << "[" << this << "] " << "update_pieces" << std::endl;
#endif
std::fill(m_priority_boundaries.begin(), m_priority_boundaries.end(), 0);
for (std::vector<piece_pos>::iterator i = m_piece_map.begin()
, end(m_piece_map.end()); i != end; ++i)
// This code is unfortunately not very straight-forward. What we do here
// is to count the number of pieces at every priority level. After this
// first step, m_priority_boundaries will contain *deltas* rather than
// absolute indices. This is fixed up in a second pass below
std::fill(m_priority_boundaries.begin(), m_priority_boundaries.end(), prio_index_t(0));
for (auto& pos : m_piece_map)
{
int prio = i->priority(this);
int prio = pos.priority(this);
if (prio == -1) continue;
if (prio >= int(m_priority_boundaries.size()))
m_priority_boundaries.resize(prio + 1, 0);
i->index = m_priority_boundaries[prio];
m_priority_boundaries.resize(prio + 1, prio_index_t(0));
pos.index = m_priority_boundaries[prio];
++m_priority_boundaries[prio];
}
@ -1449,11 +1448,15 @@ namespace libtorrent
print_pieces();
#endif
// m_priority_boundaries just contain counters of
// each priority level at this point. Now, make the m_priority_boundaries
// be cumulative indices into m_pieces (but m_pieces hasn't been set up
// yet)
int new_size = 0;
for (int& b : m_priority_boundaries)
for (prio_index_t& b : m_priority_boundaries)
{
new_size += b;
b = new_size;
new_size += static_cast<int>(b);
b = prio_index_t(new_size);
}
m_pieces.resize(new_size, piece_index_t(0));
@ -1461,26 +1464,32 @@ namespace libtorrent
print_pieces();
#endif
// set up m_pieces to contain valid piece indices, based on piece
// priority. m_piece_map[].index is still just an index relative to the
// respective priority range.
piece_index_t piece = piece_index_t(0);
for (auto i = m_piece_map.begin()
, end(m_piece_map.end()); i != end; ++i, ++piece)
for (auto i = m_piece_map.begin(), end(m_piece_map.end()); i != end; ++i, ++piece)
{
piece_pos& p = *i;
int const prio = p.priority(this);
if (prio == -1) continue;
int const new_index = (prio == 0 ? 0 : m_priority_boundaries[prio - 1]) + p.index;
prio_index_t const new_index(priority_begin(prio)
+ prio_index_t::diff_type(static_cast<int>(p.index)));
m_pieces[new_index] = piece;
}
int start = 0;
for (int b : m_priority_boundaries)
prio_index_t start(0);
for (auto b : m_priority_boundaries)
{
if (start == b) continue;
aux::random_shuffle(&m_pieces[0] + start, &m_pieces[0] + b);
auto r = range(m_pieces, start, b);
aux::random_shuffle(r.begin(), r.end());
start = b;
}
int index = 0;
// this is where we set fix up the m_piece_map[].index to actually map
// back to the piece list ordered by priority (m_pieces)
prio_index_t index(0);
for (auto p : m_pieces)
{
m_piece_map[p].index = index;
@ -1585,7 +1594,7 @@ namespace libtorrent
<< index << ")" << std::endl;
#endif
piece_pos& p = m_piece_map[index];
int const info_index = p.index;
prio_index_t const info_index = p.index;
int const priority = p.priority(this);
TORRENT_ASSERT(priority < int(m_priority_boundaries.size()) || m_dirty);
@ -2068,9 +2077,9 @@ namespace libtorrent
{
for (int i = int(m_priority_boundaries.size()) - 1; i >= 0; --i)
{
int const start = (i == 0) ? 0 : m_priority_boundaries[i - 1];
int const end = m_priority_boundaries[i];
for (int p = end - 1; p >= start; --p)
prio_index_t const start = priority_begin(i);
prio_index_t const end = priority_end(i);
for (prio_index_t p = prev(end); p >= start; --p)
{
pc.inc_stats_counter(counters::piece_picker_reverse_rare_loops);