Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
// -----------------------------------------------------------
// lowest_bit()
//
// Position of the lowest bit that is set.
// Position of the lowest or highest bit that is set.
//
// Copyright (c) 2003-2004, 2008, 2025 Gennaro Prota
// Copyright (c) 2003-2004, 2008, 2025-2026 Gennaro Prota
//
// 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)
//
// -----------------------------------------------------------

#ifndef BOOST_LOWEST_BIT_HPP_GP_20030301
#define BOOST_LOWEST_BIT_HPP_GP_20030301
#ifndef BOOST_LOWEST_HIGHEST_BIT_HPP_GP_20260109
#define BOOST_LOWEST_HIGHEST_BIT_HPP_GP_20260109

#include "boost/assert.hpp"
#include "boost/core/bit.hpp"
#include <limits>
#include <type_traits>

namespace boost {
Expand All @@ -30,6 +30,16 @@ lowest_bit( T x )
return boost::core::countr_zero( static_cast< typename std::make_unsigned< T >::type >( x ) );
}

template< typename T >
int
highest_bit( T x )
{
BOOST_ASSERT( x >= 1 );

using Unsigned = typename std::make_unsigned< T >::type;
return ( std::numeric_limits< Unsigned >::digits - 1 ) - boost::core::countl_zero( static_cast< Unsigned >( x ) );
}

}
}

Expand Down
53 changes: 48 additions & 5 deletions include/boost/dynamic_bitset/dynamic_bitset.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// -----------------------------------------------------------
//
// Copyright (c) 2001-2002 Chuck Allison and Jeremy Siek
// Copyright (c) 2003-2006, 2008, 2025 Gennaro Prota
// Copyright (c) 2003-2006, 2008, 2025-2026 Gennaro Prota
// Copyright (c) 2014 Ahmed Charles
//
// Copyright (c) 2014 Glen Joseph Fernandes
Expand Down Expand Up @@ -1249,6 +1249,11 @@ class dynamic_bitset
// -----------------------------------------------------------------------
BOOST_DYNAMIC_BITSET_CONSTEXPR20 bool intersects( const dynamic_bitset & b ) const;

//! A deprecated synonym for `find_first_one()`.
// -----------------------------------------------------------------------
BOOST_DEPRECATED( "Use find_first_one(), instead" )
BOOST_DYNAMIC_BITSET_CONSTEXPR20 size_type find_first( size_type pos = 0 ) const;

//! Finds the first set bit in `*this` with an index >= `pos`,
//! if any.
//!
Expand All @@ -1260,8 +1265,13 @@ class dynamic_bitset
//! \par Throws
//! Nothing.
// -----------------------------------------------------------------------
BOOST_DYNAMIC_BITSET_CONSTEXPR20 size_type find_first( size_type pos = 0 ) const;
BOOST_DYNAMIC_BITSET_CONSTEXPR20 size_type find_first_one( size_type pos = 0 ) const;

//! A deprecated synonym for `find_first_zero()`.
// -----------------------------------------------------------------------
BOOST_DEPRECATED( "Use find_first_zero(), instead" )
BOOST_DYNAMIC_BITSET_CONSTEXPR20 size_type find_first_off( size_type pos = 0 ) const;

//! Finds the first unset bit in `*this` with an index >= `pos`,
//! if any.
//!
Expand All @@ -1276,7 +1286,20 @@ class dynamic_bitset
//! \par Throws
//! Nothing.
// -----------------------------------------------------------------------
BOOST_DYNAMIC_BITSET_CONSTEXPR20 size_type find_first_off( size_type pos = 0 ) const;
BOOST_DYNAMIC_BITSET_CONSTEXPR20 size_type find_first_zero( size_type pos = 0 ) const;

//! Finds the last (highest-index) set bit in `*this`, if any; or
//! `npos`.
//!
//! \par Throws
//! Nothing.
// -----------------------------------------------------------------------
BOOST_DYNAMIC_BITSET_CONSTEXPR20 size_type find_last_one() const;

