// Copyright 2022 Peter Dimov // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #include #ifdef BOOST_HAS_INT128 // We need to define these operator<< overloads before // including boost/core/lightweight_test.hpp, or they // won't be visible to BOOST_TEST_EQ #include static char* mini_to_chars( char (&buffer)[ 64 ], boost::uint128_type v ) { char* p = buffer + 64; *--p = '\0'; do { *--p = "0123456789"[ v % 10 ]; v /= 10; } while ( v != 0 ); return p; } std::ostream& operator<<( std::ostream& os, boost::uint128_type v ) { char buffer[ 64 ]; os << mini_to_chars( buffer, v ); return os; } std::ostream& operator<<( std::ostream& os, boost::int128_type v ) { char buffer[ 64 ]; char* p; if( v >= 0 ) { p = mini_to_chars( buffer, v ); } else { p = mini_to_chars( buffer, -(boost::uint128_type)v ); *--p = '-'; } os << p; return os; } #endif // #ifdef BOOST_HAS_INT128 #include #include #include #include #include #include #include #include int const N = 1024; static boost::detail::splitmix64 rng; // integral types, random values template void test_roundtrip( T value, int base ) { char buffer[ 256 ]; auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value, base ); BOOST_TEST_EQ( r.ec, 0 ); T v2 = 0; auto r2 = boost::charconv::from_chars( buffer, r.ptr, v2, base ); if( BOOST_TEST_EQ( r2.ec, 0 ) && BOOST_TEST_EQ( v2, value ) ) { } else { std::cerr << "... test failure for value=" << value << "; buffer='" << std::string( buffer, r.ptr ) << "'" << std::endl; } } template void test_roundtrip_int8( int base ) { for( int i = -256; i <= 255; ++i ) { test_roundtrip( static_cast( i ), base ); } } template void test_roundtrip_uint8( int base ) { for( int i = 0; i <= 256; ++i ) { test_roundtrip( static_cast( i ), base ); } } template void test_roundtrip_int16( int base ) { test_roundtrip_int8( base ); for( int i = 0; i < N; ++i ) { std::int16_t w = static_cast( rng() ); test_roundtrip( static_cast( w ), base ); } } template void test_roundtrip_uint16( int base ) { test_roundtrip_uint8( base ); for( int i = 0; i < N; ++i ) { std::uint16_t w = static_cast( rng() ); test_roundtrip( static_cast( w ), base ); } } template void test_roundtrip_int32( int base ) { test_roundtrip_int16( base ); for( int i = 0; i < N; ++i ) { std::int32_t w = static_cast( rng() ); test_roundtrip( static_cast( w ), base ); } } template void test_roundtrip_uint32( int base ) { test_roundtrip_uint16( base ); for( int i = 0; i < N; ++i ) { std::uint32_t w = static_cast( rng() ); test_roundtrip( static_cast( w ), base ); } } template void test_roundtrip_int64( int base ) { test_roundtrip_int32( base ); for( int i = 0; i < N; ++i ) { std::int64_t w = static_cast( rng() ); test_roundtrip( static_cast( w ), base ); } } template void test_roundtrip_uint64( int base ) { test_roundtrip_uint32( base ); for( int i = 0; i < N; ++i ) { std::uint64_t w = static_cast( rng() ); test_roundtrip( static_cast( w ), base ); } } #ifdef BOOST_CHARCONV_HAS_INT128 inline boost::uint128_type concatenate(std::uint64_t word1, std::uint64_t word2) { return static_cast(word1) << 64 | word2; } template void test_roundtrip_int128( int base ) { for( int i = 0; i < N; ++i ) { boost::int128_type w = static_cast( concatenate(rng(), rng()) ); test_roundtrip( static_cast( w ), base ); } } template void test_roundtrip_uint128( int base ) { for( int i = 0; i < N; ++i ) { boost::uint128_type w = static_cast( concatenate(rng(), rng()) ); test_roundtrip( static_cast( w ), base ); } } #endif // #ifdef BOOST_CHARCONV_HAS_INT128 // integral types, boundary values template void test_roundtrip_bv( int base ) { test_roundtrip( std::numeric_limits::min(), base ); test_roundtrip( std::numeric_limits::max(), base ); } // floating point types, random values template void test_roundtrip( T value ) { char buffer[ 256 ]; auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value ); BOOST_TEST_EQ( r.ec, 0 ); T v2 = 0; auto r2 = boost::charconv::from_chars( buffer, r.ptr, v2 ); if( BOOST_TEST_EQ( r2.ec, 0 ) && BOOST_TEST_EQ( v2, value ) ) { } else { std::cerr << "... test failure for value=" << value << "; buffer='" << std::string( buffer, r.ptr ) << "'" << std::endl; } } // floating point types, boundary values template void test_roundtrip_bv() { test_roundtrip( std::numeric_limits::min() ); test_roundtrip( -std::numeric_limits::min() ); test_roundtrip( std::numeric_limits::max() ); test_roundtrip( +std::numeric_limits::max() ); } // int main() { // integral types, random values for( int base = 2; base <= 36; ++base ) { test_roundtrip_int8( base ); test_roundtrip_uint8( base ); test_roundtrip_int16( base ); test_roundtrip_uint16( base ); test_roundtrip_int32( base ); test_roundtrip_uint32( base ); test_roundtrip_int64( base ); test_roundtrip_uint64( base ); #ifdef BOOST_CHARCONV_HAS_INT128 test_roundtrip_int128( base ); test_roundtrip_uint128( base ); #endif } // integral types, boundary values for( int base = 2; base <= 36; ++base ) { test_roundtrip_bv( base ); test_roundtrip_bv( base ); test_roundtrip_bv( base ); test_roundtrip_bv( base ); test_roundtrip_bv( base ); test_roundtrip_bv( base ); test_roundtrip_bv( base ); test_roundtrip_bv( base ); test_roundtrip_bv( base ); test_roundtrip_bv( base ); test_roundtrip_bv( base ); #ifdef BOOST_CHARCONV_HAS_INT128 test_roundtrip_bv( base ); test_roundtrip_bv( base ); #endif } #if !defined(__CYGWIN__) // the stub implementations fail under Cygwin; // re-enable these when we have real ones // float double const q = std::pow( 1.0, -64 ); { for( int i = 0; i < N; ++i ) { float w0 = static_cast( rng() ); // 0 .. 2^64 test_roundtrip( w0 ); float w1 = static_cast( rng() * q ); // 0.0 .. 1.0 test_roundtrip( w1 ); float w2 = FLT_MAX / static_cast( rng() ); // large values test_roundtrip( w2 ); float w3 = FLT_MIN * static_cast( rng() ); // small values test_roundtrip( w3 ); } test_roundtrip_bv(); } // double { for( int i = 0; i < N; ++i ) { double w0 = rng() * 1.0; // 0 .. 2^64 test_roundtrip( w0 ); double w1 = rng() * q; // 0.0 .. 1.0 test_roundtrip( w1 ); double w2 = DBL_MAX / rng(); // large values test_roundtrip( w2 ); double w3 = DBL_MIN * rng(); // small values test_roundtrip( w3 ); } test_roundtrip_bv(); } // long double { long double const ql = std::pow( 1.0L, -64 ); for( int i = 0; i < N; ++i ) { long double w0 = rng() * 1.0L; // 0 .. 2^64 test_roundtrip( w0 ); long double w1 = rng() * ql; // 0.0 .. 1.0 test_roundtrip( w1 ); long double w2 = LDBL_MAX / rng(); // large values test_roundtrip( w2 ); long double w3 = LDBL_MIN * rng(); // small values test_roundtrip( w3 ); } test_roundtrip_bv(); } #endif // !defined(__CYGWIN__) return boost::report_errors(); }