// Copyright 2023 Peter Dimov // Copyright 2023 Matt Borland // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #include #include #include #include #include #include #include #include #include #include #include #include constexpr unsigned N = 2'000'000; constexpr int K = 10; template static BOOST_NOINLINE void init_input_data( std::vector& data, bool general ) { data.reserve( N ); boost::detail::splitmix64 rng; for( unsigned i = 0; i < N; ++i ) { std::uint64_t tmp = rng(); T x; std::memcpy( &x, &tmp, sizeof(x) ); if( !std::isfinite(x) ) continue; char buffer[ 64 ]; auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), x, general? boost::charconv::chars_format::general: boost::charconv::chars_format::scientific ); std::string y( buffer, r.ptr ); data.push_back( y ); } } template <> BOOST_NOINLINE void init_input_data( std::vector& data, bool general ) { data.reserve(N / 10); std::random_device rd; std::mt19937_64 rng(rd()); std::uniform_real_distribution dist(0.0L, (std::numeric_limits::max)()); for( unsigned i = 0; i < N / 10; ++i ) { const long double x = dist(rng); char buffer[ 64 ]; auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), x, general? boost::charconv::chars_format::general : boost::charconv::chars_format::scientific ); std::string y( buffer, r.ptr ); data.push_back( y ); } } template static BOOST_NOINLINE void init_input_data_uint64( std::vector& data ) { data.reserve( N ); boost::detail::splitmix64 rng; for( unsigned i = 0; i < N; ++i ) { std::uint64_t x = rng(); char buffer[ 64 ]; auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), x ); std::string y( buffer, r.ptr ); data.push_back( y ); } } using namespace std::chrono_literals; template void test_strtox( std::vector const& data, bool general, char const* label ); template<> BOOST_NOINLINE void test_strtox( std::vector const& data, bool, char const* label ) { auto t1 = std::chrono::steady_clock::now(); double s = 0; for( int i = 0; i < K; ++i ) { for( auto const& x: data ) { float y = std::strtof( x.c_str(), nullptr ); s = s / 16.0 + y; } } auto t2 = std::chrono::steady_clock::now(); std::cout << " std::strtox, " << label << ": " << std::setw( 5 ) << ( t2 - t1 ) / 1ms << " ms (s=" << s << ")\n"; } template<> BOOST_NOINLINE void test_strtox( std::vector const& data, bool, char const* label ) { auto t1 = std::chrono::steady_clock::now(); double s = 0; for( int i = 0; i < K; ++i ) { for( auto const& x: data ) { double y = std::strtod( x.c_str(), nullptr ); s = s / 16.0 + y; } } auto t2 = std::chrono::steady_clock::now(); std::cout << " std::strtox, " << label << ": " << std::setw( 5 ) << ( t2 - t1 ) / 1ms << " ms (s=" << s << ")\n"; } template<> BOOST_NOINLINE void test_strtox( std::vector const& data, bool, char const* label ) { auto t1 = std::chrono::steady_clock::now(); long double s = 0; for( int i = 0; i < K; ++i ) { for( auto const& x: data ) { double y = std::strtold( x.c_str(), nullptr ); s = s / 16.0L + y; } } auto t2 = std::chrono::steady_clock::now(); std::cout << " std::strtox, " << label << ": " << std::setw( 5 ) << ( t2 - t1 ) / 1ms << " ms (s=" << s << ")\n"; } template static BOOST_NOINLINE void test_std_from_chars( std::vector const& data, bool general, char const* label ) { auto t1 = std::chrono::steady_clock::now(); double s = 0; for( int i = 0; i < K; ++i ) { for( auto const& x: data ) { T y; std::from_chars( x.data(), x.data() + x.size(), y, general? std::chars_format::general: std::chars_format::scientific ); s = s / 16.0 + y; } } auto t2 = std::chrono::steady_clock::now(); std::cout << " std::from_chars<" << boost::core::type_name() << ">, " << label << ": " << std::setw( 5 ) << ( t2 - t1 ) / 1ms << " ms (s=" << s << ")\n"; } template<> BOOST_NOINLINE void test_std_from_chars( std::vector const& data, bool general, char const* label ) { auto t1 = std::chrono::steady_clock::now(); long double s = 0; for( int i = 0; i < K; ++i ) { for( auto const& x: data ) { long double y; std::from_chars( x.data(), x.data() + x.size(), y, general? std::chars_format::general: std::chars_format::scientific ); s = s / 16.0L + y; } } auto t2 = std::chrono::steady_clock::now(); std::cout << " std::from_chars, " << label << ": " << std::setw( 5 ) << ( t2 - t1 ) / 1ms << " ms (s=" << s << ")\n"; } template static BOOST_NOINLINE void test_boost_from_chars( std::vector const& data, bool general, char const* label ) { auto t1 = std::chrono::steady_clock::now(); double s = 0; for( int i = 0; i < K; ++i ) { for( auto const& x: data ) { T y; boost::charconv::from_chars( x.data(), x.data() + x.size(), y, general? boost::charconv::chars_format::general: boost::charconv::chars_format::scientific ); s = s / 16.0 + y; } } auto t2 = std::chrono::steady_clock::now(); std::cout << "boost::charconv::from_chars<" << boost::core::type_name() << ">, " << label << ": " << std::setw( 5 ) << ( t2 - t1 ) / 1ms << " ms (s=" << s << ")\n"; } template<> BOOST_NOINLINE void test_boost_from_chars( std::vector const& data, bool general, char const* label ) { auto t1 = std::chrono::steady_clock::now(); long double s = 0; for( int i = 0; i < K; ++i ) { for( auto const& x: data ) { long double y; boost::charconv::from_chars( x.data(), x.data() + x.size(), y, general? boost::charconv::chars_format::general: boost::charconv::chars_format::scientific ); s = s / 16.0L + y; } } auto t2 = std::chrono::steady_clock::now(); std::cout << "boost::charconv::from_chars, " << label << ": " << std::setw( 5 ) << ( t2 - t1 ) / 1ms << " ms (s=" << s << ")\n"; } template static void test( bool general ) { std::vector data; init_input_data( data, general ); char const* label = general? "general": "scientific"; test_strtox( data, general, label ); test_std_from_chars( data, general, label ); test_boost_from_chars( data, general, label ); std::cout << std::endl; } template static void test2() { std::vector data; init_input_data_uint64( data ); bool general = true; char const* label = "uint64"; test_strtox( data, general, label ); test_std_from_chars( data, general, label ); test_boost_from_chars( data, general, label ); std::cout << std::endl; } int main() { std::cout << BOOST_COMPILER << "\n"; std::cout << BOOST_STDLIB << "\n\n"; test( false ); test( false ); test( false ); test( true ); test( true ); test( true ); test2(); test2(); }