mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 10:47:35 +02:00
Improve scan prototype
This commit is contained in:
@ -18,71 +18,73 @@
|
|||||||
|
|
||||||
TEST(scan_test, read_text) {
|
TEST(scan_test, read_text) {
|
||||||
fmt::string_view s = "foo";
|
fmt::string_view s = "foo";
|
||||||
auto end = fmt::scan(s, "foo");
|
auto end = fmt::scan_to(s, "foo");
|
||||||
EXPECT_EQ(end, s.end());
|
EXPECT_EQ(end, s.end());
|
||||||
EXPECT_THROW_MSG(fmt::scan("fob", "foo"), fmt::format_error, "invalid input");
|
EXPECT_THROW_MSG(fmt::scan_to("fob", "foo"), fmt::format_error,
|
||||||
|
"invalid input");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(scan_test, read_int) {
|
TEST(scan_test, read_int) {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
fmt::scan("42", "{}", n);
|
fmt::scan_to("42", "{}", n);
|
||||||
EXPECT_EQ(n, 42);
|
EXPECT_EQ(n, 42);
|
||||||
fmt::scan("-42", "{}", n);
|
fmt::scan_to("-42", "{}", n);
|
||||||
EXPECT_EQ(n, -42);
|
EXPECT_EQ(n, -42);
|
||||||
fmt::scan("42", "{:}", n);
|
fmt::scan_to("42", "{:}", n);
|
||||||
EXPECT_EQ(n, 42);
|
EXPECT_EQ(n, 42);
|
||||||
EXPECT_THROW_MSG(fmt::scan(std::to_string(INT_MAX + 1u), "{}", n),
|
EXPECT_THROW_MSG(fmt::scan_to(std::to_string(INT_MAX + 1u), "{}", n),
|
||||||
fmt::format_error, "number is too big");
|
fmt::format_error, "number is too big");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(scan_test, read_longlong) {
|
TEST(scan_test, read_longlong) {
|
||||||
long long n = 0;
|
long long n = 0;
|
||||||
fmt::scan("42", "{}", n);
|
fmt::scan_to("42", "{}", n);
|
||||||
EXPECT_EQ(n, 42);
|
EXPECT_EQ(n, 42);
|
||||||
fmt::scan("-42", "{}", n);
|
fmt::scan_to("-42", "{}", n);
|
||||||
EXPECT_EQ(n, -42);
|
EXPECT_EQ(n, -42);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(scan_test, read_uint) {
|
TEST(scan_test, read_uint) {
|
||||||
unsigned n = 0;
|
unsigned n = 0;
|
||||||
fmt::scan("42", "{}", n);
|
fmt::scan_to("42", "{}", n);
|
||||||
EXPECT_EQ(n, 42);
|
EXPECT_EQ(n, 42);
|
||||||
EXPECT_THROW_MSG(fmt::scan("-42", "{}", n), fmt::format_error,
|
EXPECT_THROW_MSG(fmt::scan_to("-42", "{}", n), fmt::format_error,
|
||||||
"invalid input");
|
"invalid input");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(scan_test, read_ulonglong) {
|
TEST(scan_test, read_ulonglong) {
|
||||||
unsigned long long n = 0;
|
unsigned long long n = 0;
|
||||||
fmt::scan("42", "{}", n);
|
fmt::scan_to("42", "{}", n);
|
||||||
EXPECT_EQ(n, 42);
|
EXPECT_EQ(n, 42);
|
||||||
EXPECT_THROW_MSG(fmt::scan("-42", "{}", n), fmt::format_error,
|
EXPECT_THROW_MSG(fmt::scan_to("-42", "{}", n), fmt::format_error,
|
||||||
"invalid input");
|
"invalid input");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(scan_test, read_hex) {
|
TEST(scan_test, read_hex) {
|
||||||
unsigned n = 0;
|
unsigned n = 0;
|
||||||
fmt::scan("2a", "{:x}", n);
|
fmt::scan_to("2a", "{:x}", n);
|
||||||
EXPECT_EQ(n, 42);
|
EXPECT_EQ(n, 42);
|
||||||
auto num_digits = std::numeric_limits<unsigned>::digits / 4;
|
auto num_digits = std::numeric_limits<unsigned>::digits / 4;
|
||||||
EXPECT_THROW_MSG(fmt::scan(fmt::format("1{:0{}}", 0, num_digits), "{:x}", n),
|
EXPECT_THROW_MSG(
|
||||||
fmt::format_error, "number is too big");
|
fmt::scan_to(fmt::format("1{:0{}}", 0, num_digits), "{:x}", n),
|
||||||
|
fmt::format_error, "number is too big");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(scan_test, read_string) {
|
TEST(scan_test, read_string) {
|
||||||
std::string s;
|
std::string s;
|
||||||
fmt::scan("foo", "{}", s);
|
fmt::scan_to("foo", "{}", s);
|
||||||
EXPECT_EQ(s, "foo");
|
EXPECT_EQ(s, "foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(scan_test, read_string_view) {
|
TEST(scan_test, read_string_view) {
|
||||||
fmt::string_view s;
|
fmt::string_view s;
|
||||||
fmt::scan("foo", "{}", s);
|
fmt::scan_to("foo", "{}", s);
|
||||||
EXPECT_EQ(s, "foo");
|
EXPECT_EQ(s, "foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(scan_test, separator) {
|
TEST(scan_test, separator) {
|
||||||
int n1 = 0, n2 = 0;
|
int n1 = 0, n2 = 0;
|
||||||
fmt::scan("10 20", "{} {}", n1, n2);
|
fmt::scan_to("10 20", "{} {}", n1, n2);
|
||||||
EXPECT_EQ(n1, 10);
|
EXPECT_EQ(n1, 10);
|
||||||
EXPECT_EQ(n2, 20);
|
EXPECT_EQ(n2, 20);
|
||||||
}
|
}
|
||||||
@ -115,28 +117,28 @@ template <> struct scanner<num> {
|
|||||||
|
|
||||||
TEST(scan_test, read_custom) {
|
TEST(scan_test, read_custom) {
|
||||||
auto n = num();
|
auto n = num();
|
||||||
fmt::scan("42", "{}", n);
|
fmt::scan_to("42", "{}", n);
|
||||||
EXPECT_EQ(n.value, 42);
|
EXPECT_EQ(n.value, 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(scan_test, invalid_format) {
|
TEST(scan_test, invalid_format) {
|
||||||
EXPECT_THROW_MSG(fmt::scan("", "{}"), fmt::format_error,
|
EXPECT_THROW_MSG(fmt::scan_to("", "{}"), fmt::format_error,
|
||||||
"argument index out of range");
|
"argument index out of range");
|
||||||
EXPECT_THROW_MSG(fmt::scan("", "{"), fmt::format_error,
|
EXPECT_THROW_MSG(fmt::scan_to("", "{"), fmt::format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(scan_test, example) {
|
TEST(scan_test, example) {
|
||||||
std::string key;
|
std::string key;
|
||||||
int value = 0;
|
int value = 0;
|
||||||
fmt::scan("answer = 42", "{} = {}", key, value);
|
fmt::scan_to("answer = 42", "{} = {}", key, value);
|
||||||
EXPECT_EQ(key, "answer");
|
EXPECT_EQ(key, "answer");
|
||||||
EXPECT_EQ(value, 42);
|
EXPECT_EQ(value, 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(scan_test, end_of_input) {
|
TEST(scan_test, end_of_input) {
|
||||||
int value = 0;
|
int value = 0;
|
||||||
fmt::scan("", "{}", value);
|
fmt::scan_to("", "{}", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_USE_FCNTL
|
#if FMT_USE_FCNTL
|
||||||
|
34
test/scan.h
34
test/scan.h
@ -650,6 +650,40 @@ auto scan_to(string_view input, string_view fmt, T&... args)
|
|||||||
return input.begin() + (buf.begin().base() - input.data());
|
return input.begin() + (buf.begin().base() - input.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class scan_value {
|
||||||
|
private:
|
||||||
|
T value_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
scan_value(T value) : value_(std::move(value)) {}
|
||||||
|
|
||||||
|
const T& value() const {
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// A rudimentary version of std::expected for testing the API shape.
|
||||||
|
template <typename T>
|
||||||
|
class expected {
|
||||||
|
private:
|
||||||
|
T value_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
expected(T value) : value_(std::move(value)) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using scan_result = expected<scan_value<T>>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto scan(string_view input, string_view fmt) -> scan_result<T> {
|
||||||
|
static_assert(std::is_same<remove_cvref_t<T>, T>::value, "");
|
||||||
|
auto value = T();
|
||||||
|
scan_to(input, fmt, value);
|
||||||
|
return scan_value<T>(std::move(value));
|
||||||
|
}
|
||||||
|
|
||||||
template <typename InputRange, typename... T,
|
template <typename InputRange, typename... T,
|
||||||
FMT_ENABLE_IF(!std::is_convertible<InputRange, string_view>::value)>
|
FMT_ENABLE_IF(!std::is_convertible<InputRange, string_view>::value)>
|
||||||
auto scan(InputRange&& input, string_view fmt, T&... args)
|
auto scan(InputRange&& input, string_view fmt, T&... args)
|
||||||
|
Reference in New Issue
Block a user