string/numeric: add hex parsing

This commit is contained in:
Vaxry 2026-03-17 14:52:42 -04:00
parent 7d3be08f84
commit d32196ab2a
Signed by: vaxry
GPG key ID: 665806380871D640
2 changed files with 70 additions and 0 deletions

View file

@ -21,6 +21,25 @@ namespace Hyprutils::String {
return std::unexpected(NUMERIC_PARSE_BAD);
T value{};
if constexpr (std::integral<T>) {
if (sv.size() >= 2 && sv[0] == '0' && (sv[1] == 'x' || sv[1] == 'X')) {
if (sv.size() == 2)
return std::unexpected(NUMERIC_PARSE_BAD);
const auto hex = sv.substr(2);
const auto [ptr, ec] = std::from_chars(hex.data(), hex.data() + hex.size(), value, 16);
if (ec == std::errc::invalid_argument)
return std::unexpected(NUMERIC_PARSE_BAD);
if (ec == std::errc::result_out_of_range)
return std::unexpected(NUMERIC_PARSE_OUT_OF_RANGE);
if (ptr != hex.data() + hex.size())
return std::unexpected(NUMERIC_PARSE_GARBAGE);
return value;
}
}
const auto [ptr, ec] = std::from_chars(sv.data(), sv.data() + sv.size(), value);
if (ec == std::errc::invalid_argument)

View file

@ -90,3 +90,54 @@ TEST(Numeric, unsignedTypes) {
ASSERT_TRUE(r2.has_value());
EXPECT_EQ(*r2, 0u);
}
TEST(Numeric, hexSuccess) {
auto r = strToNumber<int>("0xAF23");
ASSERT_TRUE(r.has_value());
EXPECT_EQ(*r, 0xAF23);
auto r2 = strToNumber<uint32_t>("0xFF");
ASSERT_TRUE(r2.has_value());
EXPECT_EQ(*r2, 0xFFu);
auto r3 = strToNumber<uint64_t>("0xDEADBEEF");
ASSERT_TRUE(r3.has_value());
EXPECT_EQ(*r3, 0xDEADBEEFu);
// uppercase X prefix
auto r4 = strToNumber<int>("0XFF");
ASSERT_TRUE(r4.has_value());
EXPECT_EQ(*r4, 0xFF);
// lowercase hex digits
auto r5 = strToNumber<uint32_t>("0xdeadbeef");
ASSERT_TRUE(r5.has_value());
EXPECT_EQ(*r5, 0xDEADBEEFu);
// zero value
auto r6 = strToNumber<int>("0x0");
ASSERT_TRUE(r6.has_value());
EXPECT_EQ(*r6, 0);
}
TEST(Numeric, hexErrors) {
// incomplete prefix (just "0x")
auto r = strToNumber<int>("0x");
ASSERT_FALSE(r.has_value());
EXPECT_EQ(r.error(), NUMERIC_PARSE_BAD);
// garbage after valid hex digits
auto r2 = strToNumber<int>("0xFF_ZZ");
ASSERT_FALSE(r2.has_value());
EXPECT_EQ(r2.error(), NUMERIC_PARSE_GARBAGE);
// out of range for type
auto r3 = strToNumber<uint8_t>("0xFFF");
ASSERT_FALSE(r3.has_value());
EXPECT_EQ(r3.error(), NUMERIC_PARSE_OUT_OF_RANGE);
// floats do not accept hex prefix
auto r4 = strToNumber<double>("0xFF");
ASSERT_FALSE(r4.has_value());
EXPECT_EQ(r4.error(), NUMERIC_PARSE_GARBAGE);
}