// ----------------------------------------------------------- // Copyright (c) 2001 Jeremy Siek // Copyright (c) 2003-2006, 2025 Gennaro Prota // Copyright (c) 2014 Ahmed Charles // Copyright (c) 2014 Riccardo Marcangelo // // Copyright (c) 2014 Glen Joseph Fernandes // (glenjofe@gmail.com) // // 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 "boost/config.hpp" #include "boost/dynamic_bitset/dynamic_bitset.hpp" #include "boost/limits.hpp" #if ! defined( BOOST_NO_CXX11_ALLOCATOR ) # include # include template< typename T > class minimal_allocator { public: typedef T value_type; minimal_allocator() { } template< typename U > minimal_allocator( const minimal_allocator< U > & ) { } T * allocate( std::size_t n ) { void * p = std::malloc( sizeof( T ) * n ); if ( ! p ) { throw std::bad_alloc(); } return static_cast< T * >( p ); } void deallocate( T * p, std::size_t ) { std::free( p ); } }; #endif #define BOOST_BITSET_TEST_COUNT( x ) ( sizeof( x ) / sizeof( x[ 0 ] ) ) template< typename Tests, typename String > void run_string_tests( const String & s ) { const std::size_t len = s.length(); const std::size_t step = len / 4 ? len / 4 : 1; // bitset length determined by the string-related arguments std::size_t i; for ( i = 0; i <= len / 2; i += step ) { Tests::from_string( s, i, len / 2 ); // len/2 - i bits Tests::from_string( s, i, len ); // len - i bits Tests::from_string( s, i, 1 + len * 2 ); // len - i bits } // bitset length explicitly specified for ( i = 0; i <= len / 2; i += step ) { for ( std::size_t sz = 0; sz <= len * 4; sz += step * 2 ) { Tests::from_string( s, i, len / 2, sz ); Tests::from_string( s, i, len, sz ); Tests::from_string( s, i, 1 + len * 2, sz ); } } } // tests the do-the-right-thing constructor dispatch template< typename Tests, typename T > void run_numeric_ctor_tests() { const int bits_per_block = Tests::bits_per_block; const int width = std::numeric_limits< T >::digits; const T ma = ( std::numeric_limits< T >::max )(); const T mi = ( std::numeric_limits< T >::min )(); int sizes[] = { 0, 7 * width / 10, width, 13 * width / 10, 3 * width, 7 * bits_per_block / 10, bits_per_block, 13 * bits_per_block / 10, 3 * bits_per_block }; const T numbers[] = { T( -1 ), T( -3 ), T( -8 ), T( -15 ), T( mi / 2 ), T( mi ), T( 0 ), T( 1 ), T( 3 ), T( 8 ), T( 15 ), T( ma / 2 ), T( ma ) }; for ( std::size_t s = 0; s < BOOST_BITSET_TEST_COUNT( sizes ); ++s ) { for ( std::size_t n = 0; n < BOOST_BITSET_TEST_COUNT( numbers ); ++n ) { // can match ctor from ulong or templated one Tests::from_unsigned_long( sizes[ s ], numbers[ n ] ); typedef std::size_t compare_type; const compare_type sz = sizes[ s ]; // this condition is to be sure that size is representable in T, so // that for signed T's we avoid implementation-defined behavior [if ma // is larger than what std::size_t can hold then this is ok for our // purposes: our sizes are anyhow < max(size_t)], which in turn could // make the first argument of from_unsigned_long() a small negative, // later converted to a very large unsigned. Example: signed 8-bit // char (CHAR_MAX=127), bits_per_block=64, sz = 192 > 127. const bool fits = sz <= static_cast< compare_type >( ma ); if ( fits ) { // can match templated ctor only (so we test dispatching) Tests::from_unsigned_long( static_cast< T >( sizes[ s ] ), numbers[ n ] ); } } } } template< typename Block, typename AllocatorOrContainer = std::allocator< Block > > void run_test_cases() { typedef boost::dynamic_bitset< Block, AllocatorOrContainer > bitset_type; typedef bitset_test< bitset_type > Tests; const int bits_per_block = bitset_type::bits_per_block; const std::string long_string = get_long_string(); const Block all_1s = static_cast< Block >( -1 ); //===================================================================== // Test construction from unsigned long { // NOTE: // // 1. keep this in sync with the numeric types supported // for constructor dispatch (of course) // 2. bool is tested separately; ugly and inelegant, but // we don't have much time to think of a better solution // which is likely to work on broken compilers // const int sizes[] = { 0, 1, 3, 7 * bits_per_block / 10, bits_per_block, 13 * bits_per_block / 10, 3 * bits_per_block }; const bool values[] = { false, true }; for ( std::size_t s = 0; s < BOOST_BITSET_TEST_COUNT( sizes ); ++s ) { for ( std::size_t v = 0; v < BOOST_BITSET_TEST_COUNT( values ); ++v ) { Tests::from_unsigned_long( sizes[ s ], values[ v ] ); Tests::from_unsigned_long( sizes[ s ] != 0, values[ v ] ); } } run_numeric_ctor_tests< Tests, char >(); #if ! defined( BOOST_NO_INTRINSIC_WCHAR_T ) run_numeric_ctor_tests< Tests, wchar_t >(); #endif run_numeric_ctor_tests< Tests, signed char >(); run_numeric_ctor_tests< Tests, short int >(); run_numeric_ctor_tests< Tests, int >(); run_numeric_ctor_tests< Tests, long int >(); run_numeric_ctor_tests< Tests, long long >(); run_numeric_ctor_tests< Tests, unsigned char >(); run_numeric_ctor_tests< Tests, unsigned short >(); run_numeric_ctor_tests< Tests, unsigned int >(); run_numeric_ctor_tests< Tests, unsigned long >(); run_numeric_ctor_tests< Tests, unsigned long long >(); } //===================================================================== // Test construction from a string { run_string_tests< Tests >( std::string( "" ) ); // empty string run_string_tests< Tests >( std::string( "1" ) ); run_string_tests< Tests >( long_string ); #if ! defined BOOST_NO_STD_WSTRING // I need to decide what to do for non "C" locales here. On // one hand I should have better tests. On the other one // I don't want tests for dynamic_bitset to cope with locales, // ctype::widen, etc. (but that's what you deserve when you // don't separate concerns at the library level) // run_string_tests< Tests >( std::wstring( L"11111000000111111111010101010101010101010111111" ) ); #endif // Note that these are _valid_ arguments Tests::from_string( std::string( "x11y" ), 1, 2 ); Tests::from_string( std::string( "x11" ), 1, 10 ); Tests::from_string( std::string( "x11" ), 1, 10, 10 ); } //===================================================================== // test from_block_range { std::vector< Block > blocks; Tests::from_block_range( blocks ); } { std::vector< Block > blocks( 3 ); blocks[ 0 ] = static_cast< Block >( 0 ); blocks[ 1 ] = static_cast< Block >( 1 ); blocks[ 2 ] = all_1s; Tests::from_block_range( blocks ); } { const unsigned int n = ( std::numeric_limits< unsigned char >::max )(); std::vector< Block > blocks( n ); for ( typename std::vector< Block >::size_type i = 0; i < n; ++i ) blocks[ i ] = static_cast< Block >( i ); Tests::from_block_range( blocks ); } //===================================================================== // test iterators { bitset_type b; Tests::iterate_forward( b ); Tests::iterate_backward( b ); Tests::iterator_operations( b ); } { bitset_type b( 1, 1ul ); Tests::iterate_forward( b ); Tests::iterate_backward( b ); Tests::iterator_operations( b ); } { bitset_type b( bitset_type::bits_per_block, 100ul ); Tests::iterate_forward( b ); Tests::iterate_backward( b ); Tests::iterator_operations( b ); } { bitset_type b( long_string ); Tests::iterate_forward( b ); Tests::iterate_backward( b ); Tests::iterator_operations( b ); } //===================================================================== // test to_block_range { bitset_type b; Tests::to_block_range( b ); } { bitset_type b( 1, 1ul ); Tests::to_block_range( b ); } { bitset_type b( long_string ); Tests::to_block_range( b ); } //===================================================================== // Test copy constructor { bitset_type b; Tests::copy_constructor( b ); } { bitset_type b( "0" ); Tests::copy_constructor( b ); } { bitset_type b ( long_string ); Tests::copy_constructor( b ); } //===================================================================== // Test copy assignment operator { bitset_type a, b; Tests::copy_assignment_operator( a, b ); } { bitset_type a( "1" ), b( "0" ); Tests::copy_assignment_operator( a, b ); } { bitset_type a( long_string ), b( long_string ); Tests::copy_assignment_operator( a, b ); } { bitset_type a; bitset_type b( long_string ); // b greater than a, a empty Tests::copy_assignment_operator( a, b ); } { bitset_type a( "0" ); bitset_type b( long_string ); // b greater than a Tests::copy_assignment_operator( a, b ); } //===================================================================== // Test move constructor { bitset_type b; Tests::move_constructor( b ); } { bitset_type b( "0" ); Tests::move_constructor( b ); } { bitset_type b( long_string ); Tests::move_constructor( b ); } //===================================================================== // Test move assignment operator { bitset_type a, b; Tests::move_assignment_operator( a, b ); } { bitset_type a( "1" ), b( "0" ); Tests::move_assignment_operator( a, b ); } { bitset_type a( long_string ), b( long_string ); Tests::move_assignment_operator( a, b ); } { bitset_type a; bitset_type b( long_string ); // b greater than a, a empty Tests::move_assignment_operator( a, b ); } { bitset_type a( "0" ); bitset_type b( long_string ); // b greater than a Tests::move_assignment_operator( a, b ); } //===================================================================== // Test swap { bitset_type a; bitset_type b( "1" ); Tests::swap( a, b ); Tests::swap( b, a ); Tests::swap( a, a ); } { bitset_type a; bitset_type b( long_string ); Tests::swap( a, b ); Tests::swap( b, a ); } { bitset_type a( "0" ); bitset_type b( long_string ); Tests::swap( a, b ); Tests::swap( b, a ); Tests::swap( a, a ); Tests::swap( b, b ); } //===================================================================== // Test resize { bitset_type a; Tests::resize( a ); } { bitset_type a( "0" ); Tests::resize( a ); } { bitset_type a( "1" ); Tests::resize( a ); } { bitset_type a( long_string ); Tests::resize( a ); } //===================================================================== // Test clear { bitset_type a; Tests::clear( a ); } { bitset_type a( long_string ); Tests::clear( a ); } //===================================================================== // Test pop back { bitset_type a( "01" ); Tests::pop_back( a ); } { bitset_type a( "10" ); Tests::pop_back( a ); } { const int size_to_fill_all_blocks = 4 * bits_per_block; bitset_type a( size_to_fill_all_blocks, 255ul ); Tests::pop_back( a ); } { bitset_type a( long_string.c_str() ); Tests::pop_back( a ); } //===================================================================== // Test pop_front { bitset_type a( "01" ); Tests::pop_front( a ); } { bitset_type a( "10" ); Tests::pop_front( a ); } { const int size_to_fill_all_blocks = 4 * bits_per_block; bitset_type a( size_to_fill_all_blocks, 255ul ); Tests::pop_front( a ); } { bitset_type a( long_string.c_str() ); Tests::pop_front( a ); } //===================================================================== // Test append bit { bitset_type a; Tests::append_bit( a ); } { bitset_type a( "0" ); Tests::append_bit( a ); } { bitset_type a( "1" ); Tests::append_bit( a ); } { const int size_to_fill_all_blocks = 4 * bits_per_block; bitset_type a( size_to_fill_all_blocks, 255ul ); Tests::append_bit( a ); } { bitset_type a( long_string ); Tests::append_bit( a ); } //===================================================================== // Test push_front { bitset_type a; Tests::prepend_bit( a ); } { bitset_type a( "0" ); Tests::prepend_bit( a ); } { bitset_type a( "1" ); Tests::prepend_bit( a ); } { const int size_to_fill_all_blocks = 4 * bits_per_block; bitset_type a( size_to_fill_all_blocks, 255ul ); Tests::prepend_bit( a ); } { bitset_type a( long_string ); Tests::prepend_bit( a ); } //===================================================================== // Test append block { bitset_type a; Tests::append_block( a ); } { bitset_type a( "0" ); Tests::append_block( a ); } { bitset_type a( "1" ); Tests::append_block( a ); } { const int size_to_fill_all_blocks = 4 * bits_per_block; bitset_type a( size_to_fill_all_blocks, 15ul ); Tests::append_block( a ); } { bitset_type a( long_string.c_str() ); Tests::append_block( a ); } //===================================================================== // Test append block range { bitset_type a; std::vector< Block > blocks; Tests::append_block_range( a, blocks ); } { bitset_type a( "0" ); std::vector< Block > blocks( 3 ); blocks[ 0 ] = static_cast< Block >( 0 ); blocks[ 1 ] = static_cast< Block >( 1 ); blocks[ 2 ] = all_1s; Tests::append_block_range( a, blocks ); } { bitset_type a( "1" ); const unsigned int n = ( std::numeric_limits< unsigned char >::max )(); std::vector< Block > blocks( n ); for ( typename std::vector< Block >::size_type i = 0; i < n; ++i ) blocks[ i ] = static_cast< Block >( i ); Tests::append_block_range( a, blocks ); } { bitset_type a; a.append( Block( 1 ) ); a.append( Block( 2 ) ); Block x[] = { 3, 4, 5 }; std::size_t sz = sizeof( x ) / sizeof( x[ 0 ] ); std::vector< Block > blocks( x, x + sz ); Tests::append_block_range( a, blocks ); } { bitset_type a( long_string.c_str() ); std::vector< Block > blocks( 3 ); blocks[ 0 ] = static_cast< Block >( 0 ); blocks[ 1 ] = static_cast< Block >( 1 ); blocks[ 2 ] = all_1s; Tests::append_block_range( a, blocks ); } // Test with input iterators { bitset_type b; Tests::append_block_range_input_iter( b ); } { bitset_type b( "0" ); Tests::append_block_range_input_iter( b ); } { bitset_type b( long_string.c_str() ); Tests::append_block_range_input_iter( b ); } //===================================================================== // Test bracket operator { bitset_type b1; std::vector< bool > bitvec1; Tests::operator_bracket( b1, bitvec1 ); } { bitset_type b( "1" ); std::vector< bool > bit_vec( 1, true ); Tests::operator_bracket( b, bit_vec ); } { bitset_type b( long_string.c_str() ); std::size_t n = long_string.size(); std::vector< bool > bit_vec( n ); for ( std::size_t i = 0; i < n; ++i ) bit_vec[ i ] = long_string[ n - 1 - i ] == '0' ? 0 : 1; Tests::operator_bracket( b, bit_vec ); } //===================================================================== // Test at { bitset_type b1; std::vector< bool > bitvec1; Tests::at( b1, bitvec1 ); } { bitset_type b( "1" ); std::vector< bool > bit_vec( 1, true ); Tests::at( b, bit_vec ); } { bitset_type b( long_string.c_str() ); std::size_t n = long_string.size(); std::vector< bool > bit_vec( n ); for ( std::size_t i = 0; i < n; ++i ) bit_vec[ i ] = long_string[ n - 1 - i ] == '0' ? 0 : 1; Tests::at( b, bit_vec ); } //===================================================================== // Test max_size #if ! defined( BOOST_NO_CXX11_ALLOCATOR ) { typedef boost::dynamic_bitset< Block, minimal_allocator< Block > > Bitset; Bitset b; bitset_test< Bitset >::max_size( b ); } #endif { typedef boost::dynamic_bitset< Block, small_vector< Block > > Bitset; Bitset b; bitset_test< Bitset >::max_size( b ); } // Test copy-initialize with default constructor { bitset_type b[ 1 ] = {}; (void)b; } } int main() { run_test_cases< unsigned char >(); run_test_cases< unsigned char, small_vector< unsigned char > >(); run_test_cases< unsigned short >(); run_test_cases< unsigned short, small_vector< unsigned short > >(); run_test_cases< unsigned int >(); run_test_cases< unsigned int, small_vector< unsigned int > >(); run_test_cases< unsigned long >(); run_test_cases< unsigned long, small_vector< unsigned long > >(); run_test_cases< unsigned long long >(); run_test_cases< unsigned long long, small_vector< unsigned long long > >(); return boost::report_errors(); }