From a35ac2ed99e808c577a08a56e0f684d3c5782174 Mon Sep 17 00:00:00 2001 From: Evgeny Shulgin Date: Thu, 23 Aug 2018 23:22:37 +0300 Subject: [PATCH 1/4] Add set(pos, len) function to change sequences --- dynamic_bitset.html | 14 ++++ .../boost/dynamic_bitset/dynamic_bitset.hpp | 77 +++++++++++++++++++ test/bitset_test.hpp | 17 ++++ test/dyn_bitset_unit_tests2.cpp | 35 +++++++++ 4 files changed, 143 insertions(+) diff --git a/dynamic_bitset.html b/dynamic_bitset.html index 538dd76f..2659715f 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,6 +198,7 @@

Synopsis

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); @@ -1062,6 +1064,18 @@

Member Functions

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& >(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);
@@ -369,6 +371,22 @@ class dynamic_bitset
     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));
+    }
 
     template 
     void init_from_string(const std::basic_string& s,
@@ -959,6 +977,65 @@ dynamic_bitset::operator>>(size_type n) const
 //-----------------------------------------------------------------------------
 // basic bit operations
 
+template 
+dynamic_bitset&
+dynamic_bitset::set(size_type pos,
+        size_type len, bool val)
+{
+    assert(pos + len <= m_num_bits);
+
+    // Do nothing in case of zero len
+    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 int first_block = block_index(pos);
+    const int last_block = block_index(pos + len - 1);
+
+    const int first_bit_index = bit_index(pos);
+    const int 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] = set_block_bits(m_bits[first_block],
+            first_bit_index, last_bit_index, val);
+    } else {
+        // Check if the corner blocks won't be fully filled with 'val'
+        const int first_block_shift = bit_index(pos) ? 1 : 0;
+        const int 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 int first_full_block = first_block + first_block_shift;
+        const int last_full_block = last_block - last_block_shift;
+
+        if (first_full_block <= last_full_block) {
+            std::fill_n(m_bits.begin() + first_full_block,
+                    last_full_block - first_full_block + 1,
+                    val ? static_cast(~0) : Block(0));
+        }
+
+        // Fill the first block from the 'first' bit index to the end
+        if (first_block_shift) {
+            m_bits[first_block] = set_block_bits(m_bits[first_block],
+                first_bit_index, bits_per_block - 1, val);
+        }
+
+        // Fill the last block from the start to the 'last' bit index
+        if (last_block_shift) {
+            m_bits[last_block] = set_block_bits(m_bits[last_block],
+                0, last_bit_index, val);
+        }
+    }
+
+    return *this;
+}
+
 template 
 dynamic_bitset&
 dynamic_bitset::set(size_type pos, bool val)
diff --git a/test/bitset_test.hpp b/test/bitset_test.hpp
index d81c3640..492c71b6 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);
diff --git a/test/dyn_bitset_unit_tests2.cpp b/test/dyn_bitset_unit_tests2.cpp
index 457d762e..c1750a74 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;

From 12e1957c573bbd02a469107a3c1a43aae3a32ef0 Mon Sep 17 00:00:00 2001
From: Evgeny Shulgin 
Date: Fri, 31 Aug 2018 19:46:42 +0300
Subject: [PATCH 2/4] Add reset(pos, len) function to clear sequences

---
 dynamic_bitset.html                           | 14 +++++++++-
 .../boost/dynamic_bitset/dynamic_bitset.hpp   |  8 ++++++
 test/bitset_test.hpp                          | 16 +++++++++++
 test/dyn_bitset_unit_tests2.cpp               | 27 +++++++++++++++++++
 4 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/dynamic_bitset.html b/dynamic_bitset.html
index 2659715f..deef7152 100644
--- a/dynamic_bitset.html
+++ b/dynamic_bitset.html
@@ -201,6 +201,7 @@ 

Synopsis

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); @@ -1073,7 +1074,7 @@

Member Functions

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.
+clears them if val is false.
Returns: *this
@@ -1088,6 +1089,17 @@

Member Functions

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)
diff --git a/include/boost/dynamic_bitset/dynamic_bitset.hpp b/include/boost/dynamic_bitset/dynamic_bitset.hpp
index caec277d..f3518525 100644
--- a/include/boost/dynamic_bitset/dynamic_bitset.hpp
+++ b/include/boost/dynamic_bitset/dynamic_bitset.hpp
@@ -283,6 +283,7 @@ class dynamic_bitset
     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);
@@ -1059,6 +1060,13 @@ dynamic_bitset::set()
   return *this;
 }
 
+template 
+inline dynamic_bitset&
+dynamic_bitset::reset(size_type pos, size_type len)
+{
+    return set(pos, len, false);
+}
+
 template 
 dynamic_bitset&
 dynamic_bitset::reset(size_type pos)
