From 68c31e48dc8ed396a37443c8d2e7ce0b4d4f723e Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Wed, 28 May 2008 02:35:02 +0000 Subject: [PATCH] replaced vector with a custom bitfield type --- docs/libtorrent_plugins.rst | 2 +- include/Makefile.am | 1 + include/libtorrent/bitfield.hpp | 241 ++++++++++++++++++++++ include/libtorrent/bt_peer_connection.hpp | 2 +- include/libtorrent/extensions.hpp | 3 +- include/libtorrent/peer_connection.hpp | 7 +- include/libtorrent/peer_info.hpp | 5 +- include/libtorrent/piece_picker.hpp | 19 +- include/libtorrent/torrent.hpp | 10 +- include/libtorrent/torrent_handle.hpp | 2 +- src/Makefile.am | 1 + src/bt_peer_connection.cpp | 43 ++-- src/peer_connection.cpp | 38 ++-- src/piece_picker.cpp | 36 ++-- src/policy.cpp | 8 +- src/torrent.cpp | 25 ++- src/web_peer_connection.cpp | 4 +- test/test_piece_picker.cpp | 9 +- test/test_primitives.cpp | 26 +++ 19 files changed, 370 insertions(+), 112 deletions(-) create mode 100644 include/libtorrent/bitfield.hpp diff --git a/docs/libtorrent_plugins.rst b/docs/libtorrent_plugins.rst index f3e4d64c0..6583193d4 100644 --- a/docs/libtorrent_plugins.rst +++ b/docs/libtorrent_plugins.rst @@ -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 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); diff --git a/include/Makefile.am b/include/Makefile.am index 70b3d0dfb..166e9ea34 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -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 \ diff --git a/include/libtorrent/bitfield.hpp b/include/libtorrent/bitfield.hpp new file mode 100644 index 000000000..fe14cfe1c --- /dev/null +++ b/include/libtorrent/bitfield.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 + diff --git a/include/libtorrent/bt_peer_connection.hpp b/include/libtorrent/bt_peer_connection.hpp index f82d5070c..370bd3ab8 100755 --- a/include/libtorrent/bt_peer_connection.hpp +++ b/include/libtorrent/bt_peer_connection.hpp @@ -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 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(); diff --git a/include/libtorrent/extensions.hpp b/include/libtorrent/extensions.hpp index c4c2c748d..3e85b125b 100644 --- a/include/libtorrent/extensions.hpp +++ b/include/libtorrent/extensions.hpp @@ -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 const& bitfield) + virtual bool on_bitfield(bitfield const& bitfield) { return false; } virtual bool on_have_all() diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index a0a799200..669187d61 100755 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -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 get_socket() const { return m_socket; } tcp::endpoint const& remote() const { return m_remote; } - std::vector const& get_bitfield() const; + bitfield const& get_bitfield() const; std::vector const& allowed_fast(); std::vector 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 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 m_have_piece; + bitfield m_have_piece; // the queue of requests we have got // from this peer diff --git a/include/libtorrent/peer_info.hpp b/include/libtorrent/peer_info.hpp index b45b5dcbd..c778bf8d4 100755 --- a/include/libtorrent/peer_info.hpp +++ b/include/libtorrent/peer_info.hpp @@ -33,12 +33,11 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_PEER_INFO_HPP_INCLUDED #define TORRENT_PEER_INFO_HPP_INCLUDED -#include - #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 pieces; + bitfield pieces; int upload_limit; int download_limit; diff --git a/include/libtorrent/piece_picker.hpp b/include/libtorrent/piece_picker.hpp index 581975af9..6be92ffa1 100755 --- a/include/libtorrent/piece_picker.hpp +++ b/include/libtorrent/piece_picker.hpp @@ -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 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 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 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 const& pieces + void pick_pieces(bitfield const& pieces , std::vector& 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 const& piece_list - , const std::vector& pieces + , bitfield const& pieces , std::vector& interesting_blocks , int num_blocks, int prefer_whole_pieces , void* peer, std::vector const& ignore) const; // picks blocks only from downloading pieces int add_blocks_downloading( - std::vector const& pieces + bitfield const& pieces , std::vector& interesting_blocks , std::vector& 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 const& picked - , std::vector 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 const& bitmask) const; + bool can_pick(int piece, bitfield const& bitmask) const; std::pair expand_piece(int piece, int whole_pieces - , std::vector const& have) const; + , bitfield const& have) const; struct piece_pos { diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 629766c11..f679d40f0 100755 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -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& 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 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 m_have_pieces; + bitfield m_have_pieces; // the number of bytes that has been // downloaded that failed the hash-test diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index 6d0873085..a4ec19055 100755 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -200,7 +200,7 @@ namespace libtorrent // we potentially could connect to int connect_candidates; - const std::vector* pieces; + bitfield const* pieces; // this is the number of pieces the client has // downloaded. it is equal to: diff --git a/src/Makefile.am b/src/Makefile.am index e81811d58..50e3ccadc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index 80ee9fe1c..a377d454e 100755 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -937,21 +937,11 @@ namespace libtorrent buffer::const_interval recv_buffer = receive_buffer(); - std::vector 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 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 diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 29c7689fd..1a72ca148 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -326,7 +326,7 @@ namespace libtorrent TORRENT_ASSERT(t); bool interested = false; - const std::vector& 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 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 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(); diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp index bbacb9889..0b75b425e 100755 --- a/src/piece_picker.cpp +++ b/src/piece_picker.cpp @@ -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 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::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(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 const& picked - , std::vector 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::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 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::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 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::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& pieces + void piece_picker::pick_pieces(bitfield const& pieces , std::vector& 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 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 const& piece_list - , std::vector const& pieces + , bitfield const& pieces , std::vector& interesting_blocks , int num_blocks, int prefer_whole_pieces , void* peer, std::vector const& ignore) const @@ -1388,7 +1390,7 @@ namespace libtorrent return num_blocks; } - int piece_picker::add_blocks_downloading(std::vector const& pieces + int piece_picker::add_blocks_downloading(bitfield const& pieces , std::vector& interesting_blocks , std::vector& backup_blocks , int num_blocks, int prefer_whole_pieces @@ -1580,7 +1582,7 @@ namespace libtorrent } std::pair piece_picker::expand_piece(int piece, int whole_pieces - , std::vector const& have) const + , bitfield const& have) const { if (whole_pieces == 0) return std::make_pair(piece, piece + 1); diff --git a/src/policy.cpp b/src/policy.cpp index c87eb4056..158f3691a 100755 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -244,7 +244,7 @@ namespace libtorrent busy_pieces.reserve(num_requests); std::vector const& suggested = c.suggested_pieces(); - std::vector const& bitfield = c.get_bitfield(); + bitfield const& bits = c.get_bitfield(); if (c.has_peer_choked()) { @@ -254,10 +254,10 @@ namespace libtorrent std::vector const& allowed_fast = c.allowed_fast(); // build a bitmask with only the allowed pieces in it - std::vector mask(c.get_bitfield().size(), false); + bitfield mask(c.get_bitfield().size(), false); for (std::vector::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); } diff --git a/src/torrent.cpp b/src/torrent.cpp index 4fdf13734..2a0431f1d 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -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::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& 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); } } diff --git a/src/web_peer_connection.cpp b/src/web_peer_connection.cpp index 6d7db636e..ff96a163a 100755 --- a/src/web_peer_connection.cpp +++ b/src/web_peer_connection.cpp @@ -156,8 +156,8 @@ namespace libtorrent TORRENT_ASSERT(t); // this is always a seed - incoming_bitfield(std::vector( - t->torrent_file().num_pieces(), true)); + incoming_have_all(); + // it is always possible to request pieces incoming_unchoke(); diff --git a/test/test_piece_picker.cpp b/test/test_piece_picker.cpp index cbe72190e..6f63f0da5 100644 --- a/test/test_piece_picker.cpp +++ b/test/test_piece_picker.cpp @@ -1,5 +1,6 @@ #include "libtorrent/piece_picker.hpp" #include "libtorrent/policy.hpp" +#include "libtorrent/bitfield.hpp" #include #include #include @@ -12,12 +13,12 @@ using namespace libtorrent; const int blocks_per_piece = 4; -std::vector string2vec(char const* have_str) +bitfield string2vec(char const* have_str) { const int num_pieces = strlen(have_str); - std::vector 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 setup_picker( boost::shared_ptr p(new piece_picker(blocks_per_piece, num_pieces * blocks_per_piece)); - std::vector have = string2vec(have_str); + bitfield have = string2vec(have_str); for (int i = 0; i < num_pieces; ++i) { diff --git a/test/test_primitives.cpp b/test/test_primitives.cpp index 1a6b62166..e336fee15 100644 --- a/test/test_primitives.cpp +++ b/test/test_primitives.cpp @@ -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("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; }