From 1ccc0b28d2eb24ab2c71d604c3fa317394b0183d Mon Sep 17 00:00:00 2001 From: Krzysztof Para Date: Thu, 27 Apr 2023 23:12:37 +0200 Subject: [PATCH] add binary number parsing --- include/argparse/argparse.hpp | 77 +++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index 633f7820..99401abc 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -145,6 +145,7 @@ constexpr bool standard_unsigned_integer = true; } // namespace +constexpr int radix_2 = 2; constexpr int radix_8 = 8; constexpr int radix_10 = 10; constexpr int radix_16 = 16; @@ -180,9 +181,10 @@ constexpr bool starts_with(std::basic_string_view prefix, } enum class chars_format { - scientific = 0x1, - fixed = 0x2, - hex = 0x4, + scientific = 0xf1, + fixed = 0xf2, + hex = 0xf4, + bin = 0xf8, general = fixed | scientific }; @@ -202,6 +204,21 @@ constexpr auto consume_hex_prefix(std::string_view s) return {false, s}; } +struct ConsumeBinPrefixResult { + bool is_binary; + std::string_view rest; +}; + +constexpr auto consume_bin_prefix(std::string_view s) + -> ConsumeBinPrefixResult +{ + if (starts_with("0b"sv, s) || starts_with("0B"sv, s)) { + s.remove_prefix(2); + return { true, s }; + } + return { false, s }; +} + template inline auto do_from_chars(std::string_view s) -> T { T x; @@ -237,12 +254,27 @@ template struct parse_number { } }; +template +struct parse_number { + auto operator()(std::string_view s) -> T + { + if (auto [ok, rest] = consume_bin_prefix(s); ok) { + return do_from_chars(rest); + } + throw std::invalid_argument { "pattern not found" }; + } +}; + template struct parse_number { auto operator()(std::string_view s) -> T { auto [ok, rest] = consume_hex_prefix(s); if (ok) { return do_from_chars(rest); } + auto [okB, restB] = consume_bin_prefix(s); + if (okB) { + return do_from_chars(restB); + } if (starts_with("0"sv, s)) { return do_from_chars(rest); } @@ -287,6 +319,11 @@ template struct parse_number { throw std::invalid_argument{ "chars_format::general does not parse hexfloat"}; } + if (auto r = consume_bin_prefix(s); r.is_binary) { + throw std::invalid_argument { + "chars_format::general does not parse binfloat" + }; + } return do_strtod(s); } @@ -297,17 +334,43 @@ template struct parse_number { if (auto r = consume_hex_prefix(s); !r.is_hexadecimal) { throw std::invalid_argument{"chars_format::hex parses hexfloat"}; } + if (auto r = consume_bin_prefix(s); r.is_binary) { + throw std::invalid_argument { + "chars_format::hex does not parse binfloat" + }; + } return do_strtod(s); } }; +template +struct parse_number { + auto operator()(std::string const& s) -> T { + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { + throw std::invalid_argument { "chars_format::bin does not parse hexfloat" }; + } + if (auto r = consume_bin_prefix(s); !r.is_binary) { + throw std::invalid_argument { + "chars_format::bin parses binfloat" + }; + } + + return do_strtod(s); + } +}; + template struct parse_number { auto operator()(std::string const &s) -> T { if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { throw std::invalid_argument{ "chars_format::scientific does not parse hexfloat"}; } + if (auto r = consume_bin_prefix(s); r.is_binary) { + throw std::invalid_argument { + "chars_format::scientific does not parse binfloat" + }; + } if (s.find_first_of("eE") == std::string::npos) { throw std::invalid_argument{ "chars_format::scientific requires exponent part"}; @@ -323,6 +386,11 @@ template struct parse_number { throw std::invalid_argument{ "chars_format::fixed does not parse hexfloat"}; } + if (auto r = consume_bin_prefix(s); r.is_binary) { + throw std::invalid_argument { + "chars_format::fixed does not parse binfloat" + }; + } if (s.find_first_of("eE") != std::string::npos) { throw std::invalid_argument{ "chars_format::fixed does not parse exponent part"}; @@ -465,6 +533,9 @@ class Argument { } else if constexpr (is_one_of(Shape, 'u') && details::standard_unsigned_integer) { action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'b') && + details::standard_unsigned_integer) { + action(details::parse_number()); } else if constexpr (is_one_of(Shape, 'o') && details::standard_unsigned_integer) { action(details::parse_number());