diff --git a/test/bitset_test.hpp b/test/bitset_test.hpp
index 492c71b6..8fe56b88 100644
--- a/test/bitset_test.hpp
+++ b/test/bitset_test.hpp
@@ -664,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);
diff --git a/test/dyn_bitset_unit_tests2.cpp b/test/dyn_bitset_unit_tests2.cpp
index c1750a74..e152de00 100644
--- a/test/dyn_bitset_unit_tests2.cpp
+++ b/test/dyn_bitset_unit_tests2.cpp
@@ -271,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;

From 5fc7121102db45508271999eb7a92178c088c3eb Mon Sep 17 00:00:00 2001
From: Evgeny Shulgin 
Date: Sat, 1 Sep 2018 00:02:05 +0300
Subject: [PATCH 3/4] Add custom range operations

---
 .../boost/dynamic_bitset/dynamic_bitset.hpp   | 138 +++++++++++-------
 1 file changed, 85 insertions(+), 53 deletions(-)

diff --git a/include/boost/dynamic_bitset/dynamic_bitset.hpp b/include/boost/dynamic_bitset/dynamic_bitset.hpp
index f3518525..4a5b52bb 100644
--- a/include/boost/dynamic_bitset/dynamic_bitset.hpp
+++ b/include/boost/dynamic_bitset/dynamic_bitset.hpp
@@ -363,6 +363,9 @@ class dynamic_bitset
 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;
 
@@ -389,6 +392,26 @@ class dynamic_bitset
             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;
+    }
+
     template 
     void init_from_string(const std::basic_string& s,
         typename std::basic_string::size_type pos,
@@ -983,58 +1006,10 @@ dynamic_bitset&
 dynamic_bitset::set(size_type pos,
         size_type len, bool val)
 {
-    assert(pos + len <= m_num_bits);
-
-    // Do nothing in case of zero len
-    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 int first_block = block_index(pos);
-    const int last_block = block_index(pos + len - 1);
-
-    const int first_bit_index = bit_index(pos);
-    const int 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] = set_block_bits(m_bits[first_block],
-            first_bit_index, last_bit_index, val);
-    } else {
-        // Check if the corner blocks won't be fully filled with 'val'
-        const int first_block_shift = bit_index(pos) ? 1 : 0;
-        const int 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 int first_full_block = first_block + first_block_shift;
-        const int last_full_block = last_block - last_block_shift;
-
-        if (first_full_block <= last_full_block) {
-            std::fill_n(m_bits.begin() + first_full_block,
-                    last_full_block - first_full_block + 1,
-                    val ? static_cast(~0) : Block(0));
-        }
-
-        // Fill the first block from the 'first' bit index to the end
-        if (first_block_shift) {
-            m_bits[first_block] = set_block_bits(m_bits[first_block],
-                first_bit_index, bits_per_block - 1, val);
-        }
-
-        // Fill the last block from the start to the 'last' bit index
-        if (last_block_shift) {
-            m_bits[last_block] = set_block_bits(m_bits[last_block],
-                0, last_bit_index, val);
-        }
-    }
-
-    return *this;
+    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 
@@ -1064,7 +1039,7 @@ template 
 inline dynamic_bitset&
 dynamic_bitset::reset(size_type pos, size_type len)
 {
-    return set(pos, len, false);
+    return range_operation(pos, len, reset_block_partial, reset_block_full);
 }
 
 template 
@@ -2010,6 +1985,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.

From f536fcd1155af7075eb69e65c35191e07b860000 Mon Sep 17 00:00:00 2001
From: Evgeny Shulgin 
Date: Sat, 1 Sep 2018 00:15:42 +0300
Subject: [PATCH 4/4] Add flip(pos, len) function to flip sequences

---
 dynamic_bitset.html                           | 11 ++++++++
 .../boost/dynamic_bitset/dynamic_bitset.hpp   | 17 ++++++++++++
 test/bitset_test.hpp                          | 16 +++++++++++
 test/dyn_bitset_unit_tests2.cpp               | 27 +++++++++++++++++++
 4 files changed, 71 insertions(+)

diff --git a/dynamic_bitset.html b/dynamic_bitset.html
index deef7152..2389efc5 100644
--- a/dynamic_bitset.html
+++ b/dynamic_bitset.html
@@ -204,6 +204,7 @@ 

Synopsis

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; @@ -1109,6 +1110,16 @@

Member Functions

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 4a5b52bb..4f2c5b4c 100644
--- a/include/boost/dynamic_bitset/dynamic_bitset.hpp
+++ b/include/boost/dynamic_bitset/dynamic_bitset.hpp
@@ -286,6 +286,7 @@ class dynamic_bitset
     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;
@@ -411,6 +412,15 @@ class dynamic_bitset
     {
         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,
@@ -1066,6 +1076,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)
diff --git a/test/bitset_test.hpp b/test/bitset_test.hpp
index 8fe56b88..a6656fd3 100644
--- a/test/bitset_test.hpp
+++ b/test/bitset_test.hpp
@@ -717,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 e152de00..dac641bf 100644
--- a/test/dyn_bitset_unit_tests2.cpp
+++ b/test/dyn_bitset_unit_tests2.cpp
@@ -339,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