mirror of
https://github.com/boostorg/dynamic_bitset.git
synced 2026-01-19 04:12:09 +00:00
Add find_last_one() and find_previous_one()
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
// -----------------------------------------------------------
|
||||
// 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
|
||||
@@ -11,11 +10,12 @@
|
||||
//
|
||||
// -----------------------------------------------------------
|
||||
|
||||
#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 {
|
||||
@@ -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 ) );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -1288,6 +1288,14 @@ public:
|
||||
// -----------------------------------------------------------------------
|
||||
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" )
|
||||
@@ -1308,6 +1316,21 @@ public:
|
||||
// -----------------------------------------------------------------------
|
||||
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" )
|
||||
|
||||
@@ -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
|
||||
@@ -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>
|
||||
@@ -1450,6 +1450,23 @@ dynamic_bitset< Block, AllocatorOrContainer >::find_first_zero( size_type pos )
|
||||
: 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
|
||||
@@ -1466,6 +1483,39 @@ dynamic_bitset< Block, AllocatorOrContainer >::find_next_one( size_type pos ) co
|
||||
: 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
|
||||
|
||||
@@ -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 ] ]
|
||||
|
||||
@@ -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
|
||||
@@ -1107,6 +1107,23 @@ 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 )
|
||||
{
|
||||
@@ -1118,6 +1135,26 @@ struct bitset_test
|
||||
}
|
||||
}
|
||||
|
||||
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 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
operator_equal( const Bitset & a, const Bitset & b )
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// -----------------------------------------------------------
|
||||
// Copyright (c) 2001 Jeremy Siek
|
||||
// Copyright (c) 2003-2006, 2025 Gennaro Prota
|
||||
// Copyright (c) 2003-2006, 2025-2026 Gennaro Prota
|
||||
// Copyright (c) 2014 Ahmed Charles
|
||||
// Copyright (c) 2014 Riccardo Marcangelo
|
||||
//
|
||||
@@ -333,6 +333,31 @@ run_test_cases()
|
||||
b.set( b.size() - 1, false );
|
||||
Tests::find_first( b, 0, false );
|
||||
}
|
||||
|
||||
//=====================================================================
|
||||
// Test find_last_one
|
||||
{
|
||||
// empty bitset
|
||||
bitset_type b;
|
||||
Tests::find_last_one( b );
|
||||
}
|
||||
{
|
||||
// bitset of size 1
|
||||
bitset_type b( 1, 1ul );
|
||||
Tests::find_last_one( b );
|
||||
b.flip();
|
||||
Tests::find_last_one( b );
|
||||
}
|
||||
{
|
||||
// multi-block bitset
|
||||
bitset_type b( 4 * bitset_type::bits_per_block, 1ul );
|
||||
Tests::find_last_one( b );
|
||||
b.set( 3 * bitset_type::bits_per_block );
|
||||
Tests::find_last_one( b );
|
||||
b.set( 3 * bitset_type::bits_per_block - 1 );
|
||||
Tests::find_last_one( b );
|
||||
}
|
||||
|
||||
//=====================================================================
|
||||
// Test find_next_one, find_next_zero
|
||||
{
|
||||
@@ -418,6 +443,38 @@ run_test_cases()
|
||||
Tests::find_pos( b, b.npos );
|
||||
Tests::find_pos( b, b.npos, false );
|
||||
}
|
||||
|
||||
//=====================================================================
|
||||
// Test find_previous_one
|
||||
{
|
||||
bitset_type b;
|
||||
Tests::find_previous_one( b, b.npos);
|
||||
Tests::find_previous_one( b, 2);
|
||||
Tests::find_previous_one( b, 1);
|
||||
Tests::find_previous_one( b, 0);
|
||||
}
|
||||
{
|
||||
bitset_type b( 1, 1ul );
|
||||
Tests::find_previous_one( b, b.npos);
|
||||
Tests::find_previous_one( b, 2);
|
||||
Tests::find_previous_one( b, 1);
|
||||
Tests::find_previous_one( b, 0);
|
||||
}
|
||||
{
|
||||
bitset_type b( 4 * bitset_type::bits_per_block, 0ul );
|
||||
b.set( 4 );
|
||||
Tests::find_previous_one( b, b.npos);
|
||||
Tests::find_previous_one( b, 4 * bitset_type::bits_per_block );
|
||||
Tests::find_previous_one( b, 4 * bitset_type::bits_per_block - 1 );
|
||||
Tests::find_previous_one( b, 3 * bitset_type::bits_per_block );
|
||||
Tests::find_previous_one( b, 3 * bitset_type::bits_per_block - 1 );
|
||||
Tests::find_previous_one( b, bitset_type::bits_per_block );
|
||||
Tests::find_previous_one( b, bitset_type::bits_per_block - 1 );
|
||||
Tests::find_previous_one( b, 6);
|
||||
Tests::find_previous_one( b, 5);
|
||||
Tests::find_previous_one( b, 4);
|
||||
Tests::find_previous_one( b, 0);
|
||||
}
|
||||
//=====================================================================
|
||||
// Test operator==
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//
|
||||
// Copyright (C) 2018 James E. King III
|
||||
// Copyright 2026 Gennaro Prota
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -8,17 +9,20 @@
|
||||
|
||||
#include "boost/core/lightweight_test.hpp"
|
||||
#include "boost/cstdint.hpp"
|
||||
#include "boost/dynamic_bitset/detail/lowest_bit.hpp"
|
||||
#include "boost/dynamic_bitset/detail/lowest_highest_bit.hpp"
|
||||
|
||||
int
|
||||
main( int, char *[] )
|
||||
{
|
||||
for ( boost::int32_t i = 1; i < 32; ++i ) {
|
||||
BOOST_TEST_EQ( i, boost::detail::lowest_bit( 1u << i ) );
|
||||
BOOST_TEST_EQ( i, boost::detail::highest_bit( 1u << i ) );
|
||||
}
|
||||
|
||||
BOOST_TEST_EQ( 2, boost::detail::lowest_bit( 123456788 ) );
|
||||
BOOST_TEST_EQ( 30, boost::detail::lowest_bit( static_cast< boost::int64_t >( 1507208177123328 ) ) );
|
||||
BOOST_TEST_EQ( 15, boost::detail::highest_bit( 0b1000100101111000));
|
||||
BOOST_TEST_EQ( 53, boost::detail::highest_bit( static_cast< boost::int64_t >( 0x20000000000000 ) ) );
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
Reference in New Issue
Block a user