//! A deprecated synonym for `find_next_one()`.
// -----------------------------------------------------------------------
BOOST_DEPRECATED( "Use find_next_one(), instead" )
BOOST_DYNAMIC_BITSET_CONSTEXPR20 size_type find_next( size_type pos ) const;

//! Finds the first bit set in `*this` with an index > `pos`, if
//! any.
Expand All @@ -1291,7 +1314,27 @@ class dynamic_bitset
//! \par Throws
//! Nothing.
// -----------------------------------------------------------------------
BOOST_DYNAMIC_BITSET_CONSTEXPR20 size_type find_next( size_type pos ) const;
BOOST_DYNAMIC_BITSET_CONSTEXPR20 size_type find_next_one( size_type pos ) const;

//! Finds the last set bit in `*this` with an index < `pos`, if
//! any.
//!
//! \param pos The upper bound (exclusively) to start the search
//! from.
//!
//! \return
//! The highest index `i` less than `pos` such that bit `i` is
//! set, or `npos` if no such index exists.
//!
//! \par Throws
//! Nothing.
// -----------------------------------------------------------------------
BOOST_DYNAMIC_BITSET_CONSTEXPR20 size_type find_previous_one( size_type pos ) const;

//! A deprecated synonym for `find_next_zero()`.
// -----------------------------------------------------------------------
BOOST_DEPRECATED( "Use find_next_zero(), instead" )
BOOST_DYNAMIC_BITSET_CONSTEXPR20 size_type find_next_off( size_type pos ) const;

//! Finds the first unset bit in `*this` with an index > `pos`,
//! if any.
Expand All @@ -1303,7 +1346,7 @@ class dynamic_bitset
//! The lowest index `i` greater than `pos` such that bit `i` is
//! unset, or `npos` if no such index exists.
// -----------------------------------------------------------------------
BOOST_DYNAMIC_BITSET_CONSTEXPR20 size_type find_next_off( size_type pos ) const;
BOOST_DYNAMIC_BITSET_CONSTEXPR20 size_type find_next_zero( size_type pos ) const;

template< typename B, typename A >
friend BOOST_DYNAMIC_BITSET_CONSTEXPR20 bool operator==( const dynamic_bitset< B, A > & a, const dynamic_bitset< B, A > & b );
Expand Down
88 changes: 83 additions & 5 deletions include/boost/dynamic_bitset/impl/dynamic_bitset.ipp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// -----------------------------------------------------------
//
// Copyright (c) 2001-2002 Chuck Allison and Jeremy Siek
// Copyright (c) 2003-2006, 2008, 2025 Gennaro Prota
// Copyright (c) 2003-2006, 2008, 2025-2026 Gennaro Prota
// Copyright (c) 2014 Ahmed Charles
//
// Copyright (c) 2014 Glen Joseph Fernandes
Expand All @@ -19,7 +19,7 @@
#include "boost/assert.hpp"
#include "boost/core/bit.hpp"
#include "boost/core/no_exceptions_support.hpp"
#include "boost/dynamic_bitset/detail/lowest_bit.hpp"
#include "boost/dynamic_bitset/detail/lowest_highest_bit.hpp"
#include "boost/functional/hash/hash.hpp"
#include "boost/throw_exception.hpp"
#include <algorithm>
Expand Down Expand Up @@ -1207,7 +1207,7 @@ dynamic_bitset< Block, AllocatorOrContainer >::

