From c4f2de4933ae014cf81d5c4e350ca2eb25c67916 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 24 Dec 2023 07:32:27 -0800 Subject: [PATCH] Improve scan --- test/scan-test.cc | 12 ++++++++---- test/scan.h | 30 ++++++++++++++++++------------ 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/test/scan-test.cc b/test/scan-test.cc index 2f3cd6a2..96ae3746 100644 --- a/test/scan-test.cc +++ b/test/scan-test.cc @@ -127,11 +127,15 @@ TEST(scan_test, example) { TEST(scan_test, file) { fmt::file read_end, write_end; fmt::file::pipe(read_end, write_end); - fmt::string_view input = "42"; + + fmt::string_view input = "10 20"; write_end.write(input.data(), input.size()); write_end.close(); - int value = 0; - fmt::scan(read_end.fdopen("r").get(), "{}", value); - EXPECT_EQ(value, 42); + + int n1 = 0, n2 = 0; + fmt::buffered_file f = read_end.fdopen("r"); + fmt::scan(f.get(), "{} {}", n1, n2); + EXPECT_EQ(n1, 10); + EXPECT_EQ(n2, 20); } #endif // FMT_USE_FCNTL diff --git a/test/scan.h b/test/scan.h index 2ea7bfc2..f7d3e1da 100644 --- a/test/scan.h +++ b/test/scan.h @@ -14,6 +14,10 @@ FMT_BEGIN_NAMESPACE namespace detail { +inline bool is_whitespace(char c) { + return c == ' ' || c == '\n'; +} + struct maybe_contiguous_range { const char* begin; const char* end; @@ -39,21 +43,19 @@ class scan_buffer { end_ = end; } - auto peek() -> int { - if (ptr_ == end_) { - // TODO: refill buffer - return EOF; - } - return *ptr_; - } + const char* ptr() const { return ptr_; } - // Fills the buffer with more input if available. - virtual void consume() = 0; + auto peek() -> int { + return ptr_ != end_ ? *ptr_ : EOF; + } public: scan_buffer(const scan_buffer&) = delete; void operator=(const scan_buffer&) = delete; + // Fills the buffer with more input if available. + virtual void consume() = 0; + class iterator { private: const char** ptr_; @@ -76,6 +78,7 @@ class scan_buffer { iterator(scan_buffer* buf) : ptr_(&buf->ptr_), buf_(buf), value_(static_cast(buf->peek())) { + // TODO: fix check if (value_ == EOF) ptr_ = sentinel(); } @@ -235,7 +238,8 @@ class file_scan_buffer : public scan_buffer { void consume() override { // Consume the current buffer content. // TODO: do it more efficiently - for (size_t i = 0, n = file_.buffer().size(); i != n; ++i) file_.get(); + size_t n = to_unsigned(ptr() - file_.buffer().begin()); + for (size_t i = 0; i != n; ++i) file_.get(); fill(); } @@ -284,8 +288,7 @@ struct scan_context { auto end() const -> iterator { return buf_.end(); } void advance_to(iterator) { - // The scan_buffer iterator automatically updates the buffer position when - // incremented. + buf_.consume(); } }; @@ -418,6 +421,7 @@ struct scan_handler : error_handler { auto pos() const -> scan_buffer::iterator { return scan_ctx_.begin(); } void on_text(const char* begin, const char* end) { + if (begin == end) return; auto it = scan_ctx_.begin(), scan_end = scan_ctx_.end(); for (; begin != end; ++begin, ++it) { if (it == scan_end || *begin != *it) on_error("invalid input"); @@ -438,6 +442,8 @@ struct scan_handler : error_handler { void on_replacement_field(int, const char*) { auto it = scan_ctx_.begin(), end = scan_ctx_.end(); + while (it != end && is_whitespace(*it)) ++it; + scan_ctx_.advance_to(it); switch (arg_.type) { case scan_type::int_type: *arg_.int_value = read_int();