replaced vector<bool> with a custom bitfield type

This commit is contained in:
Arvid Norberg 2008-05-28 02:35:02 +00:00
parent 523c48e069
commit 68c31e48dc
19 changed files with 370 additions and 112 deletions

View File

@ -195,7 +195,7 @@ peer_plugin
virtual bool on_interested();
virtual bool on_not_interested();
virtual bool on_have(int index);
virtual bool on_bitfield(std::vector<bool> const& bitfield);
virtual bool on_bitfield(bitfield const& bits);
virtual bool on_have_all();
virtual bool on_have_none();
virtual bool on_allowed_fast(int index);

View File

@ -5,6 +5,7 @@ libtorrent/bandwidth_manager.hpp \
libtorrent/bandwidth_limit.hpp \
libtorrent/bandwidth_queue_entry.hpp \
libtorrent/bencode.hpp \
libtorrent/bitfield.hpp \
libtorrent/broadcast_socket.hpp \
libtorrent/buffer.hpp \
libtorrent/connection_queue.hpp \

View File

@ -0,0 +1,241 @@
/*
Copyright (c) 2008, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_BITFIELD_HPP_INCLUDED
#define TORRENT_BITFIELD_HPP_INCLUDED
#include "libtorrent/assert.hpp"
#include "libtorrent/config.hpp"
namespace libtorrent
{
struct TORRENT_EXPORT bitfield
{
bitfield(): m_bytes(0), m_size(0), m_own(false) {}
bitfield(int bits): m_bytes(0), m_size(0)
{ resize(bits); }
bitfield(int bits, bool val): m_bytes(0), m_size(0)
{ resize(bits, val); }
bitfield(char const* bytes, int bits): m_bytes(0), m_size(0)
{ assign(bytes, bits); }
bitfield(bitfield const& rhs): m_bytes(0), m_size(0), m_own(false)
{ assign(rhs.bytes(), rhs.size()); }
void borrow_bytes(char* bytes, int bits)
{
dealloc();
m_bytes = (unsigned char*)bytes;
m_size = bits;
m_own = false;
}
~bitfield() { dealloc(); }
void assign(char const* bytes, int bits)
{ resize(bits); memcpy(m_bytes, bytes, (bits + 7) / 8); }
bool operator[](int index) const
{ return get_bit(index); }
bool get_bit(int index) const
{
TORRENT_ASSERT(index >= 0);
TORRENT_ASSERT(index < m_size);
return m_bytes[index / 8] & (0x80 >> (index & 7));
}
void clear_bit(int index)
{
TORRENT_ASSERT(index >= 0);
TORRENT_ASSERT(index < m_size);
m_bytes[index / 8] &= ~(0x80 >> (index & 7));
}
void set_bit(int index)
{
TORRENT_ASSERT(index >= 0);
TORRENT_ASSERT(index < m_size);
m_bytes[index / 8] |= (0x80 >> (index & 7));
}
std::size_t size() const { return m_size; }
bool empty() const { return m_size == 0; }
char const* bytes() const { return (char*)m_bytes; }
bitfield& operator=(bitfield const& rhs)
{
assign(rhs.bytes(), rhs.size());
return *this;
}
int count() const
{
// 0000, 0001, 0010, 0011, 0100, 0101, 0110, 0111,
// 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111
const static char num_bits[] =
{
0, 1, 1, 2, 1, 2, 2, 3,
1, 2, 2, 3, 2, 3, 3, 4
};
int ret = 0;
const int num_bytes = m_size / 8;
for (int i = 0; i < num_bytes; ++i)
{
ret += num_bits[m_bytes[i] & 0xf] + num_bits[m_bytes[i] >> 4];
}
int rest = m_size - num_bytes * 8;
for (int i = 0; i < rest; ++i)
{
ret += (m_bytes[num_bytes] >> (7-i)) & 1;
}
TORRENT_ASSERT(ret <= m_size);
TORRENT_ASSERT(ret >= 0);
return ret;
}
struct const_iterator
{
friend struct bitfield;
typedef bool value_type;
typedef ptrdiff_t difference_type;
typedef bool const* pointer;
typedef bool& reference;
typedef std::forward_iterator_tag iterator_category;
bool operator*() { return *byte & bit; }
const_iterator& operator++() { inc(); return *this; }
const_iterator operator++(int)
{ const_iterator ret(*this); inc(); return ret; }
const_iterator& operator--() { dec(); return *this; }
const_iterator operator--(int)
{ const_iterator ret(*this); dec(); return ret; }
const_iterator(): byte(0), bit(0x80) {}
bool operator==(const_iterator const& rhs) const
{ return byte == rhs.byte && bit == rhs.bit; }
bool operator!=(const_iterator const& rhs) const
{ return byte != rhs.byte || bit != rhs.bit; }
private:
void inc()
{
TORRENT_ASSERT(byte);
if (bit == 0x01)
{
bit = 0x80;
++byte;
}
else
{
bit >>= 1;
}
}
void dec()
{
TORRENT_ASSERT(byte);
if (bit == 0x80)
{
bit = 0x01;
--byte;
}
else
{
bit <<= 1;
}
}
const_iterator(unsigned char const* ptr, int offset)
: byte(ptr), bit(0x80 >> offset) {}
unsigned char const* byte;
int bit;
};
const_iterator begin() const { return const_iterator(m_bytes, 0); }
const_iterator end() const { return const_iterator(m_bytes + m_size / 8, m_size & 7); }
void resize(int bits, bool val)
{
resize(bits);
if (val) set_all(); else clear_all();
}
void set_all()
{
memset(m_bytes, 0xff, (m_size + 7) / 8);
}
void clear_all()
{
memset(m_bytes, 0x00, (m_size + 7) / 8);
}
void resize(int bits)
{
const int bytes = (bits + 7) / 8;
if (m_bytes)
{
if (m_own)
{
m_bytes = (unsigned char*)realloc(m_bytes, bytes);
m_own = true;
}
else if (bits > m_size)
{
unsigned char* tmp = (unsigned char*)malloc(bytes);
memcpy(tmp, m_bytes, (std::min)((m_size + 7)/ 8, bytes));
m_bytes = tmp;
m_own = true;
}
}
else
{
m_bytes = (unsigned char*)malloc(bytes);
m_own = true;
}
m_size = bits;
}
private:
void dealloc() { if (m_own) free(m_bytes); m_bytes = 0; }
unsigned char* m_bytes;
int m_size; // in bits
bool m_own;
};
}
#endif // TORRENT_BITFIELD_HPP_INCLUDED

View File

@ -209,7 +209,7 @@ namespace libtorrent
void write_not_interested();
void write_request(peer_request const& r);
void write_cancel(peer_request const& r);
void write_bitfield(std::vector<bool> const& bitfield);
void write_bitfield(bitfield const& bits);
void write_have(int index);
void write_piece(peer_request const& r, disk_buffer_holder& buffer);
void write_handshake();

View File

@ -57,6 +57,7 @@ namespace libtorrent
class peer_connection;
class entry;
struct disk_buffer_holder;
struct bitfield;
struct TORRENT_EXPORT torrent_plugin
{
@ -129,7 +130,7 @@ namespace libtorrent
virtual bool on_have(int index)
{ return false; }
virtual bool on_bitfield(std::vector<bool> const& bitfield)
virtual bool on_bitfield(bitfield const& bitfield)
{ return false; }
virtual bool on_have_all()

View File

@ -76,6 +76,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/assert.hpp"
#include "libtorrent/chained_buffer.hpp"
#include "libtorrent/disk_buffer_holder.hpp"
#include "libtorrent/bitfield.hpp"
namespace libtorrent
{
@ -242,7 +243,7 @@ namespace libtorrent
boost::shared_ptr<socket_type> get_socket() const { return m_socket; }
tcp::endpoint const& remote() const { return m_remote; }
std::vector<bool> const& get_bitfield() const;
bitfield const& get_bitfield() const;
std::vector<int> const& allowed_fast();
std::vector<int> const& suggested_pieces() const { return m_suggested_pieces; }
@ -328,7 +329,7 @@ namespace libtorrent
void incoming_interested();
void incoming_not_interested();
void incoming_have(int piece_index);
void incoming_bitfield(std::vector<bool> const& bitfield);
void incoming_bitfield(bitfield const& bits);
void incoming_request(peer_request const& r);
void incoming_piece(peer_request const& p, disk_buffer_holder& data);
void incoming_piece(peer_request const& p, char const* data);
@ -629,7 +630,7 @@ namespace libtorrent
peer_id m_peer_id;
// the pieces the other end have
std::vector<bool> m_have_piece;
bitfield m_have_piece;
// the queue of requests we have got
// from this peer

View File

@ -33,12 +33,11 @@ POSSIBILITY OF SUCH DAMAGE.
#ifndef TORRENT_PEER_INFO_HPP_INCLUDED
#define TORRENT_PEER_INFO_HPP_INCLUDED
#include <vector>
#include "libtorrent/socket.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/size_type.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/bitfield.hpp"
namespace libtorrent
{
@ -96,7 +95,7 @@ namespace libtorrent
size_type total_download;
size_type total_upload;
peer_id pid;
std::vector<bool> pieces;
bitfield pieces;
int upload_limit;
int download_limit;

View File

@ -58,6 +58,7 @@ namespace libtorrent
class torrent;
class peer_connection;
class bitfield;
struct TORRENT_EXPORT piece_block
{
@ -138,7 +139,7 @@ namespace libtorrent
// the vector tells which pieces we already have
// and which we don't have.
void init(std::vector<bool> const& pieces);
void init(bitfield const& pieces);
// increases the peer count for the given piece
// (is used when a HAVE message is received)
@ -147,10 +148,10 @@ namespace libtorrent
// increases the peer count for the given piece
// (is used when a BITFIELD message is received)
void inc_refcount(std::vector<bool> const& bitmask);
void inc_refcount(bitfield const& bitmask);
// decreases the peer count for the given piece
// (used when a peer disconnects)
void dec_refcount(std::vector<bool> const& bitmask);
void dec_refcount(bitfield const& bitmask);
// these will increase and decrease the peer count
// of all pieces. They are used when seeds join
@ -193,7 +194,7 @@ namespace libtorrent
// THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION!
// The last argument is the policy::peer pointer for the peer that
// we'll download from.
void pick_pieces(std::vector<bool> const& pieces
void pick_pieces(bitfield const& pieces
, std::vector<piece_block>& interesting_blocks
, int num_pieces, int prefer_whole_pieces
, void* peer, piece_state_t speed
@ -207,14 +208,14 @@ namespace libtorrent
// blocks to be picked. Blocks are not picked from pieces
// that are being downloaded
int add_blocks(std::vector<int> const& piece_list
, const std::vector<bool>& pieces
, bitfield const& pieces
, std::vector<piece_block>& interesting_blocks
, int num_blocks, int prefer_whole_pieces
, void* peer, std::vector<int> const& ignore) const;
// picks blocks only from downloading pieces
int add_blocks_downloading(
std::vector<bool> const& pieces
bitfield const& pieces
, std::vector<piece_block>& interesting_blocks
, std::vector<piece_block>& backup_blocks
, int num_blocks, int prefer_whole_pieces
@ -280,7 +281,7 @@ namespace libtorrent
void verify_priority(int start, int end, int prio) const;
void check_invariant(const torrent* t = 0) const;
void verify_pick(std::vector<piece_block> const& picked
, std::vector<bool> const& bitfield) const;
, bitfield const& bits) const;
void print_pieces() const;
#endif
@ -302,9 +303,9 @@ namespace libtorrent
friend struct piece_pos;
bool can_pick(int piece, std::vector<bool> const& bitmask) const;
bool can_pick(int piece, bitfield const& bitmask) const;
std::pair<int, int> expand_piece(int piece, int whole_pieces
, std::vector<bool> const& have) const;
, bitfield const& have) const;
struct piece_pos
{

View File

@ -70,6 +70,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/storage.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/bitfield.hpp"
namespace libtorrent
{
@ -79,6 +80,7 @@ namespace libtorrent
class piece_manager;
struct torrent_plugin;
struct bitfield;
namespace aux
{
@ -376,7 +378,7 @@ namespace libtorrent
return m_have_pieces[index];
}
const std::vector<bool>& pieces() const
bitfield const& pieces() const
{ return m_have_pieces; }
int num_pieces() const { return m_num_pieces; }
@ -399,12 +401,12 @@ namespace libtorrent
}
// when we get a bitfield message, this is called for that piece
void peer_has(std::vector<bool> const& bitfield)
void peer_has(bitfield const& bits)
{
if (m_picker.get())
{
TORRENT_ASSERT(!is_seed());
m_picker->inc_refcount(bitfield);
m_picker->inc_refcount(bits);
}
#ifndef NDEBUG
else
@ -729,7 +731,7 @@ namespace libtorrent
// this is an index into m_trackers
// the bitmask that says which pieces we have
std::vector<bool> m_have_pieces;
bitfield m_have_pieces;
// the number of bytes that has been
// downloaded that failed the hash-test

View File

@ -200,7 +200,7 @@ namespace libtorrent
// we potentially could connect to
int connect_candidates;
const std::vector<bool>* pieces;
bitfield const* pieces;
// this is the number of pieces the client has
// downloaded. it is equal to:

View File

@ -35,6 +35,7 @@ $(top_srcdir)/include/libtorrent/bandwidth_manager.hpp \
$(top_srcdir)/include/libtorrent/bandwidth_limit.hpp \
$(top_srcdir)/include/libtorrent/bandwidth_queue_entry.hpp \
$(top_srcdir)/include/libtorrent/bencode.hpp \
$(top_srcdir)/include/libtorrent/bitfield.hpp \
$(top_srcdir)/include/libtorrent/broadcast_socket.hpp \
$(top_srcdir)/include/libtorrent/buffer.hpp \
$(top_srcdir)/include/libtorrent/connection_queue.hpp \

View File

@ -937,21 +937,11 @@ namespace libtorrent
buffer::const_interval recv_buffer = receive_buffer();
std::vector<bool> bitfield;
bitfield bits;
bits.borrow_bytes((char*)recv_buffer.begin
, t->valid_metadata()?get_bitfield().size():(packet_size()-1)*8);
if (!t->valid_metadata())
bitfield.resize((packet_size() - 1) * 8);
else
bitfield.resize(get_bitfield().size());
// if we don't have metadata yet
// just remember the bitmask
// don't update the piecepicker
// (since it doesn't exist yet)
for (int i = 0; i < (int)bitfield.size(); ++i)
bitfield[i] = (recv_buffer[1 + (i>>3)] & (1 << (7 - (i&7)))) != 0;
incoming_bitfield(bitfield);
incoming_bitfield(bits);
}
// -----------------------------
@ -1426,7 +1416,7 @@ namespace libtorrent
send_buffer(msg, sizeof(msg));
}
void bt_peer_connection::write_bitfield(std::vector<bool> const& bitfield)
void bt_peer_connection::write_bitfield(bitfield const& bits)
{
INVARIANT_CHECK;
@ -1459,12 +1449,14 @@ namespace libtorrent
return;
}
int num_pieces = bitfield.size();
int num_pieces = bits.size();
int lazy_pieces[50];
int num_lazy_pieces = 0;
int lazy_piece = 0;
TORRENT_ASSERT(t->is_seed() == (std::count(bitfield.begin(), bitfield.end(), true) == num_pieces));
TORRENT_ASSERT(t->is_seed() == (bits.count()
== num_pieces));
if (t->is_seed() && m_ses.settings().lazy_bitfields)
{
num_lazy_pieces = (std::min)(50, num_pieces / 10);
@ -1491,7 +1483,7 @@ namespace libtorrent
++lazy_piece;
continue;
}
if (bitfield[i]) bitfield_string << "1";
if (bits[i]) bitfield_string << "1";
else bitfield_string << "0";
}
bitfield_string << "\n";
@ -1506,18 +1498,9 @@ namespace libtorrent
detail::write_int32(packet_size - 4, i.begin);
detail::write_uint8(msg_bitfield, i.begin);
std::fill(i.begin, i.end, 0);
for (int c = 0; c < num_pieces; ++c)
{
if (lazy_piece < num_lazy_pieces
&& lazy_pieces[lazy_piece] == c)
{
++lazy_piece;
continue;
}
if (bitfield[c])
i.begin[c >> 3] |= 1 << (7 - (c & 7));
}
memcpy(i.begin, bits.bytes(), packet_size - 5);
for (int c = 0; c < num_lazy_pieces; ++c)
i.begin[lazy_pieces[c] / 8] &= ~(0x80 >> (lazy_pieces[c] & 7));
TORRENT_ASSERT(i.end - i.begin == (num_pieces + 7) / 8);
#ifndef NDEBUG

View File

@ -326,7 +326,7 @@ namespace libtorrent
TORRENT_ASSERT(t);
bool interested = false;
const std::vector<bool>& we_have = t->pieces();
bitfield const& we_have = t->pieces();
for (int j = 0; j != (int)we_have.size(); ++j)
{
if (!we_have[j]
@ -579,7 +579,7 @@ namespace libtorrent
m_statistics.add_stat(downloaded, uploaded);
}
std::vector<bool> const& peer_connection::get_bitfield() const
bitfield const& peer_connection::get_bitfield() const
{
return m_have_piece;
}
@ -749,7 +749,7 @@ namespace libtorrent
// if we don't have valid metadata yet,
// leave the vector unallocated
TORRENT_ASSERT(m_num_pieces == 0);
std::fill(m_have_piece.begin(), m_have_piece.end(), false);
m_have_piece.clear_all();
TORRENT_ASSERT(!m_torrent.expired());
}
@ -1082,7 +1082,7 @@ namespace libtorrent
}
else
{
m_have_piece[index] = true;
m_have_piece.set_bit(index);
// only update the piece_picker if
// we have the metadata and if
@ -1127,7 +1127,7 @@ namespace libtorrent
// --------- BITFIELD ----------
// -----------------------------
void peer_connection::incoming_bitfield(std::vector<bool> const& bitfield)
void peer_connection::incoming_bitfield(bitfield const& bits)
{
INVARIANT_CHECK;
@ -1138,7 +1138,7 @@ namespace libtorrent
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
if ((*i)->on_bitfield(bitfield)) return;
if ((*i)->on_bitfield(bits)) return;
}
#endif
@ -1147,9 +1147,9 @@ namespace libtorrent
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string() << " <== BITFIELD ";
for (int i = 0; i < int(bitfield.size()); ++i)
for (int i = 0; i < int(bits.size()); ++i)
{
if (bitfield[i]) (*m_logger) << "1";
if (bits[i]) (*m_logger) << "1";
else (*m_logger) << "0";
}
(*m_logger) << "\n";
@ -1158,10 +1158,10 @@ namespace libtorrent
// if we don't have the metedata, we cannot
// verify the bitfield size
if (t->valid_metadata()
&& (bitfield.size() / 8) != (m_have_piece.size() / 8))
&& (bits.size() / 8) != (m_have_piece.size() / 8))
{
std::stringstream msg;
msg << "got bitfield with invalid size: " << (bitfield.size() / 8)
msg << "got bitfield with invalid size: " << (bits.size() / 8)
<< "bytes. expected: " << (m_have_piece.size() / 8)
<< " bytes";
disconnect(msg.str().c_str(), 2);
@ -1174,15 +1174,15 @@ namespace libtorrent
// (since it doesn't exist yet)
if (!t->ready_for_connections())
{
m_have_piece = bitfield;
m_num_pieces = std::count(bitfield.begin(), bitfield.end(), true);
if (m_peer_info) m_peer_info->seed = (m_num_pieces == int(bitfield.size()));
m_have_piece = bits;
m_num_pieces = bits.count();
if (m_peer_info) m_peer_info->seed = (m_num_pieces == int(bits.size()));
return;
}
TORRENT_ASSERT(t->valid_metadata());
int num_pieces = std::count(bitfield.begin(), bitfield.end(), true);
int num_pieces = bits.count();
if (num_pieces == int(m_have_piece.size()))
{
#ifdef TORRENT_VERBOSE_LOGGING
@ -1197,7 +1197,7 @@ namespace libtorrent
return;
}
std::fill(m_have_piece.begin(), m_have_piece.end(), true);
m_have_piece.set_all();
m_num_pieces = num_pieces;
t->peer_has_all();
if (!t->is_finished())
@ -1211,11 +1211,11 @@ namespace libtorrent
bool interesting = false;
if (!t->is_seed())
{
t->peer_has(bitfield);
t->peer_has(bits);
for (int i = 0; i < (int)m_have_piece.size(); ++i)
{
bool have = bitfield[i];
bool have = bits[i];
if (have && !m_have_piece[i])
{
if (!t->have_piece(i) && t->picker().piece_priority(i) != 0)
@ -1229,7 +1229,7 @@ namespace libtorrent
}
}
m_have_piece = bitfield;
m_have_piece = bits;
m_num_pieces = num_pieces;
if (interesting) t->get_policy().peer_is_interesting(*this);
@ -1764,7 +1764,7 @@ namespace libtorrent
}
TORRENT_ASSERT(!m_have_piece.empty());
std::fill(m_have_piece.begin(), m_have_piece.end(), true);
m_have_piece.set_all();
m_num_pieces = m_have_piece.size();
t->peer_has_all();

View File

@ -42,6 +42,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/piece_picker.hpp"
#include "libtorrent/aux_/session_impl.hpp"
#include "libtorrent/bitfield.hpp"
#ifndef NDEBUG
#include "libtorrent/peer_connection.hpp"
@ -122,16 +123,17 @@ namespace libtorrent
}
// pieces is a bitmask with the pieces we have
void piece_picker::init(std::vector<bool> const& pieces)
void piece_picker::init(bitfield const& pieces)
{
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
#ifndef NDEBUG
m_files_checked_called = true;
#endif
for (std::vector<bool>::const_iterator i = pieces.begin();
i != pieces.end(); ++i)
int index = 0;
for (bitfield::const_iterator i = pieces.begin();
i != pieces.end(); ++i, ++index)
{
int index = static_cast<int>(i - pieces.begin());
TORRENT_ASSERT(index < pieces.size());
piece_pos& p = m_piece_map[index];
if (*i) we_have(index);
else TORRENT_ASSERT(p.index == 0);
@ -214,15 +216,15 @@ namespace libtorrent
#ifndef NDEBUG
void piece_picker::verify_pick(std::vector<piece_block> const& picked
, std::vector<bool> const& bitfield) const
, bitfield const& bits) const
{
TORRENT_ASSERT(bitfield.size() == m_piece_map.size());
TORRENT_ASSERT(bits.size() == m_piece_map.size());
for (std::vector<piece_block>::const_iterator i = picked.begin()
, end(picked.end()); i != end; ++i)
{
TORRENT_ASSERT(i->piece_index >= 0);
TORRENT_ASSERT(i->piece_index < int(bitfield.size()));
TORRENT_ASSERT(bitfield[i->piece_index]);
TORRENT_ASSERT(i->piece_index < int(bits.size()));
TORRENT_ASSERT(bits[i->piece_index]);
TORRENT_ASSERT(!m_piece_map[i->piece_index].have());
}
}
@ -887,14 +889,14 @@ namespace libtorrent
if (prev_priority >= 0) update(prev_priority, p.index);
}
void piece_picker::inc_refcount(std::vector<bool> const& bitmask)
void piece_picker::inc_refcount(bitfield const& bitmask)
{
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
TORRENT_ASSERT(bitmask.size() == m_piece_map.size());
int index = 0;
bool updated = false;
for (std::vector<bool>::const_iterator i = bitmask.begin()
for (bitfield::const_iterator i = bitmask.begin()
, end(bitmask.end()); i != end; ++i, ++index)
{
if (*i)
@ -907,14 +909,14 @@ namespace libtorrent
if (updated && m_sequential_download == -1) m_dirty = true;
}
void piece_picker::dec_refcount(std::vector<bool> const& bitmask)
void piece_picker::dec_refcount(bitfield const& bitmask)
{
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
TORRENT_ASSERT(bitmask.size() == m_piece_map.size());
int index = 0;
bool updated = false;
for (std::vector<bool>::const_iterator i = bitmask.begin()
for (bitfield::const_iterator i = bitmask.begin()
, end(bitmask.end()); i != end; ++i, ++index)
{
if (*i)
@ -1156,7 +1158,7 @@ namespace libtorrent
// to pick blocks from the same pieces as fast peers, and vice
// versa. Downloading pieces are marked as being fast, medium
// or slow once they're started.
void piece_picker::pick_pieces(const std::vector<bool>& pieces
void piece_picker::pick_pieces(bitfield const& pieces
, std::vector<piece_block>& interesting_blocks
, int num_blocks, int prefer_whole_pieces
, void* peer, piece_state_t speed, bool rarest_first
@ -1279,7 +1281,7 @@ namespace libtorrent
, backup_blocks.begin(), backup_blocks.end());
}
bool piece_picker::can_pick(int piece, std::vector<bool> const& bitmask) const
bool piece_picker::can_pick(int piece, bitfield const& bitmask) const
{
TORRENT_ASSERT(piece >= 0 && piece < int(m_piece_map.size()));
return bitmask[piece]
@ -1326,7 +1328,7 @@ namespace libtorrent
}
int piece_picker::add_blocks(std::vector<int> const& piece_list
, std::vector<bool> const& pieces
, bitfield const& pieces
, std::vector<piece_block>& interesting_blocks
, int num_blocks, int prefer_whole_pieces
, void* peer, std::vector<int> const& ignore) const
@ -1388,7 +1390,7 @@ namespace libtorrent
return num_blocks;
}
int piece_picker::add_blocks_downloading(std::vector<bool> const& pieces
int piece_picker::add_blocks_downloading(bitfield const& pieces
, std::vector<piece_block>& interesting_blocks
, std::vector<piece_block>& backup_blocks
, int num_blocks, int prefer_whole_pieces
@ -1580,7 +1582,7 @@ namespace libtorrent
}
std::pair<int, int> piece_picker::expand_piece(int piece, int whole_pieces
, std::vector<bool> const& have) const
, bitfield const& have) const
{
if (whole_pieces == 0) return std::make_pair(piece, piece + 1);

View File

@ -244,7 +244,7 @@ namespace libtorrent
busy_pieces.reserve(num_requests);
std::vector<int> const& suggested = c.suggested_pieces();
std::vector<bool> const& bitfield = c.get_bitfield();
bitfield const& bits = c.get_bitfield();
if (c.has_peer_choked())
{
@ -254,10 +254,10 @@ namespace libtorrent
std::vector<int> const& allowed_fast = c.allowed_fast();
// build a bitmask with only the allowed pieces in it
std::vector<bool> mask(c.get_bitfield().size(), false);
bitfield mask(c.get_bitfield().size(), false);
for (std::vector<int>::const_iterator i = allowed_fast.begin()
, end(allowed_fast.end()); i != end; ++i)
if (bitfield[*i]) mask[*i] = true;
if (bits[*i]) mask.set_bit(*i);
p.pick_pieces(mask, interesting_pieces
, num_requests, prefer_whole_pieces, c.peer_info_struct()
@ -273,7 +273,7 @@ namespace libtorrent
// the last argument is if we should prefer whole pieces
// for this peer. If we're downloading one piece in 20 seconds
// then use this mode.
p.pick_pieces(bitfield, interesting_pieces
p.pick_pieces(bits, interesting_pieces
, num_requests, prefer_whole_pieces, c.peer_info_struct()
, state, rarest_first, c.on_parole(), suggested);
}

View File

@ -447,7 +447,7 @@ namespace libtorrent
" ]\n";
#endif
}
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
m_have_pieces.clear_all();
m_num_pieces = 0;
m_error = j.str;
pause();
@ -523,7 +523,7 @@ namespace libtorrent
// or the resume_data was accepted
m_num_pieces = 0;
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
m_have_pieces.clear_all();
if (!fastresume_rejected)
{
TORRENT_ASSERT(m_resume_data.type() == entry::dictionary_t);
@ -536,9 +536,9 @@ namespace libtorrent
std::string const& pieces_str = pieces->string();
for (int i = 0, end(pieces_str.size()); i < end; ++i)
{
bool have = pieces_str[i] & 1;
m_have_pieces[i] = have;
m_num_pieces += have;
if ((pieces_str[i] & 1) == 0) continue;
m_have_pieces.set_bit(i);
++m_num_pieces;
}
}
@ -563,7 +563,7 @@ namespace libtorrent
if (m_have_pieces[piece_index])
{
m_have_pieces[piece_index] = false;
m_have_pieces.clear_bit(piece_index);
--m_num_pieces;
}
@ -593,7 +593,7 @@ namespace libtorrent
}
int index = 0;
for (std::vector<bool>::iterator i = m_have_pieces.begin()
for (bitfield::const_iterator i = m_have_pieces.begin()
, end(m_have_pieces.end()); i != end; ++i, ++index)
{
if (*i) m_picker->we_have(index);
@ -635,7 +635,7 @@ namespace libtorrent
" ]\n";
#endif
}
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
m_have_pieces.clear_all();
m_num_pieces = 0;
m_error = j.str;
pause();
@ -647,7 +647,7 @@ namespace libtorrent
if (j.offset >= 0 && !m_have_pieces[j.offset])
{
m_have_pieces[j.offset] = true;
m_have_pieces.set_bit(j.offset);
++m_num_pieces;
TORRENT_ASSERT(m_picker);
m_picker->we_have(j.offset);
@ -1452,7 +1452,7 @@ namespace libtorrent
if (!m_have_pieces[index])
m_num_pieces++;
m_have_pieces[index] = true;
m_have_pieces.set_bit(index);
TORRENT_ASSERT(std::accumulate(m_have_pieces.begin(), m_have_pieces.end(), 0)
== m_num_pieces);
@ -1872,9 +1872,8 @@ namespace libtorrent
{
if (m_picker.get())
{
const std::vector<bool>& pieces = p->get_bitfield();
TORRENT_ASSERT(std::count(pieces.begin(), pieces.end(), true)
< int(pieces.size()));
bitfield const& pieces = p->get_bitfield();
TORRENT_ASSERT(pieces.count() < int(pieces.size()));
m_picker->dec_refcount(pieces);
}
}

View File

@ -156,8 +156,8 @@ namespace libtorrent
TORRENT_ASSERT(t);
// this is always a seed
incoming_bitfield(std::vector<bool>(
t->torrent_file().num_pieces(), true));
incoming_have_all();
// it is always possible to request pieces
incoming_unchoke();

View File

@ -1,5 +1,6 @@
#include "libtorrent/piece_picker.hpp"
#include "libtorrent/policy.hpp"
#include "libtorrent/bitfield.hpp"
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <algorithm>
@ -12,12 +13,12 @@ using namespace libtorrent;
const int blocks_per_piece = 4;
std::vector<bool> string2vec(char const* have_str)
bitfield string2vec(char const* have_str)
{
const int num_pieces = strlen(have_str);
std::vector<bool> have(num_pieces, false);
bitfield have(num_pieces, false);
for (int i = 0; i < num_pieces; ++i)
if (have_str[i] != ' ') have[i] = true;
if (have_str[i] != ' ') have.set_bit(i);
return have;
}
@ -37,7 +38,7 @@ boost::shared_ptr<piece_picker> setup_picker(
boost::shared_ptr<piece_picker> p(new piece_picker(blocks_per_piece, num_pieces * blocks_per_piece));
std::vector<bool> have = string2vec(have_str);
bitfield have = string2vec(have_str);
for (int i = 0; i < num_pieces; ++i)
{

View File

@ -4,6 +4,7 @@
#include "libtorrent/xml_parse.hpp"
#include "libtorrent/upnp.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/bitfield.hpp"
#include "libtorrent/torrent_info.hpp"
#include "libtorrent/escape_string.hpp"
#include "libtorrent/broadcast_socket.hpp"
@ -473,6 +474,31 @@ int test_main()
TEST_CHECK(common_bits(&h1[0], &h2[0], 20) == 12);
h2 = boost::lexical_cast<sha1_hash>("0123456789abcdef11232456789abcdef0123456");
TEST_CHECK(common_bits(&h1[0], &h2[0], 20) == 16 * 4 + 3);
// test bitfield
bitfield test1(10, false);
TEST_CHECK(test1.count() == 0);
test1.set_bit(9);
TEST_CHECK(test1.count() == 1);
test1.clear_bit(9);
TEST_CHECK(test1.count() == 0);
test1.set_bit(2);
TEST_CHECK(test1.count() == 1);
test1.set_bit(1);
test1.set_bit(9);
TEST_CHECK(test1.count() == 3);
test1.clear_bit(2);
TEST_CHECK(test1.count() == 2);
int distance = std::distance(test1.begin(), test1.end());
std::cerr << distance << std::endl;
TEST_CHECK(distance == 10);
test1.set_all();
TEST_CHECK(test1.count() == 10);
test1.clear_all();
TEST_CHECK(test1.count() == 0);
return 0;
}