From 87d148296a75d87479562c36030ec0c389801794 Mon Sep 17 00:00:00 2001 From: Joao Rodrigues Date: Sun, 15 Mar 2020 19:00:37 +0000 Subject: [PATCH] Add boolean and equality partial operators Create boolean (or, and, xor and sub) and equality operators, that operate on two distinct bitsets with different starting points, but same length. Use the partial view as the base object for the partial operations. --- .../boost/dynamic_bitset/dynamic_bitset.hpp | 552 ++++++++++++++++-- test/Jamfile.v2 | 2 + test/bitset_test.hpp | 176 +++++- test/dyn_bitset_unit_tests6.cpp | 135 +++++ test/dyn_bitset_unit_tests7.cpp | 269 +++++++++ 5 files changed, 1077 insertions(+), 57 deletions(-) create mode 100644 test/dyn_bitset_unit_tests6.cpp create mode 100644 test/dyn_bitset_unit_tests7.cpp diff --git a/include/boost/dynamic_bitset/dynamic_bitset.hpp b/include/boost/dynamic_bitset/dynamic_bitset.hpp index 6cc43642b..3eab78522 100644 --- a/include/boost/dynamic_bitset/dynamic_bitset.hpp +++ b/include/boost/dynamic_bitset/dynamic_bitset.hpp @@ -55,6 +55,9 @@ namespace boost { +template +class dynamic_bitset_span; + template class dynamic_bitset { @@ -272,12 +275,11 @@ class dynamic_bitset } } - // bitset operations - dynamic_bitset& operator&=(const dynamic_bitset& b); - dynamic_bitset& operator|=(const dynamic_bitset& b); - dynamic_bitset& operator^=(const dynamic_bitset& b); - dynamic_bitset& operator-=(const dynamic_bitset& b); + dynamic_bitset& operator&=(const dynamic_bitset& rhs); + dynamic_bitset& operator|=(const dynamic_bitset& rhs); + dynamic_bitset& operator^=(const dynamic_bitset& rhs); + dynamic_bitset& operator-=(const dynamic_bitset& rhs); dynamic_bitset& operator<<=(size_type n); dynamic_bitset& operator>>=(size_type n); dynamic_bitset operator<<(size_type n) const; @@ -375,6 +377,7 @@ class 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)); + void m_zero_unused_bits(); bool m_check_invariants() const; @@ -402,6 +405,15 @@ class dynamic_bitset return block & static_cast(~bit_mask(first, last)); } + Block assemble_block(size_type index_first_block, size_type first_bit_index, size_type length_block) const + { + Block assembled_block = (m_bits[index_first_block] & bit_mask(first_bit_index, std::min(first_bit_index + length_block, bits_per_block - 1))) >> first_bit_index; + if (first_bit_index + length_block > bits_per_block - 1) { + assembled_block |= (m_bits[index_first_block + 1] & bit_mask(0, first_bit_index + length_block - bits_per_block)) << (bits_per_block - first_bit_index); + } + return assembled_block; + } + // Functions for operations on ranges inline static Block set_block_partial(Block block, size_type first, size_type last) BOOST_NOEXCEPT @@ -430,6 +442,58 @@ class dynamic_bitset { return ~block; } + inline static Block and_partial(Block lhs, Block rhs, + size_type first, size_type last) BOOST_NOEXCEPT + { + return (lhs & rhs) | ((~bit_mask(first, last)) & lhs); + } + inline static Block and_full(Block lhs, Block rhs) BOOST_NOEXCEPT + { + return lhs & rhs; + } + inline static Block or_partial(Block lhs, Block rhs, + size_type first, size_type last) BOOST_NOEXCEPT + { + return (lhs | (rhs & bit_mask(first, last))); + } + inline static Block or_full(Block lhs, Block rhs) BOOST_NOEXCEPT + { + return lhs | rhs; + } + inline static Block xor_partial(Block lhs, Block rhs, + size_type first, size_type last) BOOST_NOEXCEPT + { + return (lhs ^ (rhs & bit_mask(first, last))); + } + inline static Block xor_full(Block lhs, Block rhs) BOOST_NOEXCEPT + { + return lhs ^ rhs; + } + inline static Block difference_partial(Block lhs, Block rhs, + size_type first, size_type last) BOOST_NOEXCEPT + { + return (lhs & ~(rhs & bit_mask(first, last))); + } + inline static Block difference_full(Block lhs, Block rhs) BOOST_NOEXCEPT + { + return lhs & (~rhs); + } + inline static bool not_equal_partial(Block lhs, Block rhs, size_type first, size_type last) BOOST_NOEXCEPT + { + return (lhs & bit_mask(first, last)) != (rhs & bit_mask(first, last)); + } + inline static bool not_equal_full(Block lhs, Block rhs) BOOST_NOEXCEPT + { + return lhs != rhs; + } + inline static bool intersects_partial(Block lhs, Block rhs, size_type first, size_type last) BOOST_NOEXCEPT + { + return (lhs & rhs & bit_mask(first, last)) != Block(0); + } + inline static bool intersects_full(Block lhs, Block rhs) BOOST_NOEXCEPT + { + return (lhs & rhs) != Block(0); + } template void init_from_string(const std::basic_string& s, @@ -563,8 +627,153 @@ class dynamic_bitset size_type get_count() const { return n; } }; + template friend + class dynamic_bitset_span; + +#if !defined BOOST_DYNAMIC_BITSET_DONT_USE_FRIENDS + // lexicographical comparison + + template + friend bool operator==(const dynamic_bitset_span& lhs, + const dynamic_bitset_span& rhs); + +#endif + +}; + + +// A view class, to operate on subsets of dynamic_bitset as if they were complete +// +//template class T, class Block, class Allocator> +//template < template class T> +template +class dynamic_bitset_span +{ + +public: + typedef typename T::size_type size_type; + typedef typename T::block_type block_type; + + dynamic_bitset_span(T& x, size_type start_subset=0, size_type length_subset=T::npos) + : start(start_subset), + length(length_subset), + base(x) + { } + + //C++ does not allow the construction of const objects, hence we cast away the const-ness + //to avoid having two classes + + /*dynamic_bitset_span(const T& x, size_type start_subset=0, size_type length_subset=T::npos) + : start(start_subset), + length(length_subset), + base(const_cast(x)) + { }*/ + + // bitset operations + dynamic_bitset_span& operator&=(const dynamic_bitset_span& rhs); + dynamic_bitset_span& operator|=(const dynamic_bitset_span& rhs); + dynamic_bitset_span& operator^=(const dynamic_bitset_span& rhs); + dynamic_bitset_span& operator-=(const dynamic_bitset_span& rhs); + + bool intersects(const dynamic_bitset_span& rhs) const; + +#if !defined BOOST_DYNAMIC_BITSET_DONT_USE_FRIENDS + +// lexicographical comparison + template + friend bool operator==(const dynamic_bitset_span& lhs, + const dynamic_bitset_span& rhs); + + // bitset operations + template + friend U operator&(const dynamic_bitset_span& b1, + const dynamic_bitset_span& b2); + + template + friend U operator|(const dynamic_bitset_span& b1, + const dynamic_bitset_span& b2); + + template + friend U operator^(const dynamic_bitset_span& b1, + const dynamic_bitset_span& b2); + + template + friend U operator-(const dynamic_bitset_span& b1, + const dynamic_bitset_span& b2); + +#endif + +private: + size_type start; + size_type length; + T &base; + + dynamic_bitset_span& range_operation_pair(const dynamic_bitset_span& rhs, + block_type (*partial_block_operation)(block_type, block_type, size_type, size_type), + block_type (*full_block_operation)(block_type, block_type) ); + + bool boolean_range_operation_pair(const dynamic_bitset_span& rhs, + bool (*partial_block_operation)(block_type, block_type, size_type, size_type), + bool (*full_block_operation)(block_type, block_type) ) const; + +}; + +template +class const_dynamic_bitset_span +{ + +public: + typedef typename T::size_type size_type; + + const_dynamic_bitset_span(const T& x, size_type start_subset=0, size_type length_subset=T::npos) + : start(start_subset), + length(length_subset), + base(x) + { } + + operator const dynamic_bitset_span() const { return dynamic_bitset_span(const_cast(base), start, length); }; + +private: + size_type start; + size_type length; + const T &base; }; +template +dynamic_bitset& +dynamic_bitset::operator&=(const dynamic_bitset& rhs) +{ + dynamic_bitset_span< dynamic_bitset >(*this) &= const_dynamic_bitset_span< dynamic_bitset >(rhs); + return *this; +} + +template +dynamic_bitset& +dynamic_bitset::operator|=(const dynamic_bitset& rhs) +{ + dynamic_bitset_span< dynamic_bitset >(*this) |= const_dynamic_bitset_span< dynamic_bitset >(rhs); + return *this; + +} + +template +dynamic_bitset& +dynamic_bitset::operator^=(const dynamic_bitset& rhs) +{ + dynamic_bitset_span< dynamic_bitset >(*this) ^= const_dynamic_bitset_span< dynamic_bitset >(rhs); + return *this; + +} + +template +dynamic_bitset& +dynamic_bitset::operator-=(const dynamic_bitset& rhs) +{ + dynamic_bitset_span< dynamic_bitset >(*this) -= const_dynamic_bitset_span< dynamic_bitset >(rhs); + return *this; + +} + #if !defined BOOST_NO_INCLASS_MEMBER_INITIALIZATION template @@ -642,7 +851,7 @@ operator-(const dynamic_bitset& b1, const dynamic_bitset& b2); // namespace scope swap -template +template void swap(dynamic_bitset& b1, dynamic_bitset& b2); @@ -858,47 +1067,49 @@ append(Block value) // strong guarantee //----------------------------------------------------------------------------- // bitset operations -template -dynamic_bitset& -dynamic_bitset::operator&=(const dynamic_bitset& rhs) +template +dynamic_bitset_span& +dynamic_bitset_span::operator&=(const dynamic_bitset_span& rhs) { - assert(size() == rhs.size()); - for (size_type i = 0; i < num_blocks(); ++i) - m_bits[i] &= rhs.m_bits[i]; - return *this; + return dynamic_bitset_span(*this).range_operation_pair(rhs, + T::and_partial, T::and_full); } -template -dynamic_bitset& -dynamic_bitset::operator|=(const dynamic_bitset& rhs) +template +dynamic_bitset_span& +dynamic_bitset_span::operator|=(const dynamic_bitset_span& rhs) { - assert(size() == rhs.size()); - for (size_type i = 0; i < num_blocks(); ++i) - m_bits[i] |= rhs.m_bits[i]; - //m_zero_unused_bits(); - return *this; + return dynamic_bitset_span(*this).range_operation_pair(rhs, + T::or_partial, T::or_full); } -template -dynamic_bitset& -dynamic_bitset::operator^=(const dynamic_bitset& rhs) +template +dynamic_bitset_span& +dynamic_bitset_span::operator^=(const dynamic_bitset_span& rhs) { - assert(size() == rhs.size()); - for (size_type i = 0; i < this->num_blocks(); ++i) - m_bits[i] ^= rhs.m_bits[i]; - //m_zero_unused_bits(); - return *this; + return dynamic_bitset_span(*this).range_operation_pair(rhs, + T::xor_partial, T::xor_full); } -template -dynamic_bitset& -dynamic_bitset::operator-=(const dynamic_bitset& rhs) +template +dynamic_bitset_span& +dynamic_bitset_span::operator-=(const dynamic_bitset_span& rhs) { - assert(size() == rhs.size()); - for (size_type i = 0; i < num_blocks(); ++i) - m_bits[i] &= ~rhs.m_bits[i]; - //m_zero_unused_bits(); - return *this; + return dynamic_bitset_span(*this).range_operation_pair(rhs, + T::difference_partial, T::difference_full); +} + +template +bool operator==(const dynamic_bitset_span& lhs, const dynamic_bitset_span& rhs) +{ + return !(lhs.boolean_range_operation_pair(rhs, + T::not_equal_partial, T::not_equal_full)); +} + +template +bool operator!=(const dynamic_bitset_span& lhs, const dynamic_bitset_span& rhs) +{ + return !(lhs == rhs); } // @@ -1445,16 +1656,19 @@ is_proper_subset_of(const dynamic_bitset& a) const } template -bool dynamic_bitset::intersects(const dynamic_bitset & b) const +bool dynamic_bitset::intersects(const dynamic_bitset & rhs) const { - size_type common_blocks = num_blocks() < b.num_blocks() - ? num_blocks() : b.num_blocks(); + //for backwards compatibility with previous behaviour, if the two dynamic_bitsets + //don't have the same length, choose the smallest length + const dynamic_bitset_span< dynamic_bitset > wrapper = const_dynamic_bitset_span< dynamic_bitset >(*this, 0, std::min(size(), rhs.size())); + return wrapper.intersects(const_dynamic_bitset_span< dynamic_bitset >(rhs)); +} - for(size_type i = 0; i < common_blocks; ++i) { - if(m_bits[i] & b.m_bits[i]) - return true; - } - return false; +template +bool dynamic_bitset_span::intersects(const dynamic_bitset_span& rhs) const +{ + return (*this).boolean_range_operation_pair(rhs, + T::intersects_partial, T::intersects_full); } // -------------------------------- @@ -1969,6 +2183,45 @@ operator>>(std::basic_istream& is, dynamic_bitset& b) #endif +//----------------------------------------------------------------------------- +// bitset operations + +template +T operator&(const dynamic_bitset_span& x, + const dynamic_bitset_span& y) +{ + T b(x.base); + dynamic_bitset_span(b, x.start, x.length) &= y; + return b; +} + +template +T operator|(const dynamic_bitset_span& x, + const dynamic_bitset_span& y) +{ + T b(x.base); + dynamic_bitset_span(b, x.start, x.length) |= y; + return b; +} + +template +T operator^(const dynamic_bitset_span& x, + const dynamic_bitset_span& y) +{ + T b(x.base); + dynamic_bitset_span(b, x.start, x.length) ^= y; + return b; +} + +template +T operator-(const dynamic_bitset_span& x, + const dynamic_bitset_span& y) +{ + T b(x.base); + dynamic_bitset_span(b, x.start, x.length) -= y; + return b; +} + //----------------------------------------------------------------------------- // bitset operations @@ -1978,7 +2231,8 @@ operator&(const dynamic_bitset& x, const dynamic_bitset& y) { dynamic_bitset b(x); - return b &= y; + dynamic_bitset_span< dynamic_bitset >(b) &= const_dynamic_bitset_span >(y); + return b; } template @@ -1987,7 +2241,8 @@ operator|(const dynamic_bitset& x, const dynamic_bitset& y) { dynamic_bitset b(x); - return b |= y; + dynamic_bitset_span< dynamic_bitset >(b) |= const_dynamic_bitset_span< dynamic_bitset >(y); + return b; } template @@ -1996,7 +2251,8 @@ operator^(const dynamic_bitset& x, const dynamic_bitset& y) { dynamic_bitset b(x); - return b ^= y; + dynamic_bitset_span< dynamic_bitset >(b) ^= const_dynamic_bitset_span< dynamic_bitset >(y); + return b; } template @@ -2005,7 +2261,8 @@ operator-(const dynamic_bitset& x, const dynamic_bitset& y) { dynamic_bitset b(x); - return b -= y; + dynamic_bitset_span< dynamic_bitset >(b) -= const_dynamic_bitset_span< dynamic_bitset >(y); + return b; } //----------------------------------------------------------------------------- @@ -2108,6 +2365,203 @@ dynamic_bitset& dynamic_bitset::range_operat return *this; } +template +typename T::size_type get_common_length( + const typename T::size_type len_lhs, const typename T::size_type len_rhs, + const typename T::size_type size_lhs, const typename T::size_type size_rhs +){ + + if (len_lhs == T::npos && len_rhs == T::npos) { + assert(size_lhs == size_rhs); + return size_lhs; + }else if (len_lhs == T::npos) { + return len_rhs; + }else if (len_rhs == T::npos) { + return len_lhs; + } + + assert(len_lhs == len_rhs); + return len_lhs; + +} + +template +dynamic_bitset_span& +dynamic_bitset_span::range_operation_pair(const dynamic_bitset_span& rhs, + block_type(*partial_block_operation)(block_type, block_type, size_type, size_type), + block_type (*full_block_operation)(block_type, block_type)) +{ + + size_type len = get_common_length(length, rhs.length, base.size(), rhs.base.size()); + + // Do nothing in case of zero length + if (!len) + return *this; + + size_type a_pos = start; + size_type b_pos = rhs.start; + + assert((a_pos + len <= base.m_num_bits) && (b_pos + len <= rhs.base.m_num_bits)); + + // 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( (a_pos + len >= len) && (b_pos + len >= len)); + + // Start and end blocks of the [a_pos; a_pos + len - 1] sequence + const size_type a_first_block = base.block_index(a_pos); + const size_type a_last_block = base.block_index(a_pos + len - 1); + + const size_type a_first_bit_index = base.bit_index(a_pos); + const size_type a_last_bit_index = base.bit_index(a_pos + len - 1); + + // Start and end blocks of the b [b_pos; b_pos + len - 1] sequence + const size_type b_first_block = base.block_index(b_pos); + const size_type b_last_block = base.block_index(b_pos + len - 1); + + const size_type b_first_bit_index = base.bit_index(b_pos); + + T& a = base; + const T& b = rhs.base; + + { + const size_type a_end_first_block = (a_first_block == a_last_block) ? + a_last_bit_index : base.bits_per_block - 1; + + block_type assembled_b = b.assemble_block(b_first_block, + b_first_bit_index, a_end_first_block - a_first_bit_index) << a_first_bit_index; + + a.m_bits[a_first_block] = partial_block_operation(a.m_bits[a_first_block], + assembled_b, a_first_bit_index, a_end_first_block); + } + + const size_type b_start_index_first_block = (b_first_bit_index >= + a_first_bit_index ? 0 : b.bits_per_block) + b_first_bit_index - a_first_bit_index; + //add one to ensure this never wraps around + const size_type b_block_adjustment = b_first_block + 1 - + (a_first_bit_index > b_first_bit_index ? 1 : 0); + + for (size_type i = a_first_block + 1; i < a_last_block; ++i) { + //main iterator is a. b is adjusted to compute full blocks + const size_type b_block = i - a_first_block + b_block_adjustment - 1; + + block_type assembled_b = b.assemble_block(b_block, + b_start_index_first_block, base.bits_per_block - 1); + + a.m_bits[i] = full_block_operation(a.m_bits[i], assembled_b); + } + + // Fill the last block from the start to the 'last' bit index + if (a_first_block != a_last_block) { + const size_type b_last_bit_index = base.bit_index(b_pos + len - 1); + + size_type b_last_block_adjusted = b_last_block - + (b_last_bit_index >= b_start_index_first_block ? 0 : 1); + size_type b_last_block_length = (b_last_bit_index >= + b_start_index_first_block ? 0 : base.bits_per_block) + + b_last_bit_index - b_start_index_first_block; + + block_type assembled_b = b.assemble_block(b_last_block_adjusted, + b_start_index_first_block, b_last_block_length); + + a.m_bits[a_last_block] = partial_block_operation(a.m_bits[a_last_block], + assembled_b, 0, a_last_bit_index); + } + + return *this; +} + +template +bool dynamic_bitset_span::boolean_range_operation_pair(const dynamic_bitset_span& rhs, + bool (*partial_block_operation)(block_type, block_type, size_type, size_type), + bool (*full_block_operation)(block_type, block_type) ) const +{ + + size_type len = get_common_length(length, rhs.length, base.size(), rhs.base.size()); + + // Return false in case of zero length + if (!len) + return false; + + size_type a_pos = start; + size_type b_pos = rhs.start; + + assert((a_pos + len <= base.m_num_bits) && (b_pos + len <= rhs.base.m_num_bits)); + + // 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( (a_pos + len >= len) && (b_pos + len >= len)); + + // Start and end blocks of the [a_pos; a_pos + len - 1] sequence + const size_type a_first_block = base.block_index(a_pos); + const size_type a_last_block = base.block_index(a_pos + len - 1); + + const size_type a_first_bit_index = base.bit_index(a_pos); + const size_type a_last_bit_index = base.bit_index(a_pos + len - 1); + + // Start and end blocks of the b [b_pos; b_pos + len - 1] sequence + const size_type b_first_block = base.block_index(b_pos); + const size_type b_last_block = base.block_index(b_pos + len - 1); + + const size_type b_first_bit_index = base.bit_index(b_pos); + + const T& a = base; + const T& b = rhs.base; + + { + const size_type a_end_first_block = (a_first_block == a_last_block) ? + a_last_bit_index : base.bits_per_block - 1; + + block_type assembled_b = b.assemble_block(b_first_block, + b_first_bit_index, a_end_first_block - a_first_bit_index) << a_first_bit_index; + + if ( partial_block_operation(a.m_bits[a_first_block], assembled_b, + a_first_bit_index, a_end_first_block)) { + return true; + } + } + + const size_type b_start_index_first_block = (b_first_bit_index >= + a_first_bit_index ? 0 : b.bits_per_block) + b_first_bit_index - a_first_bit_index; + //add one to ensure this never wraps around + const size_type b_block_adjustment = b_first_block + 1 - + (a_first_bit_index > b_first_bit_index ? 1 : 0); + + for (size_type i = a_first_block + 1; i < a_last_block; ++i) { + //main iterator is a. b is adjusted to compute full blocks + const size_type b_block = i - a_first_block + b_block_adjustment - 1; + + block_type assembled_b = b.assemble_block(b_block, + b_start_index_first_block, base.bits_per_block - 1); + + if (full_block_operation(a.m_bits[i], assembled_b)) { + return true; + } + } + + // Fill the last block from the start to the 'last' bit index + if (a_first_block != a_last_block) { + const size_type b_last_bit_index = base.bit_index(b_pos + len - 1); + + size_type b_last_block_adjusted = b_last_block - + (b_last_bit_index >= b_start_index_first_block ? 0 : 1); + size_type b_last_block_length = (b_last_bit_index >= + b_start_index_first_block ? 0 : base.bits_per_block) + + b_last_bit_index - b_start_index_first_block; + + block_type assembled_b = b.assemble_block(b_last_block_adjusted, + b_start_index_first_block, b_last_block_length); + + if (partial_block_operation(a.m_bits[a_last_block], assembled_b, 0, a_last_bit_index)) { + return true; + } + } + + return false; +} + + // If size() is not a multiple of bits_per_block // then not all the bits in the last block are used. // This function resets the unused bits (convenient diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 6d173044d..f25188136 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -25,6 +25,8 @@ test-suite dynamic_bitset : /boost/system//boost_system ] [ run dyn_bitset_unit_tests4.cpp : : : /boost/filesystem//boost_filesystem /boost/system//boost_system ] + [ run dyn_bitset_unit_tests6.cpp : : : /boost/system//boost_system ] + [ run dyn_bitset_unit_tests7.cpp : : : /boost/system//boost_system ] [ run test_ambiguous_set.cpp ] [ run test_lowest_bit.cpp ] diff --git a/test/bitset_test.hpp b/test/bitset_test.hpp index 758d44dc0..ab446c313 100644 --- a/test/bitset_test.hpp +++ b/test/bitset_test.hpp @@ -500,9 +500,9 @@ struct bitset_test { // bitwise and assignment // PRE: b.size() == rhs.size() - static void and_assignment(const Bitset& b, const Bitset& rhs) + static void and_assignment(const Bitset& original_lhs, const Bitset& rhs) { - Bitset lhs(b); + Bitset lhs(original_lhs); Bitset prev(lhs); lhs &= rhs; // Clears each bit in lhs for which the corresponding bit in rhs is @@ -513,11 +513,24 @@ struct bitset_test { else BOOST_TEST(lhs[I] == prev[I]); } + static void and_assignment(const Bitset& original_lhs, const Bitset& rhs, std::size_t pos_lhs, std::size_t pos_rhs, std::size_t len) + { + Bitset lhs(original_lhs); + Bitset prev(lhs); + boost::dynamic_bitset_span(lhs, pos_lhs) &= boost::const_dynamic_bitset_span(rhs, pos_rhs, len); + // Clears each bit in lhs for which the corresponding bit in rhs is + // clear, and leaves all other bits unchanged. + for (std::size_t I = 0; I < len; ++I) + if (rhs[I + pos_rhs] == 0) + BOOST_TEST(lhs[I + pos_lhs] == 0); + else + BOOST_TEST(lhs[I + pos_lhs] == prev[I + pos_lhs]); + } // PRE: b.size() == rhs.size() - static void or_assignment(const Bitset& b, const Bitset& rhs) + static void or_assignment(const Bitset& original_lhs, const Bitset& rhs) { - Bitset lhs(b); + Bitset lhs(original_lhs); Bitset prev(lhs); lhs |= rhs; // Sets each bit in lhs for which the corresponding bit in rhs is set, and @@ -528,11 +541,24 @@ struct bitset_test { else BOOST_TEST(lhs[I] == prev[I]); } + static void or_assignment(const Bitset& original_lhs, const Bitset& rhs, std::size_t pos_lhs, std::size_t pos_rhs, std::size_t len) + { + Bitset lhs(original_lhs); + Bitset prev(lhs); + boost::dynamic_bitset_span(lhs, pos_lhs) |= boost::const_dynamic_bitset_span(rhs, pos_rhs, len); + // Clears each bit in lhs for which the corresponding bit in rhs is + // clear, and leaves all other bits unchanged. + for (std::size_t I = 0; I < len; ++I) + if (rhs[I + pos_rhs] == 1) + BOOST_TEST(lhs[I + pos_lhs] == 1); + else + BOOST_TEST(lhs[I + pos_lhs] == prev[I + pos_lhs]); + } // PRE: b.size() == rhs.size() - static void xor_assignment(const Bitset& b, const Bitset& rhs) + static void xor_assignment(const Bitset& original_lhs, const Bitset& rhs) { - Bitset lhs(b); + Bitset lhs(original_lhs); Bitset prev(lhs); lhs ^= rhs; // Flips each bit in lhs for which the corresponding bit in rhs is set, @@ -543,11 +569,24 @@ struct bitset_test { else BOOST_TEST(lhs[I] == prev[I]); } + static void xor_assignment(const Bitset& original_lhs, const Bitset& rhs, std::size_t pos_lhs, std::size_t pos_rhs, std::size_t len) + { + Bitset lhs(original_lhs); + Bitset prev(lhs); + boost::dynamic_bitset_span(lhs, pos_lhs) ^= boost::const_dynamic_bitset_span(rhs, pos_rhs, len); + // Clears each bit in lhs for which the corresponding bit in rhs is + // clear, and leaves all other bits unchanged. + for (std::size_t I = 0; I < len; ++I) + if (rhs[I + pos_rhs] == 1) + BOOST_TEST(lhs[I + pos_lhs] == !prev[I + pos_lhs]); + else + BOOST_TEST(lhs[I + pos_lhs] == prev[I + pos_lhs]); + } // PRE: b.size() == rhs.size() - static void sub_assignment(const Bitset& b, const Bitset& rhs) + static void sub_assignment(const Bitset& original_lhs, const Bitset& rhs) { - Bitset lhs(b); + Bitset lhs(original_lhs); Bitset prev(lhs); lhs -= rhs; // Resets each bit in lhs for which the corresponding bit in rhs is set, @@ -558,6 +597,19 @@ struct bitset_test { else BOOST_TEST(lhs[I] == prev[I]); } + static void sub_assignment(const Bitset& original_lhs, const Bitset& rhs, std::size_t pos_lhs, std::size_t pos_rhs, std::size_t len) + { + Bitset lhs(original_lhs); + Bitset prev(lhs); + boost::dynamic_bitset_span(lhs, pos_lhs) -= boost::const_dynamic_bitset_span(rhs, pos_rhs, len); + // Clears each bit in lhs for which the corresponding bit in rhs is + // clear, and leaves all other bits unchanged. + for (std::size_t I = 0; I < len; ++I) + if (rhs[I + pos_rhs] == 1) + BOOST_TEST(lhs[I + pos_lhs] == 0); + else + BOOST_TEST(lhs[I + pos_lhs] == prev[I + pos_lhs]); + } static void shift_left_assignment(const Bitset& b, std::size_t pos) { @@ -966,6 +1018,22 @@ struct bitset_test { // also check commutativity BOOST_TEST(b.intersects(a) == have_intersection); } + static void intersects(const Bitset& a, const Bitset& b, std::size_t pos_a, std::size_t pos_b, std::size_t len) + { + bool have_intersection = false; + + typename Bitset::size_type m = len; + for(typename Bitset::size_type i = 0; i < m && !have_intersection; ++i) + if(a[pos_a + i] == true && b[pos_b + i] == true) + have_intersection = true; + + const boost::dynamic_bitset_span span_a = boost::const_dynamic_bitset_span(a, pos_a); + const boost::dynamic_bitset_span span_b = boost::const_dynamic_bitset_span(b, pos_b, len); + + BOOST_TEST(span_a.intersects(span_b) == have_intersection); + // also check commutativity + BOOST_TEST(span_b.intersects(span_a) == have_intersection); + } static void find_first(const Bitset& b, typename Bitset::size_type offset = 0) { @@ -1005,6 +1073,40 @@ struct bitset_test { } } } + static void operator_equal(const Bitset& a, const Bitset& b, + std::size_t pos_a, std::size_t pos_b, std::size_t len) + { + const boost::dynamic_bitset_span span_a = boost::const_dynamic_bitset_span(a, pos_a); + const boost::dynamic_bitset_span span_a_len = boost::const_dynamic_bitset_span(a, pos_a, len); + const boost::dynamic_bitset_span span_b = boost::const_dynamic_bitset_span(b, pos_b, len); + + if (span_a == span_b) { + for (std::size_t I = 0; I < len; ++I) + BOOST_TEST(a[pos_a + I] == b[pos_b + I]); + } else { + bool diff = false; + for (std::size_t I = 0; I < len; ++I) + if (a[pos_a + I] != b[pos_b + I]) { + diff = true; + break; + } + BOOST_TEST(diff); + } + + if (span_a_len == span_b) { + for (std::size_t I = 0; I < len; ++I) + BOOST_TEST(a[pos_a + I] == b[pos_b + I]); + } else { + bool diff = false; + for (std::size_t I = 0; I < len; ++I) + if (a[pos_a + I] != b[pos_b + I]) { + diff = true; + break; + } + BOOST_TEST(diff); + } + + } static void operator_not_equal(const Bitset& a, const Bitset& b) { @@ -1023,6 +1125,24 @@ struct bitset_test { BOOST_TEST(a[I] == b[I]); } } + static void operator_not_equal(const Bitset& a, const Bitset& b, std::size_t pos_a, std::size_t pos_b, std::size_t len) + { + const boost::dynamic_bitset_span span_a = boost::const_dynamic_bitset_span(a, pos_a); + const boost::dynamic_bitset_span span_b = boost::const_dynamic_bitset_span(b, pos_b, len); + + if (span_a != span_b) { + bool diff = false; + for (std::size_t I = 0; I < len; ++I) + if (a[pos_a + I] != b[pos_b + I]) { + diff = true; + break; + } + BOOST_TEST(diff); + } else { + for (std::size_t I = 0; I < len; ++I) + BOOST_TEST(a[pos_a + I] == b[pos_b + I]); + } + } static bool less_than(const Bitset& a, const Bitset& b) { @@ -1253,6 +1373,16 @@ struct bitset_test { Bitset x(lhs); BOOST_TEST((lhs | rhs) == (x |= rhs)); } + static + void operator_or(const Bitset& lhs, const Bitset& rhs, typename Bitset::size_type pos_lhs, typename Bitset::size_type pos_rhs, typename Bitset::size_type len) + { + Bitset x(lhs); + const boost::dynamic_bitset_span span_rhs = boost::const_dynamic_bitset_span(rhs, pos_rhs, len); + const boost::dynamic_bitset_span span_lhs = boost::const_dynamic_bitset_span(lhs, pos_lhs); + + boost::dynamic_bitset_span(x, pos_lhs) |= span_rhs; + BOOST_TEST( (span_lhs | span_rhs) == x); + } // operator& static @@ -1261,6 +1391,16 @@ struct bitset_test { Bitset x(lhs); BOOST_TEST((lhs & rhs) == (x &= rhs)); } + static + void operator_and(const Bitset& lhs, const Bitset& rhs, typename Bitset::size_type pos_lhs, typename Bitset::size_type pos_rhs, typename Bitset::size_type len) + { + Bitset x(lhs); + const boost::dynamic_bitset_span span_rhs = boost::const_dynamic_bitset_span(rhs, pos_rhs, len); + const boost::dynamic_bitset_span span_lhs = boost::const_dynamic_bitset_span(lhs, pos_lhs); + + boost::dynamic_bitset_span(x, pos_lhs) &= span_rhs; + BOOST_TEST( (span_lhs & span_rhs) == x); + } // operator^ static @@ -1269,6 +1409,16 @@ struct bitset_test { Bitset x(lhs); BOOST_TEST((lhs ^ rhs) == (x ^= rhs)); } + static + void operator_xor(const Bitset& lhs, const Bitset& rhs, typename Bitset::size_type pos_lhs, typename Bitset::size_type pos_rhs, typename Bitset::size_type len) + { + Bitset x(lhs); + const boost::dynamic_bitset_span span_rhs = boost::const_dynamic_bitset_span(rhs, pos_rhs, len); + const boost::dynamic_bitset_span span_lhs = boost::const_dynamic_bitset_span(lhs, pos_lhs); + + boost::dynamic_bitset_span(x, pos_lhs) ^= span_rhs; + BOOST_TEST( (span_lhs ^ span_rhs) == x); + } // operator- static @@ -1277,6 +1427,16 @@ struct bitset_test { Bitset x(lhs); BOOST_TEST((lhs - rhs) == (x -= rhs)); } + static + void operator_sub(const Bitset& lhs, const Bitset& rhs, typename Bitset::size_type pos_lhs, typename Bitset::size_type pos_rhs, typename Bitset::size_type len) + { + Bitset x(lhs); + const boost::dynamic_bitset_span span_rhs = boost::const_dynamic_bitset_span(rhs, pos_rhs, len); + const boost::dynamic_bitset_span span_lhs = boost::const_dynamic_bitset_span(lhs, pos_lhs); + + boost::dynamic_bitset_span(x, pos_lhs) -= span_rhs; + BOOST_TEST( (span_lhs - span_rhs) == x); + } //------------------------------------------------------------------------------ // I/O TESTS diff --git a/test/dyn_bitset_unit_tests6.cpp b/test/dyn_bitset_unit_tests6.cpp new file mode 100644 index 000000000..2c6442a47 --- /dev/null +++ b/test/dyn_bitset_unit_tests6.cpp @@ -0,0 +1,135 @@ +// ----------------------------------------------------------- +// 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 +// http://www.boost.org/LICENSE_1_0.txt) +// +// ----------------------------------------------------------- + +#include "bitset_test.hpp" +#include +#include + + +template +void run_test_cases( BOOST_EXPLICIT_TEMPLATE_TYPE(Block) ) +{ + typedef boost::dynamic_bitset bitset_type; + typedef bitset_test< bitset_type > Tests; + //const int bits_per_block = bitset_type::bits_per_block; + + std::string long_string = get_long_string(); + + //===================================================================== + // Test operator&= + { + boost::dynamic_bitset lhs(3), rhs(4); + Tests::and_assignment(lhs, rhs, 0, 0, 3); + Tests::and_assignment(lhs, rhs, 0, 1, 3); + } + { + boost::dynamic_bitset lhs(std::string("11")), rhs(std::string("0")); + Tests::and_assignment(lhs, rhs, 0, 0, 1); + Tests::and_assignment(lhs, rhs, 1, 0, 1); + } + { + boost::dynamic_bitset lhs(long_string.size(), 0), rhs(long_string); + Tests::and_assignment(lhs, rhs, 0, 0, long_string.size()); + Tests::and_assignment(lhs, rhs, 1, 2, long_string.size() - 2); + Tests::and_assignment(lhs, rhs, long_string.size()/2, long_string.size()/2, long_string.size() - (long_string.size()/2)); + } + { + boost::dynamic_bitset lhs(long_string.size(), 1), rhs(long_string); + Tests::and_assignment(lhs, rhs, 0, 0, long_string.size()); + Tests::and_assignment(lhs, rhs, 1, 2, long_string.size() - 2); + Tests::and_assignment(lhs, rhs, long_string.size()/2, long_string.size()/2, long_string.size() - (long_string.size()/2)); + } + //===================================================================== + // Test operator |= + { + boost::dynamic_bitset lhs(3), rhs(4); + Tests::or_assignment(lhs, rhs, 0, 0, 3); + Tests::or_assignment(lhs, rhs, 0, 1, 3); + } + { + boost::dynamic_bitset lhs(std::string("11")), rhs(std::string("0")); + Tests::or_assignment(lhs, rhs, 0, 0, 1); + Tests::or_assignment(lhs, rhs, 1, 0, 1); + } + { + boost::dynamic_bitset lhs(long_string.size(), 0), rhs(long_string); + Tests::or_assignment(lhs, rhs, 0, 0, long_string.size()); + Tests::or_assignment(lhs, rhs, 1, 2, long_string.size() - 2); + Tests::or_assignment(lhs, rhs, long_string.size()/2, long_string.size()/2, long_string.size() - (long_string.size()/2)); + } + { + boost::dynamic_bitset lhs(long_string.size(), 1), rhs(long_string); + Tests::or_assignment(lhs, rhs, 0, 0, long_string.size()); + Tests::or_assignment(lhs, rhs, 1, 2, long_string.size() - 2); + Tests::or_assignment(lhs, rhs, long_string.size()/2, long_string.size()/2, long_string.size() - (long_string.size()/2)); + } + //===================================================================== + // Test operator^= + { + boost::dynamic_bitset lhs(3), rhs(4); + Tests::xor_assignment(lhs, rhs, 0, 0, 3); + Tests::xor_assignment(lhs, rhs, 0, 1, 3); + } + { + boost::dynamic_bitset lhs(std::string("11")), rhs(std::string("0")); + Tests::xor_assignment(lhs, rhs, 0, 0, 1); + Tests::xor_assignment(lhs, rhs, 1, 0, 1); + } + { + boost::dynamic_bitset lhs(std::string("00")), rhs(std::string("1")); + Tests::xor_assignment(lhs, rhs, 0, 0, 1); + Tests::xor_assignment(lhs, rhs, 1, 0, 1); + } + { + boost::dynamic_bitset lhs(long_string), rhs(long_string); + Tests::xor_assignment(lhs, rhs, 0, 0, long_string.size()); + Tests::xor_assignment(lhs, rhs, 1, 2, long_string.size() - 2); + Tests::xor_assignment(lhs, rhs, long_string.size()/2, long_string.size()/2, long_string.size() - (long_string.size()/2)); + } + //===================================================================== + // Test operator-= + { + boost::dynamic_bitset lhs(3), rhs(4); + Tests::sub_assignment(lhs, rhs, 0, 0, 3); + Tests::sub_assignment(lhs, rhs, 0, 1, 3); + } + { + boost::dynamic_bitset lhs(std::string("11")), rhs(std::string("0")); + Tests::sub_assignment(lhs, rhs, 0, 0, 1); + Tests::sub_assignment(lhs, rhs, 1, 0, 1); + } + { + boost::dynamic_bitset lhs(std::string("00")), rhs(std::string("1")); + Tests::sub_assignment(lhs, rhs, 0, 0, 1); + Tests::sub_assignment(lhs, rhs, 1, 0, 1); + } + { + boost::dynamic_bitset lhs(long_string), rhs(long_string); + Tests::sub_assignment(lhs, rhs, 0, 0, long_string.size()); + Tests::sub_assignment(lhs, rhs, 1, 2, long_string.size() - 2); + Tests::sub_assignment(lhs, rhs, long_string.size()/2, long_string.size()/2, long_string.size() - (long_string.size()/2)); + } +} + +int +main() +{ + run_test_cases(); + run_test_cases(); + run_test_cases(); + run_test_cases(); +# ifdef BOOST_HAS_LONG_LONG + run_test_cases< ::boost::ulong_long_type>(); +# endif + + return boost::report_errors(); +} diff --git a/test/dyn_bitset_unit_tests7.cpp b/test/dyn_bitset_unit_tests7.cpp new file mode 100644 index 000000000..4afdb5016 --- /dev/null +++ b/test/dyn_bitset_unit_tests7.cpp @@ -0,0 +1,269 @@ +// ----------------------------------------------------------- +// Copyright (c) 2001 Jeremy Siek +// Copyright (c) 2003-2006 Gennaro Prota +// Copyright (c) 2014 Ahmed Charles +// Copyright (c) 2014 Riccardo Marcangelo +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// ----------------------------------------------------------- + +#include +#include "bitset_test.hpp" +#include +#include +#include + +template +void run_test_cases( BOOST_EXPLICIT_TEMPLATE_TYPE(Block) ) +{ + // a bunch of typedefs which will be handy later on + typedef boost::dynamic_bitset bitset_type; + typedef bitset_test Tests; + // typedef typename bitset_type::size_type size_type; // unusable with Borland 5.5.1 + + std::string long_string = get_long_string(); + + //===================================================================== + // Test intersects + { + bitset_type a(3); // empty + bitset_type b(4); + Tests::intersects(a, b, 0, 0, 3); + Tests::intersects(a, b, 0, 1, 3); + } + { + bitset_type a(7); + bitset_type b(5, 8ul); + Tests::intersects(a, b, 0, 0, 5); + } + { + bitset_type a(8, 0ul); + bitset_type b(15, 0ul); + b[9] = 1; + Tests::intersects(a, b, 0, 3, 8); + } + { + bitset_type a(15, 0ul); + bitset_type b(22, 0ul); + a[14] = b[14] = 1; + Tests::intersects(a, b, 0, 1, 14); + } + { + bitset_type a(long_string), b(long_string); + b[long_string.size()/2].flip(); + Tests::intersects(a, b, 0, 0, long_string.size()); + } + { + bitset_type a(long_string), b(~a); + for(size_t i = 0; i < a.size(); i+= 5) + { + Tests::intersects(a, b, 0, 0, i); + a[i].flip(); + Tests::intersects(a, b, 0, 0, i); + a[i].flip(); + } + + } + { + bitset_type a(long_string), b(a); + for(size_t i = 0; i < a.size(); i+= 5) + { + Tests::intersects(a, b, 0, 0, i); + a[i].flip(); + Tests::intersects(a, b, 0, 0, i); + a[i].flip(); + } + + } + + //===================================================================== + // Test operator== + { + bitset_type a(3), b(4); + Tests::operator_equal(a, b, 0, 0, 3); + Tests::operator_equal(a, b, 0, 1, 3); + } + { + bitset_type a(3), b; + Tests::operator_equal(a, b, 0, 0, 0); + } + { + bitset_type a, b(4); + Tests::operator_equal(a, b, 0, 0, 0); + } + { + bitset_type a(std::string("00")), b(std::string("0")); + Tests::operator_equal(a, b, 0, 0, 1); + Tests::operator_equal(a, b, 1, 0, 1); + } + { + bitset_type a(std::string("11")), b(std::string("1")); + Tests::operator_equal(a, b, 0, 0, 1); + Tests::operator_equal(a, b, 1, 0, 1); + } + { + bitset_type a(long_string), b(long_string); + Tests::operator_equal(a, b, 0, 0, long_string.size()); + Tests::operator_equal(a, b, long_string.size()/2, long_string.size()/2, long_string.size() - (long_string.size()/2)); + } + { + bitset_type a(long_string), b(long_string); + a[long_string.size()/2].flip(); + Tests::operator_equal(a, b, 0, 0, long_string.size()); + Tests::operator_equal(a, b, long_string.size()/2, long_string.size()/2, long_string.size() - (long_string.size()/2)); + } + { + bitset_type a(long_string), b(long_string); + b[long_string.size()/2].flip(); + Tests::operator_equal(a, b, 0, 0, long_string.size()); + Tests::operator_equal(a, b, long_string.size()/2, long_string.size()/2, long_string.size() - (long_string.size()/2)); + } + //===================================================================== + // Test operator!= + { + bitset_type a(3), b(4); + Tests::operator_not_equal(a, b, 0, 0, 3); + Tests::operator_not_equal(a, b, 0, 1, 3); + } + { + bitset_type a(std::string("00")), b(std::string("0")); + Tests::operator_not_equal(a, b, 0, 0, 1); + Tests::operator_not_equal(a, b, 1, 0, 1); + } + { + bitset_type a(std::string("11")), b(std::string("1")); + Tests::operator_not_equal(a, b, 0, 0, 1); + Tests::operator_not_equal(a, b, 1, 0, 1); + } + { + bitset_type a(long_string), b(long_string); + Tests::operator_not_equal(a, b, 0, 0, long_string.size()); + Tests::operator_not_equal(a, b, long_string.size()/2, long_string.size()/2, long_string.size() - (long_string.size()/2)); + } + { + bitset_type a(long_string), b(long_string); + a[long_string.size()/2].flip(); + Tests::operator_not_equal(a, b, 0, 0, long_string.size()); + Tests::operator_not_equal(a, b, long_string.size()/2, long_string.size()/2, long_string.size() - (long_string.size()/2)); + } + { + bitset_type a(long_string), b(long_string); + b[long_string.size()/2].flip(); + Tests::operator_not_equal(a, b, 0, 0, long_string.size()); + Tests::operator_not_equal(a, b, long_string.size()/2, long_string.size()/2, long_string.size() - (long_string.size()/2)); + } + //===================================================================== + // Test a & b + { + bitset_type lhs(3), rhs(4); + Tests::operator_and(lhs, rhs, 0, 0, 3); + Tests::operator_and(lhs, rhs, 0, 1, 3); + } + { + bitset_type lhs(std::string("11")), rhs(std::string("0")); + Tests::operator_and(lhs, rhs, 0, 0, 1); + Tests::operator_and(lhs, rhs, 1, 0, 1); + } + { + bitset_type lhs(long_string.size(), 0), rhs(long_string); + Tests::operator_and(lhs, rhs, 0, 0, long_string.size()/2); + Tests::operator_and(lhs, rhs, 1, 2, long_string.size() - 2); + Tests::operator_and(lhs, rhs, long_string.size()/2, 0, long_string.size() - (long_string.size()/2)); + } + { + bitset_type lhs(long_string.size(), 1), rhs(long_string); + Tests::operator_and(lhs, rhs, 0, 0, long_string.size()/2); + Tests::operator_and(lhs, rhs, 1, 2, long_string.size() - 2); + Tests::operator_and(lhs, rhs, long_string.size()/2, 0, long_string.size() - (long_string.size()/2)); + } + //===================================================================== + // Test a | b + { + bitset_type lhs(3), rhs(4); + Tests::operator_or(lhs, rhs, 0, 0, 3); + Tests::operator_or(lhs, rhs, 0, 1, 3); + } + { + bitset_type lhs(std::string("11")), rhs(std::string("0")); + Tests::operator_or(lhs, rhs, 0, 0, 1); + Tests::operator_or(lhs, rhs, 1, 0, 1); + } + { + bitset_type lhs(long_string.size(), 0), rhs(long_string); + Tests::operator_or(lhs, rhs, 0, 0, long_string.size()/2); + Tests::operator_or(lhs, rhs, 1, 2, long_string.size() - 2); + Tests::operator_or(lhs, rhs, long_string.size()/2, 0, long_string.size() - (long_string.size()/2)); + } + { + bitset_type lhs(long_string.size(), 1), rhs(long_string); + Tests::operator_or(lhs, rhs, 0, 0, long_string.size()/2); + Tests::operator_or(lhs, rhs, 1, 2, long_string.size() - 2); + Tests::operator_or(lhs, rhs, long_string.size()/2, 0, long_string.size() - (long_string.size()/2)); + } + //===================================================================== + // Test a^b + { + bitset_type lhs(3), rhs(4); + Tests::operator_xor(lhs, rhs, 0, 0, 3); + Tests::operator_xor(lhs, rhs, 0, 1, 3); + } + { + bitset_type lhs(std::string("11")), rhs(std::string("0")); + Tests::operator_xor(lhs, rhs, 0, 0, 1); + Tests::operator_xor(lhs, rhs, 1, 0, 1); + } + { + bitset_type lhs(long_string.size(), 0), rhs(long_string); + Tests::operator_xor(lhs, rhs, 0, 0, long_string.size()/2); + Tests::operator_xor(lhs, rhs, 1, 2, long_string.size() - 2); + Tests::operator_xor(lhs, rhs, long_string.size()/2, 0, long_string.size() - (long_string.size()/2)); + } + { + bitset_type lhs(long_string.size(), 1), rhs(long_string); + Tests::operator_xor(lhs, rhs, 0, 0, long_string.size()/2); + Tests::operator_xor(lhs, rhs, 1, 2, long_string.size() - 2); + Tests::operator_xor(lhs, rhs, long_string.size()/2, 0, long_string.size() - (long_string.size()/2)); + } + //===================================================================== + // Test a-b + { + bitset_type lhs(3), rhs(4); + Tests::operator_sub(lhs, rhs, 0, 0, 3); + Tests::operator_sub(lhs, rhs, 0, 1, 3); + } + { + bitset_type lhs(std::string("11")), rhs(std::string("0")); + Tests::operator_sub(lhs, rhs, 0, 0, 1); + Tests::operator_sub(lhs, rhs, 1, 0, 1); + } + { + bitset_type lhs(long_string.size(), 0), rhs(long_string); + Tests::operator_sub(lhs, rhs, 0, 0, long_string.size()/2); + Tests::operator_sub(lhs, rhs, 1, 2, long_string.size() - 2); + Tests::operator_sub(lhs, rhs, long_string.size()/2, 0, long_string.size() - (long_string.size()/2)); + } + { + bitset_type lhs(long_string.size(), 1), rhs(long_string); + Tests::operator_sub(lhs, rhs, 0, 0, long_string.size()/2); + Tests::operator_sub(lhs, rhs, 1, 2, long_string.size() - 2); + Tests::operator_sub(lhs, rhs, long_string.size()/2, 0, long_string.size() - (long_string.size()/2)); + } +} + + +int +main() +{ + run_test_cases(); + run_test_cases(); + run_test_cases(); + run_test_cases(); +# ifdef BOOST_HAS_LONG_LONG + run_test_cases< ::boost::ulong_long_type>(); +# endif + + return boost::report_errors(); +}