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().
+Effects: Sets every bit indexed from n to +n + len - 1 inclusively if val is true, and +clears them if val is false.
+Returns: *this +
 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