diff --git a/test/scan-test.cc b/test/scan-test.cc index 70587561c92b5..76d75f1616be0 100644 --- a/test/scan-test.cc +++ b/test/scan-test.cc @@ -20,66 +20,50 @@ TEST(scan_test, read_text) { fmt::string_view s = "foo"; auto end = fmt::scan_to(s, "foo"); EXPECT_EQ(end, s.end()); - EXPECT_THROW_MSG(fmt::scan_to("fob", "foo"), fmt::format_error, + EXPECT_THROW_MSG(fmt::scan("fob", "foo"), fmt::format_error, "invalid input"); } TEST(scan_test, read_int) { - int n = 0; - fmt::scan_to("42", "{}", n); - EXPECT_EQ(n, 42); - fmt::scan_to("-42", "{}", n); - EXPECT_EQ(n, -42); - fmt::scan_to("42", "{:}", n); - EXPECT_EQ(n, 42); - EXPECT_THROW_MSG(fmt::scan_to(std::to_string(INT_MAX + 1u), "{}", n), + EXPECT_EQ(fmt::scan("42", "{}")->value(), 42); + EXPECT_EQ(fmt::scan("-42", "{}")->value(), -42); + EXPECT_EQ(fmt::scan("42", "{:}")->value(), 42); + EXPECT_THROW_MSG(fmt::scan(std::to_string(INT_MAX + 1u), "{}"), fmt::format_error, "number is too big"); } -TEST(scan_test, read_longlong) { - long long n = 0; - fmt::scan_to("42", "{}", n); - EXPECT_EQ(n, 42); - fmt::scan_to("-42", "{}", n); - EXPECT_EQ(n, -42); +TEST(scan_test, read_long_long) { + EXPECT_EQ(fmt::scan("42", "{}")->value(), 42); + EXPECT_EQ(fmt::scan("-42", "{}")->value(), -42); } TEST(scan_test, read_uint) { - unsigned n = 0; - fmt::scan_to("42", "{}", n); - EXPECT_EQ(n, 42); - EXPECT_THROW_MSG(fmt::scan_to("-42", "{}", n), fmt::format_error, + EXPECT_EQ(fmt::scan("42", "{}")->value(), 42); + EXPECT_THROW_MSG(fmt::scan("-42", "{}"), fmt::format_error, "invalid input"); } -TEST(scan_test, read_ulonglong) { - unsigned long long n = 0; - fmt::scan_to("42", "{}", n); - EXPECT_EQ(n, 42); - EXPECT_THROW_MSG(fmt::scan_to("-42", "{}", n), fmt::format_error, - "invalid input"); +TEST(scan_test, read_ulong_long) { + EXPECT_EQ(fmt::scan("42", "{}")->value(), 42); + EXPECT_THROW_MSG(fmt::scan("-42", "{}")->value(), + fmt::format_error, "invalid input"); } TEST(scan_test, read_hex) { - unsigned n = 0; - fmt::scan_to("2a", "{:x}", n); - EXPECT_EQ(n, 42); + EXPECT_EQ(fmt::scan("2a", "{:x}")->value(), 42); auto num_digits = std::numeric_limits::digits / 4; EXPECT_THROW_MSG( - fmt::scan_to(fmt::format("1{:0{}}", 0, num_digits), "{:x}", n), + fmt::scan(fmt::format("1{:0{}}", 0, num_digits), "{:x}") + ->value(), fmt::format_error, "number is too big"); } TEST(scan_test, read_string) { - std::string s; - fmt::scan_to("foo", "{}", s); - EXPECT_EQ(s, "foo"); + EXPECT_EQ(fmt::scan("foo", "{}")->value(), "foo"); } TEST(scan_test, read_string_view) { - fmt::string_view s; - fmt::scan_to("foo", "{}", s); - EXPECT_EQ(s, "foo"); + EXPECT_EQ(fmt::scan("foo", "{}")->value(), "foo"); } TEST(scan_test, separator) { @@ -109,16 +93,14 @@ template <> struct scanner { template auto scan(num& n, ScanContext& ctx) const -> typename ScanContext::iterator { - // TODO: handle specifier - return fmt::scan(ctx, "{}", n.value); + return hex ? scan_to(ctx, "{:x}", n.value) : scan_to(ctx, "{}", n.value); } }; } // namespace fmt TEST(scan_test, read_custom) { - auto n = num(); - fmt::scan_to("42", "{}", n); - EXPECT_EQ(n.value, 42); + EXPECT_EQ(fmt::scan("42", "{}")->value().value, 42); + EXPECT_EQ(fmt::scan("2a", "{:x}")->value().value, 42); } TEST(scan_test, invalid_format) { @@ -136,10 +118,7 @@ TEST(scan_test, example) { EXPECT_EQ(value, 42); } -TEST(scan_test, end_of_input) { - int value = 0; - fmt::scan_to("", "{}", value); -} +TEST(scan_test, end_of_input) { fmt::scan("", "{}"); } #if FMT_USE_FCNTL TEST(scan_test, file) { @@ -151,7 +130,7 @@ TEST(scan_test, file) { int n1 = 0, n2 = 0; fmt::buffered_file f = pipe.read_end.fdopen("r"); - fmt::scan(f.get(), "{} {}", n1, n2); + fmt::scan_to(f.get(), "{} {}", n1, n2); EXPECT_EQ(n1, 10); EXPECT_EQ(n2, 20); } @@ -170,7 +149,7 @@ TEST(scan_test, lock) { fmt::buffered_file f = pipe.read_end.fdopen("r"); auto fun = [&]() { int value = 0; - while (fmt::scan(f.get(), "{}", value)) { + while (fmt::scan_to(f.get(), "{}", value)) { if (value != 42) { pipe.read_end.close(); EXPECT_EQ(value, 42); diff --git a/test/scan.h b/test/scan.h index 006f7a2e69017..7b307575b7776 100644 --- a/test/scan.h +++ b/test/scan.h @@ -450,8 +450,7 @@ const char* parse_scan_specs(const char* begin, const char* end, } template ::value)> -auto read(scan_iterator it, T& value) - -> scan_iterator { +auto read(scan_iterator it, T& value) -> scan_iterator { if (it == scan_sentinel()) return it; char c = *it; if (c < '0' || c > '9') throw_format_error("invalid input"); @@ -484,8 +483,7 @@ auto read(scan_iterator it, T& value) } template ::value)> -auto read_hex(scan_iterator it, T& value) - -> scan_iterator { +auto read_hex(scan_iterator it, T& value) -> scan_iterator { if (it == scan_sentinel()) return it; int digit = to_hex_digit(*it); if (digit < 0) throw_format_error("invalid input"); @@ -510,13 +508,12 @@ auto read_hex(scan_iterator it, T& value) template ::value)> auto read(scan_iterator it, T& value, const format_specs<>& specs) -> scan_iterator { - if (specs.type == presentation_type::hex_lower) - return read_hex(it, value); + if (specs.type == presentation_type::hex_lower) return read_hex(it, value); return read(it, value); } template ::value)> -auto read(scan_iterator it, T& value, const format_specs<>& = {}) +auto read(scan_iterator it, T& value, const format_specs<>& specs = {}) -> scan_iterator { bool negative = it != scan_sentinel() && *it == '-'; if (negative) { @@ -525,7 +522,7 @@ auto read(scan_iterator it, T& value, const format_specs<>& = {}) } using unsigned_type = typename std::make_unsigned::type; unsigned_type abs_value = 0; - it = read(it, abs_value); + it = read(it, abs_value, specs); auto n = static_cast(abs_value); value = negative ? -n : n; return it; @@ -636,45 +633,42 @@ auto make_scan_args(T&... args) -> std::array { return {{args...}}; } -void vscan(detail::scan_buffer& buf, string_view fmt, scan_args args) { - auto h = detail::scan_handler(fmt, buf, args); - detail::parse_format_string(fmt, h); -} - -// Scans the input and stores the results (in)to args. -template -auto scan_to(string_view input, string_view fmt, T&... args) - -> string_view::iterator { - auto&& buf = detail::string_scan_buffer(input); - vscan(buf, fmt, make_scan_args(args...)); - return input.begin() + (buf.begin().base() - input.data()); -} - -template -class scan_value { +template class scan_value { private: T value_; public: scan_value(T value) : value_(std::move(value)) {} - const T& value() const { - return value_; - } + const T& value() const { return value_; } }; // A rudimentary version of std::expected for testing the API shape. -template -class expected { +template class expected { private: T value_; public: expected(T value) : value_(std::move(value)) {} + + const T* operator->() const { return &value_; } }; -template -using scan_result = expected>; +template using scan_result = expected>; + +void vscan(detail::scan_buffer& buf, string_view fmt, scan_args args) { + auto h = detail::scan_handler(fmt, buf, args); + detail::parse_format_string(fmt, h); +} + +// Scans the input and stores the results (in)to args. +template +auto scan_to(string_view input, string_view fmt, T&... args) + -> string_view::iterator { + auto&& buf = detail::string_scan_buffer(input); + vscan(buf, fmt, make_scan_args(args...)); + return input.begin() + (buf.begin().base() - input.data()); +} template auto scan(string_view input, string_view fmt) -> scan_result { @@ -686,14 +680,15 @@ auto scan(string_view input, string_view fmt) -> scan_result { template ::value)> -auto scan(InputRange&& input, string_view fmt, T&... args) +auto scan_to(InputRange&& input, string_view fmt, T&... args) -> decltype(std::begin(input)) { auto it = std::begin(input); vscan(get_buffer(it), fmt, make_scan_args(args...)); return it; } -template bool scan(std::FILE* f, string_view fmt, T&... args) { +template +bool scan_to(std::FILE* f, string_view fmt, T&... args) { auto&& buf = detail::file_scan_buffer(f); vscan(buf, fmt, make_scan_args(args...)); return buf.begin() != buf.end();