From 5ee08046315e2ffa5aef7a1638b1b44c754e5643 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 15 May 2019 10:02:40 -0700 Subject: [PATCH] Experiment with scan API --- test/CMakeLists.txt | 1 + test/scan-test.cc | 87 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 test/scan-test.cc diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7bbe63a5..69c76085 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -105,6 +105,7 @@ add_fmt_test(prepare-test) add_fmt_test(printf-test) add_fmt_test(custom-formatter-test) add_fmt_test(ranges-test) +add_fmt_test(scan-test) # MSVC fails to compile GMock when C++17 is enabled. if (FMT_HAS_VARIANT AND NOT MSVC) diff --git a/test/scan-test.cc b/test/scan-test.cc new file mode 100644 index 00000000..061f4abc --- /dev/null +++ b/test/scan-test.cc @@ -0,0 +1,87 @@ +// Formatting library for C++ - scanning API proof of concept +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#include +#include + +#include "fmt/format.h" +#include "gmock.h" + +namespace fmt { + +struct scan_arg { + int& value; + // TODO: more types +}; + +struct scan_args { + int size; + const scan_arg* data; + + template + scan_args(const std::array& store) + : size(N), data(store.data()) { + static_assert(N < std::numeric_limits::max(), "too many arguments"); + } +}; + +template +void parse_scan_format(string_view format_str, Handler& handler) { + const char* p = format_str.data(); + const char* end = p + format_str.size(); + while (p != end) { + char c = *p++; + if (c != '{' || p == end || *p++ != '}') + throw format_error("invalid format string"); + handler.on_arg(); + } +} + +void vscan(string_view input, string_view format_str, scan_args args) { + struct handler { + const char* begin; + const char* end; + scan_args args; + int next_arg_id; + + handler(string_view input, scan_args args) + : begin(input.data()), + end(begin + input.size()), + args(args), + next_arg_id(0) {} + + void on_arg() { + int value = 0; + while (begin != end) { + char c = *begin++; + if (c < '0' || c > '9') throw format_error("invalid input"); + value = value * 10 + (c - '0'); + } + if (next_arg_id >= args.size) + throw format_error("argument index out of range"); + args.data[0].value = value; + } + } h(input, args); + parse_scan_format(format_str, h); +} + +template +std::array make_scan_args(Args&... args) { + return {args...}; +} + +template +void scan(string_view input, string_view format_str, Args&... args) { + vscan(input, format_str, make_scan_args(args...)); +} +} // namespace fmt + +TEST(ScanTest, ReadInt) { + int n = 0; + fmt::scan("42", "{}", n); + EXPECT_EQ(n, 42); +}