From 4e300df7123a402aef472aaaac30907b18a10c27 Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Wed, 12 Mar 2025 13:31:47 -0400 Subject: [PATCH] string: add `base` argument for ToIntegral to operate on hexadecimal --- src/test/util_tests.cpp | 33 +++++++++++++++++++++++++++++++++ src/util/strencodings.h | 7 ++++--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 13821db4b95..daa5b8b334d 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -835,6 +835,39 @@ BOOST_AUTO_TEST_CASE(test_LocaleIndependentAtoi) BOOST_CHECK_EQUAL(LocaleIndependentAtoi("256"), 255U); } +BOOST_AUTO_TEST_CASE(test_ToIntegralHex) +{ + std::optional n; + // Valid values + n = ToIntegral("1234", 16); + BOOST_CHECK_EQUAL(*n, 0x1234); + n = ToIntegral("a", 16); + BOOST_CHECK_EQUAL(*n, 0xA); + n = ToIntegral("0000000a", 16); + BOOST_CHECK_EQUAL(*n, 0xA); + n = ToIntegral("100", 16); + BOOST_CHECK_EQUAL(*n, 0x100); + n = ToIntegral("DEADbeef", 16); + BOOST_CHECK_EQUAL(*n, 0xDEADbeef); + n = ToIntegral("FfFfFfFf", 16); + BOOST_CHECK_EQUAL(*n, 0xFfFfFfFf); + n = ToIntegral("123456789", 16); + BOOST_CHECK_EQUAL(*n, 0x123456789ULL); + n = ToIntegral("0", 16); + BOOST_CHECK_EQUAL(*n, 0); + n = ToIntegral("FfFfFfFfFfFfFfFf", 16); + BOOST_CHECK_EQUAL(*n, 0xFfFfFfFfFfFfFfFfULL); + n = ToIntegral("-1", 16); + BOOST_CHECK_EQUAL(*n, -1); + // Invalid values + BOOST_CHECK(!ToIntegral("", 16)); + BOOST_CHECK(!ToIntegral("-1", 16)); + BOOST_CHECK(!ToIntegral("10 00", 16)); + BOOST_CHECK(!ToIntegral("1 ", 16)); + BOOST_CHECK(!ToIntegral("0xAB", 16)); + BOOST_CHECK(!ToIntegral("FfFfFfFfFfFfFfFf0", 16)); +} + BOOST_AUTO_TEST_CASE(test_FormatParagraph) { BOOST_CHECK_EQUAL(FormatParagraph("", 79, 0), ""); diff --git a/src/util/strencodings.h b/src/util/strencodings.h index 01063858047..dc8493ff566 100644 --- a/src/util/strencodings.h +++ b/src/util/strencodings.h @@ -169,17 +169,18 @@ constexpr inline bool IsSpace(char c) noexcept { /** * Convert string to integral type T. Leading whitespace, a leading +, or any * trailing character fail the parsing. The required format expressed as regex - * is `-?[0-9]+`. The minus sign is only permitted for signed integer types. + * is `-?[0-9]+` by default (or `-?[0-9a-fA-F]+` if base = 16). + * The minus sign is only permitted for signed integer types. * * @returns std::nullopt if the entire string could not be parsed, or if the * parsed value is not in the range representable by the type T. */ template -std::optional ToIntegral(std::string_view str) +std::optional ToIntegral(std::string_view str, size_t base = 10) { static_assert(std::is_integral_v); T result; - const auto [first_nonmatching, error_condition] = std::from_chars(str.data(), str.data() + str.size(), result); + const auto [first_nonmatching, error_condition] = std::from_chars(str.data(), str.data() + str.size(), result, base); if (first_nonmatching != str.data() + str.size() || error_condition != std::errc{}) { return std::nullopt; }