Files
dynamic_bitset/test/dyn_bitset_unit_tests1.cpp
2025-10-14 19:24:45 +02:00

552 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/config/workaround.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 ] ) )
// Codewarrior 8.3 for Win fails without this.
// Thanks Howard Hinnant ;)
#if defined __MWERKS__ && BOOST_WORKAROUND( __MWERKS__, <= 0x3003 ) // 8.x
# pragma parse_func_templ off
#endif
template< typename Tests, typename String >
void
run_string_tests( const String & s BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE( Tests ) )
{
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( BOOST_EXPLICIT_TEMPLATE_TYPE( Tests )
BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE( T ) )
{
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 >
void
run_test_cases( BOOST_EXPLICIT_TEMPLATE_TYPE( Block ) )
{
typedef boost::dynamic_bitset< Block > 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 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
{
boost::dynamic_bitset< Block > b;
Tests::copy_constructor( b );
}
{
boost::dynamic_bitset< Block > b( std::string( "0" ) );
Tests::copy_constructor( b );
}
{
boost::dynamic_bitset< Block > b( long_string );
Tests::copy_constructor( b );
}
//=====================================================================
// Test copy assignment operator
{
bitset_type a, b;
Tests::copy_assignment_operator( a, b );
}
{
bitset_type a( std::string( "1" ) ), b( std::string( "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( std::string( "0" ) );
bitset_type b( long_string ); // b greater than a
Tests::copy_assignment_operator( a, b );
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
//=====================================================================
// Test move constructor
{
boost::dynamic_bitset< Block > b;
Tests::move_constructor( b );
}
{
boost::dynamic_bitset< Block > b( std::string( "0" ) );
Tests::move_constructor( b );
}
{
boost::dynamic_bitset< Block > b( long_string );
Tests::move_constructor( b );
}
//=====================================================================
// Test move assignment operator
{
bitset_type a, b;
Tests::move_assignment_operator( a, b );
}
{
bitset_type a( std::string( "1" ) ), b( std::string( "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( std::string( "0" ) );
bitset_type b( long_string ); // b greater than a
Tests::move_assignment_operator( a, b );
}
#endif // BOOST_NO_CXX11_RVALUE_REFERENCES
//=====================================================================
// Test swap
{
bitset_type a;
bitset_type b( std::string( "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( std::string( "0" ) );
bitset_type b( long_string );
Tests::swap( a, b );
Tests::swap( b, a );
Tests::swap( a, a );
Tests::swap( b, b );
}
//=====================================================================
// Test resize
{
boost::dynamic_bitset< Block > a;
Tests::resize( a );
}
{
boost::dynamic_bitset< Block > a( std::string( "0" ) );
Tests::resize( a );
}
{
boost::dynamic_bitset< Block > a( std::string( "1" ) );
Tests::resize( a );
}
{
boost::dynamic_bitset< Block > a( long_string );
Tests::resize( a );
}
//=====================================================================
// Test clear
{
boost::dynamic_bitset< Block > a;
Tests::clear( a );
}
{
boost::dynamic_bitset< Block > a( long_string );
Tests::clear( a );
}
//=====================================================================
// Test pop back
{
boost::dynamic_bitset< Block > a( std::string( "01" ) );
Tests::pop_back( a );
}
{
boost::dynamic_bitset< Block > a( std::string( "10" ) );
Tests::pop_back( a );
}
{
const int size_to_fill_all_blocks = 4 * bits_per_block;
boost::dynamic_bitset< Block > a( size_to_fill_all_blocks, 255ul );
Tests::pop_back( a );
}
{
boost::dynamic_bitset< Block > a( long_string );
Tests::pop_back( a );
}
//=====================================================================
// Test append bit
{
boost::dynamic_bitset< Block > a;
Tests::append_bit( a );
}
{
boost::dynamic_bitset< Block > a( std::string( "0" ) );
Tests::append_bit( a );
}
{
boost::dynamic_bitset< Block > a( std::string( "1" ) );
Tests::append_bit( a );
}
{
const int size_to_fill_all_blocks = 4 * bits_per_block;
boost::dynamic_bitset< Block > a( size_to_fill_all_blocks, 255ul );
Tests::append_bit( a );
}
{
boost::dynamic_bitset< Block > a( long_string );
Tests::append_bit( a );
}
//=====================================================================
// Test append block
{
boost::dynamic_bitset< Block > a;
Tests::append_block( a );
}
{
boost::dynamic_bitset< Block > a( std::string( "0" ) );
Tests::append_block( a );
}
{
boost::dynamic_bitset< Block > a( std::string( "1" ) );
Tests::append_block( a );
}
{
const int size_to_fill_all_blocks = 4 * bits_per_block;
boost::dynamic_bitset< Block > a( size_to_fill_all_blocks, 15ul );
Tests::append_block( a );
}
{
boost::dynamic_bitset< Block > a( long_string );
Tests::append_block( a );
}
//=====================================================================
// Test append block range
{
boost::dynamic_bitset< Block > a;
std::vector< Block > blocks;
Tests::append_block_range( a, blocks );
}
{
boost::dynamic_bitset< Block > a( std::string( "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 );
}
{
boost::dynamic_bitset< Block > a( std::string( "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 );
}
{
boost::dynamic_bitset< Block > 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 );
}
{
boost::dynamic_bitset< Block > a( long_string );
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
{
boost::dynamic_bitset< Block > b1;
std::vector< bool > bitvec1;
Tests::operator_bracket( b1, bitvec1 );
}
{
boost::dynamic_bitset< Block > b( std::string( "1" ) );
std::vector< bool > bit_vec( 1, true );
Tests::operator_bracket( b, bit_vec );
}
{
boost::dynamic_bitset< Block > b( long_string );
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
{
boost::dynamic_bitset< Block > b1;
std::vector< bool > bitvec1;
Tests::at( b1, bitvec1 );
}
{
boost::dynamic_bitset< Block > b( std::string( "1" ) );
std::vector< bool > bit_vec( 1, true );
Tests::at( b, bit_vec );
}
{
boost::dynamic_bitset< Block > b( long_string );
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
{
boost::dynamic_bitset< Block > b[ 1 ] = {};
(void)b;
}
}
int
main()
{
run_test_cases< unsigned char >();
run_test_cases< unsigned short >();
run_test_cases< unsigned int >();
run_test_cases< unsigned long >();
#ifdef BOOST_HAS_LONG_LONG
run_test_cases< ::boost::ulong_long_type >();
#endif
return boost::report_errors();
}