diff --git a/CMakeLists.txt b/CMakeLists.txt index de5604922..d0846d1e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ set(sources bandwidth_manager bandwidth_queue_entry bdecode + bitfield block_cache bloom_filter chained_buffer diff --git a/Jamfile b/Jamfile index ccd636596..097e7bc20 100644 --- a/Jamfile +++ b/Jamfile @@ -563,6 +563,7 @@ SOURCES = bandwidth_manager bandwidth_queue_entry bdecode + bitfield block_cache bloom_filter chained_buffer diff --git a/include/libtorrent/bitfield.hpp b/include/libtorrent/bitfield.hpp index 938de163b..850e1ac6a 100644 --- a/include/libtorrent/bitfield.hpp +++ b/include/libtorrent/bitfield.hpp @@ -36,17 +36,12 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/assert.hpp" #include "libtorrent/config.hpp" #include "libtorrent/aux_/byteswap.hpp" -#include "libtorrent/aux_/cpuid.hpp" #include // for memset and memcpy #include // for malloc, free and realloc #include // uint32_t #include // for min() -#ifdef _MSC_VER -#include -#endif - namespace libtorrent { // The bitfiled type stores any number of bits as a bitfield @@ -116,21 +111,7 @@ namespace libtorrent } // returns true if all bits in the bitfield are set - bool all_set() const - { - const int words = size() / 32; - for (int i = 0; i < words; ++i) - { - if (m_buf[i] != 0xffffffff) return false; - } - int rest = size() & 31; - if (rest > 0) - { - boost::uint32_t mask = aux::host_to_network(0xffffffff << (32-rest)); - if ((m_buf[words] & mask) != mask) return false; - } - return true; - } + bool all_set() const; bool none_set() const { @@ -172,46 +153,7 @@ namespace libtorrent } // count the number of bits in the bitfield that are set to 1. - int count() const - { - int ret = 0; - const int words = num_words(); -#if TORRENT_HAS_SSE - if (aux::mmx_support) - { - for (int i = 0; i < words; ++i) - { -#ifdef __GNUC__ - ret += __builtin_popcount(m_buf[i]); -#else - ret += _mm_popcnt_u32(m_buf[i]); -#endif - } - - return ret; - } -#endif // TORRENT_HAS_SSE - - for (int i = 0; i < words; ++i) - { - boost::uint32_t v = m_buf[i]; - // from: - // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel - static const int S[] = {1, 2, 4, 8, 16}; // Magic Binary Numbers - static const int B[] = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF}; - - boost::uint32_t c = v - ((v >> 1) & B[0]); - c = ((c >> S[1]) & B[1]) + (c & B[1]); - c = ((c >> S[2]) + c) & B[2]; - c = ((c >> S[3]) + c) & B[3]; - c = ((c >> S[4]) + c) & B[4]; - ret += c; - } - - TORRENT_ASSERT(ret <= size()); - TORRENT_ASSERT(ret >= 0); - return ret; - } + int count() const; struct const_iterator { @@ -277,66 +219,9 @@ namespace libtorrent // set the size of the bitfield to ``bits`` length. If the bitfield is extended, // the new bits are initialized to ``val``. - void resize(int bits, bool val) - { - if (bits == size()) return; + void resize(int bits, bool val); - int s = size(); - int b = size() & 31; - resize(bits); - if (s >= size()) return; - int old_size_words = (s + 31) / 32; - int new_size_words = num_words(); - if (val) - { - if (old_size_words && b) m_buf[old_size_words - 1] |= aux::host_to_network((0xffffffff >> b)); - if (old_size_words < new_size_words) - std::memset(m_buf + old_size_words, 0xff - , size_t((new_size_words - old_size_words) * 4)); - clear_trailing_bits(); - } - else - { - if (old_size_words < new_size_words) - std::memset(m_buf + old_size_words, 0x00 - , size_t((new_size_words - old_size_words) * 4)); - } - TORRENT_ASSERT(size() == bits); - } - - void resize(int bits) - { - if (bits == size()) return; - - TORRENT_ASSERT(bits >= 0); - // +1 because the first word is the size (in bits) - const int b = (bits + 31) / 32; - if (m_buf) - { - boost::uint32_t* tmp = static_cast(std::realloc(m_buf-1, (b+1) * 4)); -#ifndef BOOST_NO_EXCEPTIONS - if (tmp == NULL) throw std::bad_alloc(); -#endif - m_buf = tmp + 1; - m_buf[-1] = bits; - } - else if (bits > 0) - { - boost::uint32_t* tmp = static_cast(std::malloc((b+1) * 4)); -#ifndef BOOST_NO_EXCEPTIONS - if (tmp == NULL) throw std::bad_alloc(); -#endif - m_buf = tmp + 1; - m_buf[-1] = bits; - } - else if (m_buf != NULL) - { - std::free(m_buf-1); - m_buf = NULL; - } - clear_trailing_bits(); - TORRENT_ASSERT(size() == bits); - } + void resize(int bits); // set all bits in the bitfield to 1 (set_all) or 0 (clear_all). void set_all() diff --git a/src/Makefile.am b/src/Makefile.am index 8e8bafc74..d2ff91f79 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -43,6 +43,7 @@ libtorrent_rasterbar_la_SOURCES = \ bandwidth_manager.cpp \ bandwidth_queue_entry.cpp \ bdecode.cpp \ + bitfield.cpp \ bloom_filter.cpp \ broadcast_socket.cpp \ block_cache.cpp \ diff --git a/src/bitfield.cpp b/src/bitfield.cpp new file mode 100644 index 000000000..5432e34db --- /dev/null +++ b/src/bitfield.cpp @@ -0,0 +1,160 @@ +/* + +Copyright (c) 2008-2016, 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. + +*/ + +#include "libtorrent/bitfield.hpp" +#include "libtorrent/aux_/cpuid.hpp" + +#ifdef _MSC_VER +#include +#endif + +namespace libtorrent +{ + bool bitfield::all_set() const + { + const int words = size() / 32; + for (int i = 0; i < words; ++i) + { + if (m_buf[i] != 0xffffffff) return false; + } + int rest = size() & 31; + if (rest > 0) + { + boost::uint32_t mask = aux::host_to_network(0xffffffff << (32-rest)); + if ((m_buf[words] & mask) != mask) return false; + } + return true; + } + + int bitfield::count() const + { + int ret = 0; + const int words = num_words(); +#if TORRENT_HAS_SSE + if (aux::mmx_support) + { + for (int i = 0; i < words; ++i) + { +#ifdef __GNUC__ + ret += __builtin_popcount(m_buf[i]); +#else + ret += _mm_popcnt_u32(m_buf[i]); +#endif + } + + return ret; + } +#endif // TORRENT_HAS_SSE + + for (int i = 0; i < words; ++i) + { + boost::uint32_t v = m_buf[i]; + // from: + // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + static const int S[] = {1, 2, 4, 8, 16}; // Magic Binary Numbers + static const int B[] = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF}; + + boost::uint32_t c = v - ((v >> 1) & B[0]); + c = ((c >> S[1]) & B[1]) + (c & B[1]); + c = ((c >> S[2]) + c) & B[2]; + c = ((c >> S[3]) + c) & B[3]; + c = ((c >> S[4]) + c) & B[4]; + ret += c; + } + + TORRENT_ASSERT(ret <= size()); + TORRENT_ASSERT(ret >= 0); + return ret; + } + + void bitfield::resize(int bits, bool val) + { + if (bits == size()) return; + + int s = size(); + int b = size() & 31; + resize(bits); + if (s >= size()) return; + int old_size_words = (s + 31) / 32; + int new_size_words = num_words(); + if (val) + { + if (old_size_words && b) m_buf[old_size_words - 1] |= aux::host_to_network((0xffffffff >> b)); + if (old_size_words < new_size_words) + std::memset(m_buf + old_size_words, 0xff + , size_t((new_size_words - old_size_words) * 4)); + clear_trailing_bits(); + } + else + { + if (old_size_words < new_size_words) + std::memset(m_buf + old_size_words, 0x00 + , size_t((new_size_words - old_size_words) * 4)); + } + TORRENT_ASSERT(size() == bits); + } + + void bitfield::resize(int bits) + { + if (bits == size()) return; + + TORRENT_ASSERT(bits >= 0); + // +1 because the first word is the size (in bits) + const int b = (bits + 31) / 32; + if (m_buf) + { + boost::uint32_t* tmp = static_cast(std::realloc(m_buf-1, (b+1) * 4)); +#ifndef BOOST_NO_EXCEPTIONS + if (tmp == NULL) throw std::bad_alloc(); +#endif + m_buf = tmp + 1; + m_buf[-1] = bits; + } + else if (bits > 0) + { + boost::uint32_t* tmp = static_cast(std::malloc((b+1) * 4)); +#ifndef BOOST_NO_EXCEPTIONS + if (tmp == NULL) throw std::bad_alloc(); +#endif + m_buf = tmp + 1; + m_buf[-1] = bits; + } + else if (m_buf != NULL) + { + std::free(m_buf-1); + m_buf = NULL; + } + clear_trailing_bits(); + TORRENT_ASSERT(size() == bits); + } +} +