replaced vector<bool> with a custom bitfield type
This commit is contained in:
parent
523c48e069
commit
68c31e48dc
|
@ -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);
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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();
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue