Commit ef6282fc authored by Victor Zverovich's avatar Victor Zverovich

Fix gcc 4.4 build

parent e3e470bb
...@@ -10,27 +10,18 @@ ...@@ -10,27 +10,18 @@
#include "fmt/format.h" #include "fmt/format.h"
#include "gmock.h" #include "gmock.h"
#include "gtest-extra.h"
namespace fmt { FMT_BEGIN_NAMESPACE
namespace internal {
struct scan_arg { struct scan_arg {
int& value; int* value;
// TODO: more types // TODO: more types
}; };
struct scan_args {
int size;
const scan_arg* data;
template <size_t N>
scan_args(const std::array<scan_arg, N>& store)
: size(N), data(store.data()) {
static_assert(N < INT_MAX, "too many arguments");
}
};
template <typename Handler> template <typename Handler>
void parse_scan_format(string_view format_str, Handler& handler) { void parse_scan_format(string_view format_str, Handler&& handler) {
const char* p = format_str.data(); const char* p = format_str.data();
const char* end = p + format_str.size(); const char* end = p + format_str.size();
while (p != end) { while (p != end) {
...@@ -40,48 +31,70 @@ void parse_scan_format(string_view format_str, Handler& handler) { ...@@ -40,48 +31,70 @@ void parse_scan_format(string_view format_str, Handler& handler) {
handler.on_arg(); handler.on_arg();
} }
} }
} // namespace internal
void vscan(string_view input, string_view format_str, scan_args args) { struct scan_args {
struct handler { int size;
const char* begin; const internal::scan_arg* data;
const char* end;
scan_args args;
int next_arg_id;
handler(string_view input, scan_args args) template <size_t N>
: begin(input.data()), scan_args(const std::array<internal::scan_arg, N>& store)
end(begin + input.size()), : size(N), data(store.data()) {
args(args), static_assert(N < INT_MAX, "too many arguments");
next_arg_id(0) {} }
};
namespace internal {
struct scan_handler {
const char* begin;
const char* end;
scan_args args;
int next_arg_id;
scan_handler(string_view input, scan_args args)
: begin(input.data()),
end(begin + input.size()),
args(args),
next_arg_id(0) {}
void on_arg() { void on_arg() {
int value = 0; int value = 0;
while (begin != end) { while (begin != end) {
char c = *begin++; char c = *begin++;
if (c < '0' || c > '9') throw format_error("invalid input"); if (c < '0' || c > '9') throw format_error("invalid input");
value = value * 10 + (c - '0'); 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); if (next_arg_id >= args.size)
parse_scan_format(format_str, h); throw format_error("argument index out of range");
*args.data[0].value = value;
}
};
} // namespace internal
void vscan(string_view input, string_view format_str, scan_args args) {
internal::parse_scan_format(format_str, internal::scan_handler(input, args));
} }
template <typename... Args> template <typename... Args>
std::array<scan_arg, sizeof...(Args)> make_scan_args(Args&... args) { std::array<internal::scan_arg, sizeof...(Args)> make_scan_args(Args&... args) {
return {args...}; return std::array<internal::scan_arg, sizeof...(Args)>{&args...};
} }
template <typename... Args> template <typename... Args>
void scan(string_view input, string_view format_str, Args&... args) { void scan(string_view input, string_view format_str, Args&... args) {
vscan(input, format_str, make_scan_args(args...)); vscan(input, format_str, make_scan_args(args...));
} }
} // namespace fmt FMT_END_NAMESPACE
TEST(ScanTest, ReadInt) { TEST(ScanTest, ReadInt) {
int n = 0; int n = 0;
fmt::scan("42", "{}", n); fmt::scan("42", "{}", n);
EXPECT_EQ(n, 42); EXPECT_EQ(n, 42);
} }
TEST(ScanTest, InvalidFormat) {
EXPECT_THROW_MSG(fmt::scan("", "{}"), fmt::format_error,
"argument index out of range");
EXPECT_THROW_MSG(fmt::scan("", "{"), fmt::format_error,
"invalid format string");
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment