diff --git a/dynamic_bitset.html b/dynamic_bitset.html
index e63b1af..108527a 100644
--- a/dynamic_bitset.html
+++ b/dynamic_bitset.html
@@ -8,6 +8,7 @@
Copyright (c) 2003-2004, 2008 Gennaro Prota
Copyright (c) 2014 Ahmed Charles
Copyright (c) 2014 Riccardo Marcangelo
+ Copyright (c) 2018 Evgeny Shulgin
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
@@ -197,10 +198,13 @@ public:
dynamic_bitset operator<<(size_type n) const;
dynamic_bitset operator>>(size_type n) const;
+ dynamic_bitset& set(size_type n, size_type len, bool val = true);
dynamic_bitset& set(size_type n, bool val = true);
dynamic_bitset& set();
+ dynamic_bitset& reset(size_type n, size_type len);
dynamic_bitset& reset(size_type n);
dynamic_bitset& reset();
+ dynamic_bitset& flip(size_type n, size_type len);
dynamic_bitset& flip(size_type n);
dynamic_bitset& flip();
bool test(size_type n) const;
@@ -1062,6 +1066,18 @@ dynamic_bitset& reset()
Returns: *this
Throws: nothing.
+
+dynamic_bitset& set(size_type n, size_type len, bool val = true); ++ +Precondition: n + len < this->size().
dynamic_bitset& false.
Returns: *this +
++dynamic_bitset& reset(size_type n, size_type len); ++ +Precondition: n + len < this->size().
+Effects: Clears every bit indexed from n to +n + len - 1 inclusively.
+Returns: *this +
dynamic_bitset& reset(size_type n) @@ -1083,6 +1110,16 @@ dynamic_bitset& reset(size_type n) Effects: Clears bit n.
Returns: *this +
++dynamic_bitset& flip(size_type n, size_type len) ++ +Precondition: n + len < this->size().
+Effects: Flips every bit indexed from n to +n + len - 1 inclusively.
+Returns: *this +
dynamic_bitset& flip(size_type n) diff --git a/include/boost/dynamic_bitset/dynamic_bitset.hpp b/include/boost/dynamic_bitset/dynamic_bitset.hpp index 38fe63d..9eb638d 100644 --- a/include/boost/dynamic_bitset/dynamic_bitset.hpp +++ b/include/boost/dynamic_bitset/dynamic_bitset.hpp @@ -281,10 +281,13 @@ public: dynamic_bitset operator>>(size_type n) const; // basic bit operations + dynamic_bitset& set(size_type n, size_type len, bool val = true); dynamic_bitset& set(size_type n, bool val = true); dynamic_bitset& set(); + dynamic_bitset& reset(size_type n, size_type len); dynamic_bitset& reset(size_type n); dynamic_bitset& reset(); + dynamic_bitset& flip(size_type n, size_type len); dynamic_bitset& flip(size_type n); dynamic_bitset& flip(); bool test(size_type n) const; @@ -362,6 +365,9 @@ public: private: BOOST_STATIC_CONSTANT(block_width_type, ulong_width = std::numeric_limits::digits); + dynamic_bitset& range_operation(size_type pos, size_type len, + Block (*partial_block_operation)(Block, size_type, size_type), + Block (*full_block_operation)(Block)); void m_zero_unused_bits(); bool m_check_invariants() const; @@ -371,6 +377,51 @@ private: static size_type block_index(size_type pos) BOOST_NOEXCEPT { return pos / bits_per_block; } static block_width_type bit_index(size_type pos) BOOST_NOEXCEPT { return static_cast (pos % bits_per_block); } static Block bit_mask(size_type pos) BOOST_NOEXCEPT { return Block(1) << bit_index(pos); } + static Block bit_mask(size_type first, size_type last) BOOST_NOEXCEPT + { + Block res = (last == bits_per_block - 1) + ? static_cast (~0) + : ((Block(1) << (last + 1)) - 1); + res ^= (Block(1) << first) - 1; + return res; + } + static Block set_block_bits(Block block, size_type first, + size_type last, bool val) BOOST_NOEXCEPT + { + if (val) + return block | bit_mask(first, last); + else + return block & static_cast (~bit_mask(first, last)); + } + + // Functions for operations on ranges + inline static Block set_block_partial(Block block, size_type first, + size_type last) BOOST_NOEXCEPT + { + return set_block_bits(block, first, last, true); + } + inline static Block set_block_full(Block) BOOST_NOEXCEPT + { + return static_cast (~0); + } + inline static Block reset_block_partial(Block block, size_type first, + size_type last) BOOST_NOEXCEPT + { + return set_block_bits(block, first, last, false); + } + inline static Block reset_block_full(Block) BOOST_NOEXCEPT + { + return 0; + } + inline static Block flip_block_partial(Block block, size_type first, + size_type last) BOOST_NOEXCEPT + { + return block ^ bit_mask(first, last); + } + inline static Block flip_block_full(Block block) BOOST_NOEXCEPT + { + return ~block; + } template void init_from_string(const std::basic_string & s, @@ -961,6 +1012,17 @@ dynamic_bitset ::operator>>(size_type n) const //----------------------------------------------------------------------------- // basic bit operations +template +dynamic_bitset & +dynamic_bitset ::set(size_type pos, + size_type len, bool val) +{ + if (val) + return range_operation(pos, len, set_block_partial, set_block_full); + else + return range_operation(pos, len, reset_block_partial, reset_block_full); +} + template dynamic_bitset & dynamic_bitset ::set(size_type pos, bool val) @@ -984,6 +1046,13 @@ dynamic_bitset ::set() return *this; } +template +inline dynamic_bitset & +dynamic_bitset ::reset(size_type pos, size_type len) +{ + return range_operation(pos, len, reset_block_partial, reset_block_full); +} + template dynamic_bitset & dynamic_bitset ::reset(size_type pos) @@ -1008,6 +1077,13 @@ dynamic_bitset ::reset() return *this; } +template +dynamic_bitset & +dynamic_bitset ::flip(size_type pos, size_type len) +{ + return range_operation(pos, len, flip_block_partial, flip_block_full); +} + template dynamic_bitset & dynamic_bitset ::flip(size_type pos) @@ -1937,6 +2013,63 @@ inline const Block& dynamic_bitset ::m_highest_block() const return m_bits.back(); } +template +dynamic_bitset & dynamic_bitset ::range_operation( + size_type pos, size_type len, + Block (*partial_block_operation)(Block, size_type, size_type), + Block (*full_block_operation)(Block)) +{ + assert(pos + len <= m_num_bits); + + // Do nothing in case of zero length + if (!len) + return *this; + + // Use an additional asserts in order to detect size_type overflow + // For example: pos = 10, len = size_type_limit - 2, pos + len = 7 + // In case of overflow, 'pos + len' is always smaller than 'len' + assert(pos + len >= len); + + // Start and end blocks of the [pos; pos + len - 1] sequence + const size_type first_block = block_index(pos); + const size_type last_block = block_index(pos + len - 1); + + const size_type first_bit_index = bit_index(pos); + const size_type last_bit_index = bit_index(pos + len - 1); + + if (first_block == last_block) { + // Filling only a sub-block of a block + m_bits[first_block] = partial_block_operation(m_bits[first_block], + first_bit_index, last_bit_index); + } else { + // Check if the corner blocks won't be fully filled with 'val' + const size_type first_block_shift = bit_index(pos) ? 1 : 0; + const size_type last_block_shift = (bit_index(pos + len - 1) + == bits_per_block - 1) ? 0 : 1; + + // Blocks that will be filled with ~0 or 0 at once + const size_type first_full_block = first_block + first_block_shift; + const size_type last_full_block = last_block - last_block_shift; + + for (size_type i = first_full_block; i <= last_full_block; ++i) { + m_bits[i] = full_block_operation(m_bits[i]); + } + + // Fill the first block from the 'first' bit index to the end + if (first_block_shift) { + m_bits[first_block] = partial_block_operation(m_bits[first_block], + first_bit_index, bits_per_block - 1); + } + + // Fill the last block from the start to the 'last' bit index + if (last_block_shift) { + m_bits[last_block] = partial_block_operation(m_bits[last_block], + 0, last_bit_index); + } + } + + return *this; +} // If size() is not a multiple of bits_per_block // then not all the bits in the last block are used. diff --git a/test/bitset_test.hpp b/test/bitset_test.hpp index d81c364..a6656fd 100644 --- a/test/bitset_test.hpp +++ b/test/bitset_test.hpp @@ -3,6 +3,7 @@ // Copyright (c) 2003-2006, 2008 Gennaro Prota // Copyright (c) 2014 Ahmed Charles // Copyright (c) 2014 Riccardo Marcangelo +// Copyright (c) 2018 Evgeny Shulgin // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -619,6 +620,22 @@ struct bitset_test { } } + static void set_segment(const Bitset& b, std::size_t pos, + std::size_t len, bool value) + { + Bitset lhs(b); + std::size_t N = lhs.size(); + Bitset prev(lhs); + lhs.set(pos, len, value); + for (std::size_t I = 0; I < N; ++I) + { + if (I < pos || I >= pos + len) + BOOST_CHECK(lhs[I] == prev[I]); + else + BOOST_CHECK(lhs[I] == value); + } + } + static void reset_all(const Bitset& b) { Bitset lhs(b); @@ -647,6 +664,22 @@ struct bitset_test { } } + static void reset_segment(const Bitset& b, std::size_t pos, + std::size_t len) + { + Bitset lhs(b); + std::size_t N = lhs.size(); + Bitset prev(lhs); + lhs.reset(pos, len); + for (std::size_t I = 0; I < N; ++I) + { + if (I < pos || I >= pos + len) + BOOST_CHECK(lhs[I] == prev[I]); + else + BOOST_CHECK(!lhs[I]); + } + } + static void operator_flip(const Bitset& b) { Bitset lhs(b); @@ -684,6 +717,22 @@ struct bitset_test { } } + static void flip_segment(const Bitset& b, std::size_t pos, + std::size_t len) + { + Bitset lhs(b); + std::size_t N = lhs.size(); + Bitset prev(lhs); + lhs.flip(pos, len); + for (std::size_t I = 0; I < N; ++I) + { + if (I < pos || I >= pos + len) + BOOST_CHECK(lhs[I] == prev[I]); + else + BOOST_CHECK(lhs[I] != prev[I]); + } + } + // empty static void empty(const Bitset& b) { diff --git a/test/dyn_bitset_unit_tests2.cpp b/test/dyn_bitset_unit_tests2.cpp index 457d762..dac641b 100644 --- a/test/dyn_bitset_unit_tests2.cpp +++ b/test/dyn_bitset_unit_tests2.cpp @@ -2,6 +2,7 @@ // Copyright (c) 2001 Jeremy Siek // Copyright (c) 2003-2006 Gennaro Prota // Copyright (c) 2014 Ahmed Charles +// Copyright (c) 2018 Evgeny Shulgin // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -208,6 +209,40 @@ void run_test_cases( BOOST_EXPLICIT_TEMPLATE_TYPE(Block) ) Tests::set_one(b, long_string.size()/2, false); } //===================================================================== + // Test b.set(pos, len) + { // case size is 1 + boost::dynamic_bitset b(std::string("0")); + Tests::set_segment(b, 0, 1, true); + Tests::set_segment(b, 0, 1, false); + } + { // case fill the whole set + boost::dynamic_bitset b(long_string); + Tests::set_segment(b, 0, b.size(), true); + Tests::set_segment(b, 0, b.size(), false); + } + { // case pos = size / 4, len = size / 2 + boost::dynamic_bitset b(long_string); + Tests::set_segment(b, b.size() / 4, b.size() / 2, true); + Tests::set_segment(b, b.size() / 4, b.size() / 2, false); + } + { // case pos = block_size / 2, len = size - block_size + boost::dynamic_bitset b(long_string); + Tests::set_segment(b, boost::dynamic_bitset ::bits_per_block / 2, + b.size() - boost::dynamic_bitset ::bits_per_block, true); + Tests::set_segment(b, boost::dynamic_bitset ::bits_per_block / 2, + b.size() - boost::dynamic_bitset ::bits_per_block, false); + } + { // case pos = 1, len = size - 2 + boost::dynamic_bitset b(long_string); + Tests::set_segment(b, 1, b.size() - 2, true); + Tests::set_segment(b, 1, b.size() - 2, false); + } + { // case pos = 3, len = 7 + boost::dynamic_bitset b(long_string); + Tests::set_segment(b, 3, 7, true); + Tests::set_segment(b, 3, 7, false); + } + //===================================================================== // Test b.reset() { boost::dynamic_bitset b; @@ -236,6 +271,33 @@ void run_test_cases( BOOST_EXPLICIT_TEMPLATE_TYPE(Block) ) Tests::reset_one(b, long_string.size()/2); } //===================================================================== + // Test b.reset(pos, len) + { // case size is 1 + boost::dynamic_bitset b(std::string("0")); + Tests::reset_segment(b, 0, 1); + } + { // case fill the whole set + boost::dynamic_bitset b(long_string); + Tests::reset_segment(b, 0, b.size()); + } + { // case pos = size / 4, len = size / 2 + boost::dynamic_bitset b(long_string); + Tests::reset_segment(b, b.size() / 4, b.size() / 2); + } + { // case pos = block_size / 2, len = size - block_size + boost::dynamic_bitset b(long_string); + Tests::reset_segment(b, boost::dynamic_bitset ::bits_per_block / 2, + b.size() - boost::dynamic_bitset ::bits_per_block); + } + { // case pos = 1, len = size - 2 + boost::dynamic_bitset b(long_string); + Tests::reset_segment(b, 1, b.size() - 2); + } + { // case pos = 3, len = 7 + boost::dynamic_bitset b(long_string); + Tests::reset_segment(b, 3, 7); + } + //===================================================================== // Test ~b { boost::dynamic_bitset b; @@ -277,6 +339,33 @@ void run_test_cases( BOOST_EXPLICIT_TEMPLATE_TYPE(Block) ) boost::dynamic_bitset b(long_string); Tests::flip_one(b, long_string.size()/2); } + //===================================================================== + // Test b.flip(pos, len) + { // case size is 1 + boost::dynamic_bitset b(std::string("0")); + Tests::flip_segment(b, 0, 1); + } + { // case fill the whole set + boost::dynamic_bitset b(long_string); + Tests::flip_segment(b, 0, b.size()); + } + { // case pos = size / 4, len = size / 2 + boost::dynamic_bitset b(long_string); + Tests::flip_segment(b, b.size() / 4, b.size() / 2); + } + { // case pos = block_size / 2, len = size - block_size + boost::dynamic_bitset b(long_string); + Tests::flip_segment(b, boost::dynamic_bitset ::bits_per_block / 2, + b.size() - boost::dynamic_bitset ::bits_per_block); + } + { // case pos = 1, len = size - 2 + boost::dynamic_bitset b(long_string); + Tests::flip_segment(b, 1, b.size() - 2); + } + { // case pos = 3, len = 7 + boost::dynamic_bitset b(long_string); + Tests::flip_segment(b, 3, 7); + } } int