diff --git a/include/boost/dynamic_bitset/dynamic_bitset.hpp b/include/boost/dynamic_bitset/dynamic_bitset.hpp index 6cc43642..3eab7852 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 6d173044..f2518813 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 758d44dc..ab446c31 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 00000000..2c6442a4 --- /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 00000000..4afdb501 --- /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(); +}