Files
dynamic_bitset/test/dyn_bitset_unit_tests1.cpp
Gennaro Prota efd4d41f60 No longer use BOOST_NO_CXX11_RVALUE_REFERENCES
Reason: We require decent C++11 support anyway.
2025-10-15 11:41:43 +02:00

576 lines
18 KiB
C++

// -----------------------------------------------------------
// 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 <cstdlib>
template< class 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, unsigned char >();
run_numeric_ctor_tests< Tests, unsigned short >();
run_numeric_ctor_tests< Tests, unsigned int >();
run_numeric_ctor_tests< Tests, unsigned long >();
#if defined( BOOST_HAS_LONG_LONG )
run_numeric_ctor_tests< Tests, ::boost::long_long_type >();
run_numeric_ctor_tests< Tests, ::boost::ulong_long_type >();
#endif
}
//=====================================================================
// 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 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 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 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 );
}
#if ! defined( BOOST_NO_CXX11_ALLOCATOR )
{
typedef boost::dynamic_bitset< Block, minimal_allocator< Block > > Bitset;
Bitset b;
bitset_test< Bitset >::max_size( b );
}
#endif
// 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 > >();
#ifdef BOOST_HAS_LONG_LONG
run_test_cases< ::boost::ulong_long_type >();
run_test_cases< ::boost::ulong_long_type, small_vector< ::boost::ulong_long_type > >();
#endif
return boost::report_errors();
}