| 1 | // Copyright 2023 Matt Borland |
| 2 | // Copyright 2023 Peter Dimov |
| 3 | // Distributed under the Boost Software License, Version 1.0. |
| 4 | // https://www.boost.org/LICENSE_1_0.txt |
| 5 | |
| 6 | #include <boost/config.hpp> |
| 7 | |
| 8 | #ifdef BOOST_HAS_INT128 |
| 9 | |
| 10 | // We need to define these operator<< overloads before |
| 11 | // including boost/core/lightweight_test.hpp, or they |
| 12 | // won't be visible to BOOST_TEST_EQ |
| 13 | // LCOV_EXCL_START |
| 14 | |
| 15 | #include <ostream> |
| 16 | |
| 17 | static char* mini_to_chars( char (&buffer)[ 64 ], boost::uint128_type v ) |
| 18 | { |
| 19 | char* p = buffer + 64; |
| 20 | *--p = '\0'; |
| 21 | |
| 22 | do |
| 23 | { |
| 24 | *--p = "0123456789" [ v % 10 ]; |
| 25 | v /= 10; |
| 26 | } |
| 27 | while ( v != 0 ); |
| 28 | |
| 29 | return p; |
| 30 | } |
| 31 | |
| 32 | std::ostream& operator<<( std::ostream& os, boost::uint128_type v ) |
| 33 | { |
| 34 | char buffer[ 64 ]; |
| 35 | |
| 36 | os << mini_to_chars( buffer, v ); |
| 37 | return os; |
| 38 | } |
| 39 | |
| 40 | std::ostream& operator<<( std::ostream& os, boost::int128_type v ) |
| 41 | { |
| 42 | char buffer[ 64 ]; |
| 43 | char* p; |
| 44 | |
| 45 | if( v >= 0 ) |
| 46 | { |
| 47 | p = mini_to_chars( buffer, v: static_cast<boost::uint128_type>(v) ); |
| 48 | } |
| 49 | else |
| 50 | { |
| 51 | p = mini_to_chars( buffer, v: -static_cast<boost::uint128_type>(v) ); |
| 52 | *--p = '-'; |
| 53 | } |
| 54 | |
| 55 | os << p; |
| 56 | return os; |
| 57 | } |
| 58 | |
| 59 | // LCOV_EXCL_STOP |
| 60 | |
| 61 | #endif // #ifdef BOOST_HAS_INT128 |
| 62 | |
| 63 | #include <boost/charconv/limits.hpp> |
| 64 | #include <boost/charconv/to_chars.hpp> |
| 65 | #include <boost/charconv/from_chars.hpp> |
| 66 | #include <boost/core/lightweight_test.hpp> |
| 67 | #include <system_error> |
| 68 | #include <limits> |
| 69 | #include <string> |
| 70 | |
| 71 | void test_odr_use( int const* ); |
| 72 | |
| 73 | template<typename T> void test_integral( T value ) |
| 74 | { |
| 75 | // no base |
| 76 | { |
| 77 | char buffer[ boost::charconv::limits<T>::max_chars10 ]; |
| 78 | auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value ); |
| 79 | BOOST_TEST(r.ec == std::errc()); |
| 80 | |
| 81 | T v2 = 0; |
| 82 | auto r2 = boost::charconv::from_chars( buffer, r.ptr, v2 ); |
| 83 | |
| 84 | if( BOOST_TEST( r2.ec == std::errc() ) && BOOST_TEST( v2 == value ) ) |
| 85 | { |
| 86 | } |
| 87 | else |
| 88 | { |
| 89 | std::cerr << "... test failure for value=" << value << "; buffer='" << std::string( buffer, r.ptr ) << "'" << std::endl; // LCOV_EXCL_LINE |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | // base 10 |
| 94 | { |
| 95 | char buffer[ boost::charconv::limits<T>::max_chars10 ]; |
| 96 | auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value, 10 ); |
| 97 | BOOST_TEST(r.ec == std::errc()); |
| 98 | |
| 99 | T v2 = 0; |
| 100 | auto r2 = boost::charconv::from_chars( buffer, r.ptr, v2, 10 ); |
| 101 | |
| 102 | if( BOOST_TEST( r2.ec == std::errc() ) && BOOST_TEST( v2 == value ) ) |
| 103 | { |
| 104 | } |
| 105 | else |
| 106 | { |
| 107 | std::cerr << "... test failure for value=" << value << "; buffer='" << std::string( buffer, r.ptr ) << "'" << std::endl; // LCOV_EXCL_LINE |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | // any base |
| 112 | for( int base = 2; base <= 36; ++base ) |
| 113 | { |
| 114 | char buffer[ boost::charconv::limits<T>::max_chars ]; |
| 115 | auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value, base ); |
| 116 | BOOST_TEST(r.ec == std::errc()); |
| 117 | |
| 118 | T v2 = 0; |
| 119 | auto r2 = boost::charconv::from_chars( buffer, r.ptr, v2, base ); |
| 120 | |
| 121 | if( BOOST_TEST( r2.ec == std::errc() ) && BOOST_TEST( v2 == value ) ) |
| 122 | { |
| 123 | } |
| 124 | else |
| 125 | { |
| 126 | std::cerr << "... test failure for value=" << value << "; buffer='" << std::string( buffer, r.ptr ) << "'" << std::endl; // LCOV_EXCL_LINE |
| 127 | } |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | template<typename T> void test_integral() |
| 132 | { |
| 133 | BOOST_TEST_GE( boost::charconv::limits<T>::max_chars10, std::numeric_limits<T>::digits10 ); |
| 134 | BOOST_TEST_GE( boost::charconv::limits<T>::max_chars, std::numeric_limits<T>::digits ); |
| 135 | |
| 136 | test_odr_use( &boost::charconv::limits<T>::max_chars10 ); |
| 137 | test_odr_use( &boost::charconv::limits<T>::max_chars ); |
| 138 | |
| 139 | test_integral( std::numeric_limits<T>::min() ); |
| 140 | test_integral( std::numeric_limits<T>::max() ); |
| 141 | } |
| 142 | |
| 143 | template<typename T> void test_floating_point( T value ) |
| 144 | { |
| 145 | // no base, max_chars10 |
| 146 | { |
| 147 | char buffer[ boost::charconv::limits<T>::max_chars10 ]; |
| 148 | auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value ); |
| 149 | if (!BOOST_TEST(r.ec == std::errc())) |
| 150 | { |
| 151 | // LCOV_EXCL_START |
| 152 | std::cerr << " Value: " << value |
| 153 | << "\nBuffer: " << std::string(buffer) |
| 154 | << "\n Ec: " << static_cast<int>(r.ec) << std::endl; |
| 155 | // LCOV_EXCL_STOP |
| 156 | } |
| 157 | |
| 158 | T v2 = 0; |
| 159 | auto r2 = boost::charconv::from_chars( buffer, r.ptr, v2 ); |
| 160 | |
| 161 | if (!BOOST_TEST(r2.ec == std::errc()) && BOOST_TEST_EQ( v2, value )) |
| 162 | { |
| 163 | // LCOV_EXCL_START |
| 164 | std::cerr << " Value: " << value |
| 165 | << "\nBuffer: " << std::string(buffer) |
| 166 | << "\nRetVal: " << v2 |
| 167 | << "\n Ec: " << static_cast<int>(r2.ec) << std::endl; |
| 168 | // LCOV_EXCL_STOP |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | // no base, max_chars |
| 173 | { |
| 174 | char buffer[ boost::charconv::limits<T>::max_chars ]; |
| 175 | auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value ); |
| 176 | if (!BOOST_TEST(r.ec == std::errc())) |
| 177 | { |
| 178 | // LCOV_EXCL_START |
| 179 | std::cerr << " Value: " << value |
| 180 | << "\nBuffer: " << std::string(buffer) |
| 181 | << "\n Ec: " << static_cast<int>(r.ec) << std::endl; |
| 182 | // LCOV_EXCL_STOP |
| 183 | } |
| 184 | |
| 185 | T v2 = 0; |
| 186 | auto r2 = boost::charconv::from_chars( buffer, r.ptr, v2 ); |
| 187 | |
| 188 | if (!BOOST_TEST(r2.ec == std::errc()) && BOOST_TEST_EQ( v2, value )) |
| 189 | { |
| 190 | // LCOV_EXCL_START |
| 191 | std::cerr << " Value: " << value |
| 192 | << "\nBuffer: " << std::string(buffer) |
| 193 | << "\nRetVal: " << v2 |
| 194 | << "\n Ec: " << static_cast<int>(r2.ec) << std::endl; |
| 195 | // LCOV_EXCL_STOP |
| 196 | } |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | template<typename T> void test_floating_point() |
| 201 | { |
| 202 | BOOST_TEST_GE( boost::charconv::limits<T>::max_chars10, std::numeric_limits<T>::max_digits10 ); |
| 203 | BOOST_TEST_GE( boost::charconv::limits<T>::max_chars, std::numeric_limits<T>::max_digits10 ); |
| 204 | |
| 205 | test_odr_use( &boost::charconv::limits<T>::max_chars10 ); |
| 206 | test_odr_use( &boost::charconv::limits<T>::max_chars ); |
| 207 | |
| 208 | test_floating_point( std::numeric_limits<T>::min() ); |
| 209 | test_floating_point( -std::numeric_limits<T>::min() ); |
| 210 | test_floating_point( std::numeric_limits<T>::max() ); |
| 211 | test_floating_point( -std::numeric_limits<T>::max() ); |
| 212 | } |
| 213 | |
| 214 | int main() |
| 215 | { |
| 216 | test_integral<char>(); |
| 217 | test_integral<signed char>(); |
| 218 | test_integral<unsigned char>(); |
| 219 | test_integral<short>(); |
| 220 | test_integral<unsigned short>(); |
| 221 | test_integral<int>(); |
| 222 | test_integral<unsigned>(); |
| 223 | test_integral<long>(); |
| 224 | test_integral<unsigned long>(); |
| 225 | test_integral<long long>(); |
| 226 | test_integral<unsigned long long>(); |
| 227 | |
| 228 | test_floating_point<float>(); |
| 229 | test_floating_point<double>(); |
| 230 | test_floating_point<long double>(); |
| 231 | |
| 232 | #ifdef BOOST_CHARCONV_HAS_INT128 |
| 233 | |
| 234 | test_integral<boost::int128_type>(); |
| 235 | test_integral<boost::uint128_type>(); |
| 236 | |
| 237 | #endif |
| 238 | |
| 239 | return boost::report_errors(); |
| 240 | } |
| 241 | |
| 242 | void test_odr_use( int const* ) |
| 243 | { |
| 244 | } |
| 245 | |