From a1a03ebf6c687692820a667e3c60ace84a930c2a Mon Sep 17 00:00:00 2001 From: Christopher Kormanyos Date: Mon, 22 Jan 2024 15:10:37 +0100 Subject: [PATCH 1/5] Implement and test from_chars() --- math/wide_integer/uintwide_t.h | 143 +++++++++++++++++++++++----- test/test.cpp | 5 +- test/test_uintwide_t_edge_cases.cpp | 141 ++++++++++++++++++++++++++- 3 files changed, 258 insertions(+), 31 deletions(-) diff --git a/math/wide_integer/uintwide_t.h b/math/wide_integer/uintwide_t.h index 78e2863..efb14c2 100644 --- a/math/wide_integer/uintwide_t.h +++ b/math/wide_integer/uintwide_t.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 1999 - 2023. // +// Copyright Christopher Kormanyos 1999 - 2024. // // 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) // @@ -1617,10 +1617,21 @@ typename LimbType, typename AllocatorType, const bool IsSigned> + WIDE_INTEGER_CONSTEXPR auto to_chars(char* first, char* last, const uintwide_t& x, int base = static_cast(INT8_C(10))) -> std::to_chars_result; + + template + WIDE_INTEGER_CONSTEXPR + auto from_chars(const char* first, + const char* last, + uintwide_t& x, + int base = static_cast(INT8_C(10))) -> std::from_chars_result; #endif #if !defined(WIDE_INTEGER_DISABLE_TO_STRING) @@ -2454,7 +2465,7 @@ typename representation_type::allocator_type() } { - if(!rd_string(str_input)) + if(!rd_string(str_input, (std::numeric_limits::max)(), 0)) { static_cast(operator=((std::numeric_limits::max)())); } @@ -3549,6 +3560,28 @@ #endif friend auto ::test_uintwide_t_edge::test_various_isolated_edge_cases() -> bool; + template + friend WIDE_INTEGER_CONSTEXPR auto divmod(const uintwide_t& a, // NOLINT(readability-redundant-declaration) + const uintwide_t& b, + std::enable_if_t<((!OtherIsSignedLeft) && (!OtherIsSignedRight)), int>* p_nullparam) -> std::pair, uintwide_t>; + + #if (defined(__cpp_lib_to_chars) && (__cpp_lib_to_chars >= 201611L)) + template + friend + WIDE_INTEGER_CONSTEXPR + auto from_chars(const char* first, + const char* last, + uintwide_t& x, + int base) -> std::from_chars_result; + #endif + template bool // NOLINT(readability-function-cognitive-complexity) + WIDE_INTEGER_CONSTEXPR auto rd_string(const char* str_input, const unsigned_fast_type count, const int base_hint) -> bool // NOLINT(readability-function-cognitive-complexity,bugprone-easily-swappable-parameters) { detail::fill_unsafe(values.begin(), values.end(), static_cast(UINT8_C(0))); - const auto str_length = detail::strlen_unsafe(str_input); - - auto base = static_cast(UINT8_C(10)); + const auto str_length = + static_cast + ( + (count == (std::numeric_limits::max)()) ? detail::strlen_unsafe(str_input) : count + ); auto pos = static_cast(UINT8_C(0)); @@ -5359,33 +5394,45 @@ ++pos; } - // Perform a dynamic detection of the base. - if(str_length > static_cast(static_cast(pos) + static_cast(UINT8_C(0)))) + std::uint_fast8_t base { }; + + if(base_hint == 0) { - const auto might_be_oct_or_hex = ((str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(0)))] == '0') && (str_length > static_cast(static_cast(pos) + static_cast(UINT8_C(0))))); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + base = static_cast(UINT8_C(10)); - if(might_be_oct_or_hex) + // Perform a dynamic detection of the base. + if(str_length > static_cast(static_cast(pos) + static_cast(UINT8_C(0)))) { - if((str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(1)))] >= '0') && (str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(1)))] <= '8')) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + const auto might_be_oct_or_hex = ((str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(0)))] == '0') && (str_length > static_cast(static_cast(pos) + static_cast(UINT8_C(0))))); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + + if(might_be_oct_or_hex) { - // The input format is octal. - base = static_cast(UINT8_C(8)); + if((str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(1)))] >= '0') && (str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(1)))] <= '8')) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + { + // The input format is octal. + base = static_cast(UINT8_C(8)); + + pos = static_cast(static_cast(pos) + static_cast(UINT8_C(1))); + } + else if((str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(1)))] == 'x') || (str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(1)))] == 'X')) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + { + // The input format is hexadecimal. + base = static_cast(UINT8_C(16)); - pos = static_cast(static_cast(pos) + static_cast(UINT8_C(1))); + pos = static_cast(static_cast(pos) + static_cast(UINT8_C(2))); + } } - else if((str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(1)))] == 'x') || (str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(1)))] == 'X')) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + else if((str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(0)))] >= '0') && (str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(0)))] <= '9')) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) { - // The input format is hexadecimal. - base = static_cast(UINT8_C(16)); - - pos = static_cast(static_cast(pos) + static_cast(UINT8_C(2))); + // The input format is decimal. + ; } } - else if((str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(0)))] >= '0') && (str_input[static_cast(static_cast(pos) + static_cast(UINT8_C(0)))] <= '9')) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) - { - // The input format is decimal. - ; - } + } + else + { + // Set the base if the client has supplied a non-zero base-hint. + base = static_cast(base_hint); } auto char_is_valid = true; @@ -7283,6 +7330,7 @@ typename LimbType, typename AllocatorType, const bool IsSigned> + WIDE_INTEGER_CONSTEXPR auto to_chars(char* first, char* last, const uintwide_t& x, @@ -7441,6 +7489,53 @@ return result; } + + template + WIDE_INTEGER_CONSTEXPR + auto from_chars(const char* first, + const char* last, + uintwide_t& x, + int base) -> std::from_chars_result + { + using local_wide_integer_type = uintwide_t; + + using local_wide_integer_type = uintwide_t; + using local_limb_type = typename local_wide_integer_type::limb_type; + + detail::fill_unsafe(x.values.begin(), x.values.end(), static_cast(UINT8_C(0))); + + const auto str_len = static_cast(detail::distance_unsafe(first, last)); + + const auto result_rd_string_is_ok = x.rd_string(first, str_len, base); + + std::from_chars_result result { }; + + if(result_rd_string_is_ok) + { + result = + std::from_chars_result + { + last, + std::errc() + }; + } + else + { + result = + std::from_chars_result + { + last, + std::errc::result_out_of_range + }; + + detail::fill_unsafe(x.values.begin(), x.values.end(), static_cast(UINT8_C(0))); + } + + return result; + } #endif #if !defined(WIDE_INTEGER_DISABLE_TO_STRING) diff --git a/test/test.cpp b/test/test.cpp index 3419817..a0546d6 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2018 - 2023. // +// Copyright Christopher Kormanyos 2018 - 2024. // // 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) // @@ -11,8 +11,9 @@ // When using local Boost-develop branch, use specific include paths. // -I/mnt/c/boost/modular_boost/boost/libs/config/include -I/mnt/c/boost/modular_boost/boost/libs/multiprecision/include -// When using -std=c++14 and g++ +// When using -std=c++14/20 and g++ // g++ -finline-functions -march=native -mtune=native -O3 -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -std=c++14 -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -DWIDE_INTEGER_HAS_MUL_8_BY_8_UNROLL -I. -I/mnt/c/boost/boost_1_83_0 -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp examples/example000a_builtin_convert.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe +// g++ -finline-functions -march=native -mtune=native -O3 -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -std=c++20 -DWIDE_INTEGER_HAS_LIMB_TYPE_UINT64 -DWIDE_INTEGER_HAS_MUL_8_BY_8_UNROLL -I. -I/mnt/c/boost/boost_1_83_0 -pthread -lpthread test/test.cpp test/test_uintwide_t_boost_backend.cpp test/test_uintwide_t_edge_cases.cpp test/test_uintwide_t_examples.cpp test/test_uintwide_t_float_convert.cpp test/test_uintwide_t_int_convert.cpp test/test_uintwide_t_n_base.cpp test/test_uintwide_t_n_binary_ops_base.cpp examples/example000a_builtin_convert.cpp test/test_uintwide_t_spot_values.cpp examples/example000_numeric_limits.cpp examples/example001_mul_div.cpp examples/example001a_div_mod.cpp examples/example002_shl_shr.cpp examples/example003_sqrt.cpp examples/example003a_cbrt.cpp examples/example004_rootk_pow.cpp examples/example005_powm.cpp examples/example005a_pow_factors_of_p99.cpp examples/example006_gcd.cpp examples/example007_random_generator.cpp examples/example008_miller_rabin_prime.cpp examples/example008a_miller_rabin_prime.cpp examples/example009_timed_mul.cpp examples/example009a_timed_mul_4_by_4.cpp examples/example009b_timed_mul_8_by_8.cpp examples/example010_uint48_t.cpp examples/example011_uint24_t.cpp examples/example012_rsa_crypto.cpp examples/example013_ecdsa_sign_verify.cpp examples/example014_pi_spigot_wide.cpp -o wide_integer.exe // cd .tidy/make // make prepare -f make_tidy_01_generic.gmk MY_BOOST_ROOT=/mnt/c/boost/boost_1_83_0 diff --git a/test/test_uintwide_t_edge_cases.cpp b/test/test_uintwide_t_edge_cases.cpp index 500f495..cb8c274 100644 --- a/test/test_uintwide_t_edge_cases.cpp +++ b/test/test_uintwide_t_edge_cases.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2019 - 2023. +// Copyright Christopher Kormanyos 2019 - 2024. // 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) @@ -150,6 +150,38 @@ using boost_uint_type = boost::multiprecision::et_off>; #endif +} // namespace test_uintwide_t_edge + +// LCOV_EXCL_START +#if (defined(__cpp_lib_to_chars) && (__cpp_lib_to_chars >= 201611L)) +#if (defined (WIDE_INTEGER_CONSTEXPR_IS_COMPILE_TIME_CONST) && (WIDE_INTEGER_CONSTEXPR_IS_COMPILE_TIME_CONST == 1)) +WIDE_INTEGER_CONSTEXPR auto constexpr_test_from_chars() -> ::test_uintwide_t_edge::local_uintwide_t_small_signed_type +{ + const char str_oct[] = "03065217317131113762053502330331263237375335355677425522565630540315656637703556251373"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + + ::test_uintwide_t_edge::local_uintwide_t_small_signed_type val { }; + + using std::from_chars; + + const auto fc_result = + from_chars + ( + str_oct + static_cast(UINT8_C(1)), // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic) + str_oct + static_cast(sizeof(str_oct) - static_cast(UINT8_C(1))), // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay,cppcoreguidelines-pro-bounds-pointer-arithmetic) + val, + 8 + ); + + static_cast(fc_result); + + return val; +} +#endif +#endif +// LCOV_EXCL_STOP + +namespace test_uintwide_t_edge { + enum class local_base { dec, @@ -1691,14 +1723,14 @@ auto test_various_isolated_edge_cases() -> bool // NOLINT(readability-function-c return result_is_ok; } -auto test_to_chars_and_to_string() -> bool // NOLINT(readability-function-cognitive-complexity) +auto test_to_and_from_chars_and_to_string() -> bool // NOLINT(readability-function-cognitive-complexity) { eng_sgn.seed(util::util_pseudorandom_time_point_seed::value()); eng_dig.seed(util::util_pseudorandom_time_point_seed::value()); auto result_is_ok = true; - #if defined(__cpp_lib_to_chars) + #if (defined(__cpp_lib_to_chars) && (__cpp_lib_to_chars >= 201611L)) for(auto i = static_cast(UINT8_C(0)); i < static_cast(loop_count_hi); ++i) @@ -1781,7 +1813,106 @@ auto test_to_chars_and_to_string() -> bool // NOLINT(readability-function-cognit result_is_ok = (result_n_to_from_string_dec_is_ok && result_is_ok); } - #endif // __cpp_lib_to_chars + + { + using from_chars_vals_array_type = std::array(UINT8_C(3))>; + using from_chars_str_array_type = std::array(UINT8_C(3))>; + + const from_chars_str_array_type from_chars_strings_dec = + {{ + std::string("15144643305917092583843275533505256431413500728112133531049985787371431391573"), + std::string("32468694466796117852331137634732746549554240939117027005983522724188427316919"), + std::string("22464118857179526662260684853039985803178920824202321315045157411980838523643") + }}; + + const from_chars_vals_array_type from_chars_vals = + {{ + local_uintwide_t_small_signed_type(from_chars_strings_dec[0U].c_str()), + local_uintwide_t_small_signed_type(from_chars_strings_dec[1U].c_str()), + local_uintwide_t_small_signed_type(from_chars_strings_dec[2U].c_str()) + }}; + + #if (defined (WIDE_INTEGER_CONSTEXPR_IS_COMPILE_TIME_CONST) && (WIDE_INTEGER_CONSTEXPR_IS_COMPILE_TIME_CONST == 1)) + { + WIDE_INTEGER_CONSTEXPR local_uintwide_t_small_signed_type compile_time_val("22464118857179526662260684853039985803178920824202321315045157411980838523643"); + + static_assert(::constexpr_test_from_chars() == compile_time_val, "Error: Can not perform constexpr-from_chars() at compile-time"); + + const auto result_constexpr_test_from_chars_is_ok = (::constexpr_test_from_chars() == compile_time_val); + + result_is_ok = (result_constexpr_test_from_chars_is_ok && result_is_ok); + } + #endif + + const from_chars_str_array_type from_chars_strings_hex = + {{ + std::string("0x217B907900B4119043037FA80D33976A08FCA38343D756BD61F2744C273FF155"), + std::string("0x47C8A13C35D6BFC31A75B127413559683B4FD3E725429CBC7221E5351BD2EEB7"), + std::string("0x31AA3D9E5925FC857426C365669F7EB75DBBF8AD4AEB98B03375D9FE1DB952FB") + }}; + + const from_chars_str_array_type from_chars_strings_oct = + {{ + std::string("02057344074400550106202060157752006463456650107712160320753526572607623504604717770525"), + std::string("04371050236065655377030647266111640465262640732375174711241234570710417123243364567267"), + std::string("03065217317131113762053502330331263237375335355677425522565630540315656637703556251373") + }}; + + { + // Test from_chars for dec. + std::size_t index { }; + + for(const auto& str : from_chars_strings_dec) + { + local_uintwide_t_small_signed_type val { }; + + const auto fc_result = from_chars(str.data(), str.data() + str.length(), val, 10); + + const auto result_from_chars_val_is_ok = ((val == from_chars_vals[index]) && (fc_result.ec == std::errc())); + + result_is_ok = (result_from_chars_val_is_ok && result_is_ok); + + ++index; + } + } + + { + // Test from_chars for hex. + std::size_t index { }; + + for(const auto& str : from_chars_strings_hex) + { + local_uintwide_t_small_signed_type val { }; + + const auto fc_result = from_chars(str.data() + static_cast(UINT8_C(2)), str.data() + str.length(), val, 16); + + const auto result_from_chars_val_is_ok = ((val == from_chars_vals[index]) && (fc_result.ec == std::errc())); + + result_is_ok = (result_from_chars_val_is_ok && result_is_ok); + + ++index; + } + } + + { + // Test from_chars for dec. + std::size_t index { }; + + for(const auto& str : from_chars_strings_oct) + { + local_uintwide_t_small_signed_type val { }; + + const auto fc_result = from_chars(str.data() + static_cast(UINT8_C(1)), str.data() + str.length(), val, 8); + + const auto result_from_chars_val_is_ok = ((val == from_chars_vals[index]) && (fc_result.ec == std::errc())); + + result_is_ok = (result_from_chars_val_is_ok && result_is_ok); + + ++index; + } + } + } + #endif // (defined(__cpp_lib_to_chars) && (__cpp_lib_to_chars >= 201611L)) #if !defined(WIDE_INTEGER_DISABLE_TO_STRING) for(auto i = static_cast(UINT8_C(0)); @@ -2419,7 +2550,7 @@ auto ::math::wide_integer::test_uintwide_t_edge_cases() -> bool result_is_ok = (test_uintwide_t_edge::test_small_prime_and_non_prime () && result_is_ok); result_is_ok = (test_uintwide_t_edge::test_some_gcd_and_equal_left_right () && result_is_ok); result_is_ok = (test_uintwide_t_edge::test_various_isolated_edge_cases () && result_is_ok); - result_is_ok = (test_uintwide_t_edge::test_to_chars_and_to_string () && result_is_ok); + result_is_ok = (test_uintwide_t_edge::test_to_and_from_chars_and_to_string() && result_is_ok); result_is_ok = (test_uintwide_t_edge::test_import_bits () && result_is_ok); result_is_ok = (test_uintwide_t_edge::test_export_bits () && result_is_ok); From 60f92ed2287de6077415a57e7034d906bc4ab02c Mon Sep 17 00:00:00 2001 From: Christopher Kormanyos Date: Mon, 22 Jan 2024 15:26:43 +0100 Subject: [PATCH 2/5] Handle clang-tidy messages --- math/wide_integer/uintwide_t.h | 10 ++++------ test/test_uintwide_t_edge_cases.cpp | 6 +++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/math/wide_integer/uintwide_t.h b/math/wide_integer/uintwide_t.h index efb14c2..e4cddd1 100644 --- a/math/wide_integer/uintwide_t.h +++ b/math/wide_integer/uintwide_t.h @@ -3574,12 +3574,10 @@ typename OtherLimbType, typename OtherAllocatorType, const bool OtherIsSigned> - friend - WIDE_INTEGER_CONSTEXPR - auto from_chars(const char* first, - const char* last, - uintwide_t& x, - int base) -> std::from_chars_result; + friend WIDE_INTEGER_CONSTEXPR auto from_chars(const char* first, // NOLINT(readability-redundant-declaration) + const char* last, + uintwide_t& x, + int base) -> std::from_chars_result; #endif template bool // NOLINT(readability-functi { local_uintwide_t_small_signed_type val { }; - const auto fc_result = from_chars(str.data(), str.data() + str.length(), val, 10); + const auto fc_result = from_chars(str.data(), str.data() + str.length(), val, 10); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) const auto result_from_chars_val_is_ok = ((val == from_chars_vals[index]) && (fc_result.ec == std::errc())); @@ -1884,7 +1884,7 @@ auto test_to_and_from_chars_and_to_string() -> bool // NOLINT(readability-functi { local_uintwide_t_small_signed_type val { }; - const auto fc_result = from_chars(str.data() + static_cast(UINT8_C(2)), str.data() + str.length(), val, 16); + const auto fc_result = from_chars(str.data() + static_cast(UINT8_C(2)), str.data() + str.length(), val, 16); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) const auto result_from_chars_val_is_ok = ((val == from_chars_vals[index]) && (fc_result.ec == std::errc())); @@ -1902,7 +1902,7 @@ auto test_to_and_from_chars_and_to_string() -> bool // NOLINT(readability-functi { local_uintwide_t_small_signed_type val { }; - const auto fc_result = from_chars(str.data() + static_cast(UINT8_C(1)), str.data() + str.length(), val, 8); + const auto fc_result = from_chars(str.data() + static_cast(UINT8_C(1)), str.data() + str.length(), val, 8); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) const auto result_from_chars_val_is_ok = ((val == from_chars_vals[index]) && (fc_result.ec == std::errc())); From c8f15841cd0e26c9df2e8e864f3fb0d5eeb6d8f7 Mon Sep 17 00:00:00 2001 From: Christopher Kormanyos Date: Mon, 22 Jan 2024 15:36:31 +0100 Subject: [PATCH 3/5] Update docs for from_chars() --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a64699..b76fa7b 100644 --- a/README.md +++ b/README.md @@ -868,7 +868,14 @@ in the wide-integer project. - All wide-integer-types are move constructable. - All wide-integer types having the same widths and having the same limb-type (but possibly different sign) are move-assignable and `std::move()`-capable. -### Importing and exporting bits +### Importing and exporting characters and bits + +For sufficiently modern standards-conforming compilers, +namespace-specific functions `to_chars()` and `from_chars()` +are available. These each have the _usual_ ``-like +behavior and can also be used in `constexpr`-context. +For motivational words on these, see also +[issue 398](https://github.com/ckormanyos/wide-integer/issues/398). Support for importing and exporting bits is granted by the subroutines `import_bits()` and `export_bits()`. Their interfaces, input/output forms From 2e0b4fef9240394bbbbf8eb3f222bed69ffef23c Mon Sep 17 00:00:00 2001 From: Christopher Kormanyos Date: Mon, 22 Jan 2024 17:49:24 +0100 Subject: [PATCH 4/5] Add another test case for from_chars --- test/test_uintwide_t_edge_cases.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/test_uintwide_t_edge_cases.cpp b/test/test_uintwide_t_edge_cases.cpp index b63b3b4..e53b72c 100644 --- a/test/test_uintwide_t_edge_cases.cpp +++ b/test/test_uintwide_t_edge_cases.cpp @@ -1844,6 +1844,27 @@ auto test_to_and_from_chars_and_to_string() -> bool // NOLINT(readability-functi } #endif + { + auto str_false = from_chars_strings_dec.back(); + + local_uintwide_t_small_signed_type val_false { }; + + const auto fc_result_ok = from_chars(str_false.data(), str_false.data() + str_false.length(), val_false, 10); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + + const auto result_false_correct_is_ok = ((val_false == from_chars_vals.back()) && (fc_result_ok.ec == std::errc())); + + // Now make the false-string to actually be false. + str_false.back() = 'Z'; + + const auto fc_result_not_ok = from_chars(str_false.data(), str_false.data() + str_false.length(), val_false, 10); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + + const auto result_false_false_is_ok = ((val_false != from_chars_vals.back()) && (fc_result_not_ok.ec != std::errc())); + + const auto result_both_vals_false_are_ok = (result_false_correct_is_ok && result_false_false_is_ok); + + result_is_ok = (result_both_vals_false_are_ok && result_is_ok); + } + const from_chars_str_array_type from_chars_strings_hex = {{ std::string("0x217B907900B4119043037FA80D33976A08FCA38343D756BD61F2744C273FF155"), From 7183be81cf12f898c576fbf6d80944eebed7c829 Mon Sep 17 00:00:00 2001 From: Christopher Kormanyos Date: Mon, 22 Jan 2024 18:30:57 +0100 Subject: [PATCH 5/5] Simplify char-conv base handling --- math/wide_integer/uintwide_t.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/math/wide_integer/uintwide_t.h b/math/wide_integer/uintwide_t.h index e4cddd1..e0c3859 100644 --- a/math/wide_integer/uintwide_t.h +++ b/math/wide_integer/uintwide_t.h @@ -5392,9 +5392,10 @@ ++pos; } - std::uint_fast8_t base { }; + // Set the base if the client has supplied a non-zero base-hint. + auto base = static_cast(base_hint); - if(base_hint == 0) + if(base == static_cast(UINT8_C(0))) { base = static_cast(UINT8_C(10)); @@ -5427,11 +5428,6 @@ } } } - else - { - // Set the base if the client has supplied a non-zero base-hint. - base = static_cast(base_hint); - } auto char_is_valid = true;