Files
fmt/test/scan-test.cc

101 lines
2.4 KiB
C++
Raw Normal View History

2019-05-15 10:02:40 -07:00
// 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 <array>
2019-05-15 10:20:51 -07:00
#include <climits>
2019-05-15 10:02:40 -07:00
#include "fmt/format.h"
#include "gmock.h"
2019-05-15 11:05:19 -07:00
#include "gtest-extra.h"
2019-05-15 10:02:40 -07:00
2019-05-15 11:05:19 -07:00
FMT_BEGIN_NAMESPACE
namespace internal {
2019-05-15 10:02:40 -07:00
struct scan_arg {
2019-05-15 11:05:19 -07:00
int* value;
2019-05-15 10:02:40 -07:00
// TODO: more types
};
template <typename Handler>
2019-05-15 11:05:19 -07:00
void parse_scan_format(string_view format_str, Handler&& handler) {
2019-05-15 10:02:40 -07:00
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();
}
}
2019-05-15 11:05:19 -07:00
} // namespace internal
2019-05-15 10:02:40 -07:00
2019-05-15 11:05:19 -07:00
struct scan_args {
int size;
const internal::scan_arg* data;
2019-05-15 10:02:40 -07:00
2019-05-15 11:05:19 -07:00
template <size_t N>
scan_args(const std::array<internal::scan_arg, N>& store)
: size(N), data(store.data()) {
static_assert(N < INT_MAX, "too many arguments");
}
};
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) {}
2019-05-15 10:02:40 -07:00
2019-05-15 11:05:19 -07:00
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');
2019-05-15 10:02:40 -07:00
}
2019-05-15 11:05:19 -07:00
if (next_arg_id >= args.size)
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));
2019-05-15 10:02:40 -07:00
}
template <typename... Args>
2019-05-15 11:05:19 -07:00
std::array<internal::scan_arg, sizeof...(Args)> make_scan_args(Args&... args) {
return std::array<internal::scan_arg, sizeof...(Args)>{&args...};
2019-05-15 10:02:40 -07:00
}
template <typename... Args>
void scan(string_view input, string_view format_str, Args&... args) {
vscan(input, format_str, make_scan_args(args...));
}
2019-05-15 11:05:19 -07:00
FMT_END_NAMESPACE
2019-05-15 10:02:40 -07:00
TEST(ScanTest, ReadInt) {
int n = 0;
fmt::scan("42", "{}", n);
EXPECT_EQ(n, 42);
}
2019-05-15 11:05:19 -07:00
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");
}