mirror of
https://github.com/boostorg/dynamic_bitset.git
synced 2026-01-19 04:12:09 +00:00
Add find_first_off(), find_first_off( size_type ) and find_next_off( size_type )
This commit is contained in:
@@ -1076,6 +1076,17 @@ public:
|
||||
// -----------------------------------------------------------------------
|
||||
size_type find_first() const;
|
||||
|
||||
//! Finds the first unset bit in `*this`, if any.
|
||||
//!
|
||||
//! \return
|
||||
//! The lowest index `i` such that bit `i` is unset in `*this`,
|
||||
//! or `npos` if no such index exists.
|
||||
//!
|
||||
//! \par Throws
|
||||
//! Nothing.
|
||||
// -----------------------------------------------------------------------
|
||||
size_type find_first_off() const;
|
||||
|
||||
//! Finds the first set bit in `*this` with an index >= `pos`,
|
||||
//! if any.
|
||||
//!
|
||||
@@ -1089,6 +1100,19 @@ public:
|
||||
// -----------------------------------------------------------------------
|
||||
size_type find_first( size_type pos ) const;
|
||||
|
||||
//! Finds the first unset bit in `*this` with an index >= `pos`,
|
||||
//! if any.
|
||||
//!
|
||||
//! \return
|
||||
//! The lowest index `i` greater than or equal to `pos` such
|
||||
//! that bit `i` is unset in `*this`, or `npos` if no such index
|
||||
//! exists.
|
||||
//!
|
||||
//! \par Throws
|
||||
//! Nothing.
|
||||
// -----------------------------------------------------------------------
|
||||
size_type find_first_off( size_type pos ) const;
|
||||
|
||||
//! Finds the first bit set in `*this` with an index > `pos`, if
|
||||
//! any.
|
||||
//!
|
||||
@@ -1104,6 +1128,18 @@ public:
|
||||
// -----------------------------------------------------------------------
|
||||
size_type find_next( size_type pos ) const;
|
||||
|
||||
//! Finds the first unset bit in `*this` with an index > `pos`,
|
||||
//! if any.
|
||||
//!
|
||||
//! \param pos The lower bound (exclusively) to start the search
|
||||
//! from.
|
||||
//!
|
||||
//! \return
|
||||
//! The lowest index `i` greater than `pos` such that bit `i` is
|
||||
//! unset, or `npos` if no such index exists.
|
||||
// -----------------------------------------------------------------------
|
||||
size_type find_next_off( size_type pos ) const;
|
||||
|
||||
template< typename B, typename A >
|
||||
friend bool operator==( const dynamic_bitset< B, A > & a, const dynamic_bitset< B, A > & b );
|
||||
|
||||
@@ -1146,7 +1182,8 @@ private:
|
||||
bool m_check_invariants() const;
|
||||
|
||||
static bool m_not_empty( Block x );
|
||||
size_type m_do_find_from( size_type first_block ) const;
|
||||
static bool m_not_full( Block x );
|
||||
size_type m_do_find_from( size_type first_block, bool value ) const;
|
||||
|
||||
int count_extra_bits() const noexcept;
|
||||
static size_type block_index( size_type pos ) noexcept;
|
||||
|
||||
@@ -946,26 +946,39 @@ dynamic_bitset< Block, Allocator >::intersects( const dynamic_bitset & b ) const
|
||||
// --------------------------------
|
||||
// lookup
|
||||
|
||||
// Look for the first bit "on", starting from the block with index
|
||||
// Look for the first bit with value `value`, starting from the block with index
|
||||
// first_block.
|
||||
template< typename Block, typename Allocator >
|
||||
typename dynamic_bitset< Block, Allocator >::size_type
|
||||
dynamic_bitset< Block, Allocator >::m_do_find_from( size_type first_block ) const
|
||||
dynamic_bitset< Block, Allocator >::m_do_find_from( size_type first_block, bool value ) const
|
||||
{
|
||||
size_type i = std::distance( m_bits.begin(), std::find_if( m_bits.begin() + first_block, m_bits.end(), m_not_empty ) );
|
||||
size_type i = std::distance( m_bits.begin(), std::find_if( m_bits.begin() + first_block, m_bits.end(),
|
||||
value
|
||||
? m_not_empty
|
||||
: m_not_full ) );
|
||||
|
||||
if ( i >= num_blocks() ) {
|
||||
return npos; // not found
|
||||
}
|
||||
|
||||
return i * bits_per_block + static_cast< size_type >( detail::lowest_bit( m_bits[ i ] ) );
|
||||
const Block b = value
|
||||
? m_bits[ i ]
|
||||
: m_bits[ i ] ^ Block( -1 );
|
||||
return i * bits_per_block + static_cast< size_type >( detail::lowest_bit( b ) );
|
||||
}
|
||||
|
||||
template< typename Block, typename Allocator >
|
||||
typename dynamic_bitset< Block, Allocator >::size_type
|
||||
dynamic_bitset< Block, Allocator >::find_first() const
|
||||
{
|
||||
return m_do_find_from( 0 );
|
||||
return m_do_find_from( 0, true );
|
||||
}
|
||||
|
||||
template< typename Block, typename Allocator >
|
||||
typename dynamic_bitset< Block, Allocator >::size_type
|
||||
dynamic_bitset< Block, Allocator >::find_first_off() const
|
||||
{
|
||||
return m_do_find_from( 0, false );
|
||||
}
|
||||
|
||||
template< typename Block, typename Allocator >
|
||||
@@ -983,8 +996,36 @@ dynamic_bitset< Block, Allocator >::find_first( size_type pos ) const
|
||||
// shift bits upto one immediately after current
|
||||
const Block fore = m_bits[ blk ] >> ind;
|
||||
|
||||
return fore ? pos + static_cast< size_type >( detail::lowest_bit( fore ) )
|
||||
: m_do_find_from( blk + 1 );
|
||||
const bool found = m_not_empty( fore );
|
||||
return found ? pos + static_cast< size_type >( detail::lowest_bit( fore ) )
|
||||
: m_do_find_from( blk + 1, true );
|
||||
}
|
||||
|
||||
template< typename Block, typename Allocator >
|
||||
typename dynamic_bitset< Block, Allocator >::size_type
|
||||
dynamic_bitset< Block, Allocator >::find_first_off( size_type pos ) const
|
||||
{
|
||||
if ( pos >= size() ) {
|
||||
return npos;
|
||||
}
|
||||
|
||||
const size_type blk = block_index( pos );
|
||||
const int ind = bit_index( pos );
|
||||
const Block fore = m_bits[ blk ] >> ind;
|
||||
bool found = false;
|
||||
int lowest_off_bit_pos = -1;
|
||||
if ( m_not_full( fore ) ) {
|
||||
lowest_off_bit_pos = detail::lowest_bit( fore ^ Block( -1 ) );
|
||||
// don't consider a zero introduced by m_bits[ blk ] >> ind as found
|
||||
found = lowest_off_bit_pos <= ( bits_per_block - 1 - ind );
|
||||
}
|
||||
|
||||
const size_type zero_pos = found
|
||||
? pos + lowest_off_bit_pos
|
||||
: m_do_find_from( blk + 1, false );
|
||||
return zero_pos >= size()
|
||||
? npos
|
||||
: zero_pos;
|
||||
}
|
||||
|
||||
template< typename Block, typename Allocator >
|
||||
@@ -997,6 +1038,15 @@ dynamic_bitset< Block, Allocator >::find_next( size_type pos ) const
|
||||
return find_first( pos + 1 );
|
||||
}
|
||||
|
||||
template< typename Block, typename Allocator >
|
||||
typename dynamic_bitset< Block, Allocator >::size_type
|
||||
dynamic_bitset< Block, Allocator >::find_next_off( size_type pos ) const
|
||||
{
|
||||
return pos == npos
|
||||
? npos
|
||||
: find_first_off( pos + 1 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// comparison
|
||||
|
||||
@@ -1472,6 +1522,13 @@ dynamic_bitset< Block, Allocator >::m_not_empty( Block x )
|
||||
return x != Block( 0 );
|
||||
}
|
||||
|
||||
template< typename Block, typename Allocator >
|
||||
bool
|
||||
dynamic_bitset< Block, Allocator >::m_not_full( Block x )
|
||||
{
|
||||
return x != Block( -1 );
|
||||
}
|
||||
|
||||
template< typename Block, typename Allocator >
|
||||
int
|
||||
dynamic_bitset< Block, Allocator >::count_extra_bits() const noexcept
|
||||
|
||||
@@ -994,26 +994,34 @@ struct bitset_test
|
||||
}
|
||||
|
||||
static void
|
||||
find_first( const Bitset & b, typename Bitset::size_type offset = 0 )
|
||||
find_first( const Bitset & b, typename Bitset::size_type offset = 0, bool value = true )
|
||||
{
|
||||
// find first non-null bit from offset onwards, if any
|
||||
const typename Bitset::size_type result = value
|
||||
? b.find_first( offset )
|
||||
: b.find_first_off( offset );
|
||||
|
||||
// find first bit with value `value` from offset onwards, if any
|
||||
typename Bitset::size_type i = offset;
|
||||
while ( i < b.size() && b[ i ] == 0 )
|
||||
while ( i < b.size() && b[ i ] != value )
|
||||
++i;
|
||||
|
||||
if ( i >= b.size() )
|
||||
BOOST_TEST( b.find_first( offset ) == Bitset::npos ); // not found;
|
||||
BOOST_TEST( result == Bitset::npos ); // not found;
|
||||
else {
|
||||
BOOST_TEST( b.find_first( offset ) == i );
|
||||
BOOST_TEST( b.test( i ) == true );
|
||||
BOOST_TEST( result == i );
|
||||
BOOST_TEST( b.test( i ) == value );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
find_pos( const Bitset & b, typename Bitset::size_type pos )
|
||||
find_pos( const Bitset & b, typename Bitset::size_type pos, bool value = true )
|
||||
{
|
||||
find_first( b, pos );
|
||||
BOOST_TEST( next_bit_on( b, pos ) == b.find_next( pos ) );
|
||||
find_first( b, pos, value);
|
||||
if ( value ) {
|
||||
BOOST_TEST( next_bit_on( b, pos ) == b.find_next( pos ) );
|
||||
} else {
|
||||
BOOST_TEST( next_bit_off( b, pos ) == b.find_next_off( pos ) );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1106,6 +1114,32 @@ struct bitset_test
|
||||
return i == b.size() ? Bitset::npos : i;
|
||||
}
|
||||
|
||||
static typename Bitset::size_type
|
||||
next_bit_off( const Bitset & b, typename Bitset::size_type prev )
|
||||
{
|
||||
// helper function for find_pos()
|
||||
//
|
||||
|
||||
if ( b.all() || prev == Bitset::npos ) {
|
||||
return Bitset::npos;
|
||||
}
|
||||
|
||||
++prev;
|
||||
|
||||
if ( prev >= b.size() ) {
|
||||
return Bitset::npos;
|
||||
}
|
||||
|
||||
typename Bitset::size_type i = prev;
|
||||
while ( i < b.size() && b[ i ] ) {
|
||||
++i;
|
||||
}
|
||||
|
||||
return i == b.size()
|
||||
? Bitset::npos
|
||||
: i;
|
||||
}
|
||||
|
||||
static void
|
||||
operator_less_than( const Bitset & a, const Bitset & b )
|
||||
{
|
||||
|
||||
@@ -305,30 +305,37 @@ run_test_cases( BOOST_EXPLICIT_TEMPLATE_TYPE( Block ) )
|
||||
// empty bitset
|
||||
bitset_type b;
|
||||
Tests::find_first( b );
|
||||
Tests::find_first( b, 0, false );
|
||||
}
|
||||
{
|
||||
// bitset of size 1
|
||||
bitset_type b( 1, 1ul );
|
||||
Tests::find_first( b );
|
||||
Tests::find_first( b, 0, false );
|
||||
}
|
||||
{
|
||||
// all-0s bitset
|
||||
bitset_type b( 4 * bitset_type::bits_per_block, 0ul );
|
||||
Tests::find_first( b );
|
||||
Tests::find_first( b, 0, false );
|
||||
}
|
||||
{
|
||||
// first bit on
|
||||
// first bit on or off
|
||||
bitset_type b( 1, 1ul );
|
||||
Tests::find_first( b );
|
||||
b.set( 0, false );
|
||||
Tests::find_first( b, 0, false );
|
||||
}
|
||||
{
|
||||
// last bit on
|
||||
// last bit on or off
|
||||
bitset_type b( 4 * bitset_type::bits_per_block - 1, 0ul );
|
||||
b.set( b.size() - 1 );
|
||||
Tests::find_first( b );
|
||||
b.set( b.size() - 1, false );
|
||||
Tests::find_first( b, 0, false );
|
||||
}
|
||||
//=====================================================================
|
||||
// Test find_next and offset find_first
|
||||
// Test find_next, find_next_off, offset find_first and offset find_first_off
|
||||
{
|
||||
// empty bitset
|
||||
bitset_type b;
|
||||
@@ -338,6 +345,10 @@ run_test_cases( BOOST_EXPLICIT_TEMPLATE_TYPE( Block ) )
|
||||
Tests::find_pos( b, 1 );
|
||||
Tests::find_pos( b, 200 );
|
||||
Tests::find_pos( b, b.npos );
|
||||
Tests::find_pos( b, 0, false );
|
||||
Tests::find_pos( b, 1, false );
|
||||
Tests::find_pos( b, 200, false );
|
||||
Tests::find_pos( b, b.npos, false );
|
||||
}
|
||||
{
|
||||
// bitset of size 1 (find_next can never find)
|
||||
@@ -348,6 +359,10 @@ run_test_cases( BOOST_EXPLICIT_TEMPLATE_TYPE( Block ) )
|
||||
Tests::find_pos( b, 1 );
|
||||
Tests::find_pos( b, 200 );
|
||||
Tests::find_pos( b, b.npos );
|
||||
Tests::find_pos( b, 0, false );
|
||||
Tests::find_pos( b, 1, false );
|
||||
Tests::find_pos( b, 200, false );
|
||||
Tests::find_pos( b, b.npos, false );
|
||||
}
|
||||
{
|
||||
// all-1s bitset
|
||||
@@ -358,8 +373,10 @@ run_test_cases( BOOST_EXPLICIT_TEMPLATE_TYPE( Block ) )
|
||||
const typename bitset_type::size_type larger_than_size = 5 + b.size();
|
||||
for ( typename bitset_type::size_type i = 0; i <= larger_than_size; ++i ) {
|
||||
Tests::find_pos( b, i );
|
||||
Tests::find_pos( b, i, false );
|
||||
}
|
||||
Tests::find_pos( b, b.npos );
|
||||
Tests::find_pos( b, b.npos, false );
|
||||
}
|
||||
{
|
||||
// a bitset with 1s at block boundary only
|
||||
@@ -378,8 +395,10 @@ run_test_cases( BOOST_EXPLICIT_TEMPLATE_TYPE( Block ) )
|
||||
const typename bitset_type::size_type larger_than_size = 5 + b.size();
|
||||
for ( i = 0; i <= larger_than_size; ++i ) {
|
||||
Tests::find_pos( b, i );
|
||||
Tests::find_pos( b, i, false );
|
||||
}
|
||||
Tests::find_pos( b, b.npos );
|
||||
Tests::find_pos( b, b.npos, false );
|
||||
}
|
||||
{
|
||||
// bitset with alternate 1s and 0s
|
||||
@@ -395,8 +414,10 @@ run_test_cases( BOOST_EXPLICIT_TEMPLATE_TYPE( Block ) )
|
||||
const typename bitset_type::size_type larger_than_size = 5 + b.size();
|
||||
for ( i = 0; i <= larger_than_size; ++i ) {
|
||||
Tests::find_pos( b, i );
|
||||
Tests::find_pos( b, i, false );
|
||||
}
|
||||
Tests::find_pos( b, b.npos );
|
||||
Tests::find_pos( b, b.npos, false );
|
||||
}
|
||||
//=====================================================================
|
||||
// Test operator==
|
||||
|
||||
Reference in New Issue
Block a user