// Check for overflows. This may be a performance burden on very large
// bitsets but is required by the specification, sorry.
if ( find_first( ulong_width ) != npos ) {
if ( find_first_one( ulong_width ) != npos ) {
BOOST_THROW_EXCEPTION( std::overflow_error( "boost::dynamic_bitset::to_ulong overflow" ) );
}

Expand Down Expand Up @@ -1392,6 +1392,13 @@ dynamic_bitset< Block, AllocatorOrContainer >::m_do_find_from( size_type first_b
template< typename Block, typename AllocatorOrContainer >
BOOST_DYNAMIC_BITSET_CONSTEXPR20 typename dynamic_bitset< Block, AllocatorOrContainer >::size_type
dynamic_bitset< Block, AllocatorOrContainer >::find_first( size_type pos ) const
{
return find_first_one( pos );
}

template< typename Block, typename AllocatorOrContainer >
BOOST_DYNAMIC_BITSET_CONSTEXPR20 typename dynamic_bitset< Block, AllocatorOrContainer >::size_type
dynamic_bitset< Block, AllocatorOrContainer >::find_first_one( size_type pos ) const
{
const size_type sz = size();
if ( pos >= sz ) {
Expand All @@ -1412,6 +1419,13 @@ dynamic_bitset< Block, AllocatorOrContainer >::find_first( size_type pos ) const
template< typename Block, typename AllocatorOrContainer >
BOOST_DYNAMIC_BITSET_CONSTEXPR20 typename dynamic_bitset< Block, AllocatorOrContainer >::size_type
dynamic_bitset< Block, AllocatorOrContainer >::find_first_off( size_type pos ) const
{
return find_first_zero( pos );
}

template< typename Block, typename AllocatorOrContainer >
BOOST_DYNAMIC_BITSET_CONSTEXPR20 typename dynamic_bitset< Block, AllocatorOrContainer >::size_type
dynamic_bitset< Block, AllocatorOrContainer >::find_first_zero( size_type pos ) const
{
if ( pos >= size() ) {
return npos;
Expand All @@ -1436,22 +1450,86 @@ dynamic_bitset< Block, AllocatorOrContainer >::find_first_off( size_type pos ) c
: zero_pos;
}

template< typename Block, typename AllocatorOrContainer >
BOOST_DYNAMIC_BITSET_CONSTEXPR20 typename dynamic_bitset< Block, AllocatorOrContainer >::size_type
dynamic_bitset< Block, AllocatorOrContainer >::find_last_one() const
{
size_type result = npos;

size_type i = num_blocks();
while ( i > 0 ) {
--i;
if ( m_not_empty( m_bits[ i ] ) ) {
result = i * bits_per_block + detail::highest_bit( m_bits[ i ] );
break;
}
}
return result;
}

template< typename Block, typename AllocatorOrContainer >
BOOST_DYNAMIC_BITSET_CONSTEXPR20 typename dynamic_bitset< Block, AllocatorOrContainer >::size_type
dynamic_bitset< Block, AllocatorOrContainer >::find_next( size_type pos ) const
{
return find_next_one( pos );
}

template< typename Block, typename AllocatorOrContainer >
BOOST_DYNAMIC_BITSET_CONSTEXPR20 typename dynamic_bitset< Block, AllocatorOrContainer >::size_type
dynamic_bitset< Block, AllocatorOrContainer >::find_next_one( size_type pos ) const
{
return pos == npos
? npos
: find_first( pos + 1 );
: find_first_one( pos + 1 );
}

template< typename Block, typename AllocatorOrContainer >
BOOST_DYNAMIC_BITSET_CONSTEXPR20 typename dynamic_bitset< Block, AllocatorOrContainer >::size_type
dynamic_bitset< Block, AllocatorOrContainer >::find_previous_one( size_type pos ) const
{
if ( pos == 0 || empty() ) {
return npos;
}

if ( pos >= size() ) {
return find_last_one();
}

const size_type blk = block_index( pos );
const int ind = bit_index( pos );
// mask out bits from ind upwards
Block back = m_bits[ blk ] & ( ( Block( 1 ) << ind ) - 1 );
bool found = m_not_empty( back );
size_type i = blk;
if ( ! found ) {
while ( i > 0 ) {
--i;
back = m_bits[ i ];
if ( m_not_empty( back ) ) {
found = true;
break;
}
}
}
return found
? i * bits_per_block + detail::highest_bit( back )
: npos;
}

template< typename Block, typename AllocatorOrContainer >
BOOST_DYNAMIC_BITSET_CONSTEXPR20 typename dynamic_bitset< Block, AllocatorOrContainer >::size_type
dynamic_bitset< Block, AllocatorOrContainer >::find_next_off( size_type pos ) const
{
return find_next_zero( pos );
}

template< typename Block, typename AllocatorOrContainer >
BOOST_DYNAMIC_BITSET_CONSTEXPR20 typename dynamic_bitset< Block, AllocatorOrContainer >::size_type
dynamic_bitset< Block, AllocatorOrContainer >::find_next_zero( size_type pos ) const
{
return pos == npos
? npos
: find_first_off( pos + 1 );
: find_first_zero( pos + 1 );
}

//-----------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion test/Jamfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ test-suite dynamic_bitset :
[ run dyn_bitset_unit_tests4.cpp : : : <library>/boost/filesystem//boost_filesystem
<library>/boost/system//boost_system ]
[ run test_ambiguous_set.cpp ]
[ run test_lowest_bit.cpp ]
[ run test_lowest_highest_bit.cpp ]

[ run test_boost_hash.cpp ]
[ run test_std_hash.cpp : : : [ requires cxx11_hdr_unordered_set ] ]
Expand Down
47 changes: 42 additions & 5 deletions test/bitset_test.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// -----------------------------------------------------------
// Copyright (c) 2001 Jeremy Siek
// Copyright (c) 2003-2006, 2008, 2025 Gennaro Prota
// Copyright (c) 2003-2006, 2008, 2025-2026 Gennaro Prota
// Copyright (c) 2014 Ahmed Charles
// Copyright (c) 2014 Riccardo Marcangelo
// Copyright (c) 2018 Evgeny Shulgin
Expand Down Expand Up @@ -1091,8 +1091,8 @@ struct bitset_test
find_first( const Bitset & b, typename Bitset::size_type offset = 0, bool value = true )
{
const typename Bitset::size_type result = value
? b.find_first( offset )
: b.find_first_off( offset );
? b.find_first_one( offset )
: b.find_first_zero( offset );

// find first bit with value `value` from offset onwards, if any
typename Bitset::size_type i = offset;
Expand All @@ -1107,14 +1107,51 @@ struct bitset_test
}
}

static void
find_last_one( const Bitset & b )
{
const typename Bitset::size_type result = b.find_last_one();

if ( b.none() ) {
BOOST_TEST( result == Bitset::npos );
} else {
typename Bitset::size_type i = b.size() - 1;
while ( i > 0 && ! b[ i ] ) {
--i;
}
BOOST_TEST( result == i );
BOOST_TEST( b.test( i ) );
}
}

static void
find_pos( const Bitset & b, typename Bitset::size_type pos, bool value = true )
{
find_first( b, pos, value);
if ( value ) {
BOOST_TEST( next_bit_on( b, pos ) == b.find_next( pos ) );
BOOST_TEST( next_bit_on( b, pos ) == b.find_next_one( pos ) );
} else {
BOOST_TEST( next_bit_off( b, pos ) == b.find_next_off( pos ) );
BOOST_TEST( next_bit_off( b, pos ) == b.find_next_zero( pos ) );
}
}

static void
find_previous_one( const Bitset & b, typename Bitset::size_type pos )
{
const typename Bitset::size_type result = b.find_previous_one( pos );
if ( b.none() || pos == 0 ) {
BOOST_TEST( result == Bitset::npos );
} else {
typename Bitset::size_type i = (std::min)(pos - 1, b.size() - 1);
while ( i > 0 && ! b[ i ] ) {
--i;
}
if ( i == 0 && ! b[ i ] ) {
BOOST_TEST( result == Bitset::npos );
} else {
BOOST_TEST( result == i );
BOOST_TEST( b.test( i ) );
}
}
}

Expand Down
Loading
Loading