More tests
This commit is contained in:
parent
093e2a4780
commit
5a32e64b05
@ -407,7 +407,7 @@ class basic_string_view {
|
|||||||
constexpr iterator begin() const { return data_; }
|
constexpr iterator begin() const { return data_; }
|
||||||
constexpr iterator end() const { return data_ + size_; }
|
constexpr iterator end() const { return data_ + size_; }
|
||||||
|
|
||||||
void remove_prefix(size_t n) {
|
constexpr void remove_prefix(size_t n) {
|
||||||
data_ += n;
|
data_ += n;
|
||||||
size_ -= n;
|
size_ -= n;
|
||||||
}
|
}
|
||||||
@ -460,7 +460,7 @@ namespace internal {
|
|||||||
|
|
||||||
// Casts nonnegative integer to unsigned.
|
// Casts nonnegative integer to unsigned.
|
||||||
template <typename Int>
|
template <typename Int>
|
||||||
inline typename std::make_unsigned<Int>::type to_unsigned(Int value) {
|
constexpr typename std::make_unsigned<Int>::type to_unsigned(Int value) {
|
||||||
FMT_ASSERT(value >= 0, "negative value");
|
FMT_ASSERT(value >= 0, "negative value");
|
||||||
return static_cast<typename std::make_unsigned<Int>::type>(value);
|
return static_cast<typename std::make_unsigned<Int>::type>(value);
|
||||||
}
|
}
|
||||||
@ -1956,9 +1956,9 @@ class parse_context : public ErrorHandler {
|
|||||||
int next_arg_index_;
|
int next_arg_index_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool check_no_auto_index(const char *&error) {
|
constexpr bool check_no_auto_index() {
|
||||||
if (next_arg_index_ > 0) {
|
if (next_arg_index_ > 0) {
|
||||||
error = "cannot switch from automatic to manual argument indexing";
|
on_error("cannot switch from automatic to manual argument indexing");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
next_arg_index_ = -1;
|
next_arg_index_ = -1;
|
||||||
@ -1981,26 +1981,25 @@ class parse_context : public ErrorHandler {
|
|||||||
constexpr iterator end() const { return format_str_.end(); }
|
constexpr iterator end() const { return format_str_.end(); }
|
||||||
|
|
||||||
// Advances the begin iterator to ``it``.
|
// Advances the begin iterator to ``it``.
|
||||||
void advance_to(iterator it) {
|
constexpr void advance_to(iterator it) {
|
||||||
format_str_.remove_prefix(it - begin());
|
format_str_.remove_prefix(it - begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the next argument index.
|
// Returns the next argument index.
|
||||||
unsigned next_arg_index(const char *&error) {
|
constexpr unsigned next_arg_index() {
|
||||||
if (next_arg_index_ >= 0)
|
if (next_arg_index_ >= 0)
|
||||||
return internal::to_unsigned(next_arg_index_++);
|
return internal::to_unsigned(next_arg_index_++);
|
||||||
error = "cannot switch from manual to automatic argument indexing";
|
on_error("cannot switch from manual to automatic argument indexing");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_arg_id(unsigned) {
|
constexpr void check_arg_id(unsigned) { check_no_auto_index(); }
|
||||||
const char *error = 0;
|
|
||||||
if (!check_no_auto_index(error))
|
|
||||||
FMT_THROW(format_error(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
void check_arg_id(basic_string_view<Char>) {}
|
void check_arg_id(basic_string_view<Char>) {}
|
||||||
|
|
||||||
|
constexpr void on_error(const char *message) {
|
||||||
|
ErrorHandler::on_error(message);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr ErrorHandler error_handler() const { return *this; }
|
constexpr ErrorHandler error_handler() const { return *this; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2029,7 +2028,7 @@ class context_base : public parse_context<Char>{
|
|||||||
// Checks if manual indexing is used and returns the argument with
|
// Checks if manual indexing is used and returns the argument with
|
||||||
// specified index.
|
// specified index.
|
||||||
format_arg get_arg(unsigned arg_index, const char *&error) {
|
format_arg get_arg(unsigned arg_index, const char *&error) {
|
||||||
return this->check_no_auto_index(error) ?
|
return this->check_no_auto_index() ?
|
||||||
this->do_get_arg(arg_index, error) : format_arg();
|
this->do_get_arg(arg_index, error) : format_arg();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2365,11 +2364,7 @@ class dynamic_specs_handler :
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr arg_ref_type make_arg_ref(auto_id) {
|
constexpr arg_ref_type make_arg_ref(auto_id) {
|
||||||
const char *error = 0;
|
return arg_ref_type(context_.next_arg_index());
|
||||||
auto index = context_.next_arg_index(error);
|
|
||||||
if (error)
|
|
||||||
FMT_THROW(format_error(error));
|
|
||||||
return arg_ref_type(index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamic_format_specs<char_type> &specs_;
|
dynamic_format_specs<char_type> &specs_;
|
||||||
@ -2607,19 +2602,21 @@ constexpr const typename ParseContext::char_type *
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename ErrorHandler, typename... Args>
|
template <typename Char, typename ErrorHandler, typename... Args>
|
||||||
class format_string_checker : public ErrorHandler {
|
class format_string_checker {
|
||||||
public:
|
public:
|
||||||
explicit constexpr format_string_checker(ErrorHandler eh, const Char *end)
|
explicit constexpr format_string_checker(
|
||||||
: ErrorHandler(eh), end_(end) {}
|
basic_string_view<Char> format_str, ErrorHandler eh)
|
||||||
|
: context_(format_str, eh) {}
|
||||||
|
|
||||||
constexpr void on_text(const Char *, const Char *) {}
|
constexpr void on_text(const Char *, const Char *) {}
|
||||||
|
|
||||||
constexpr void on_arg_id() {
|
constexpr void on_arg_id() {
|
||||||
++arg_index_;
|
arg_index_ = context_.next_arg_index();
|
||||||
check_arg_index();
|
check_arg_index();
|
||||||
}
|
}
|
||||||
constexpr void on_arg_id(unsigned index) {
|
constexpr void on_arg_id(unsigned index) {
|
||||||
arg_index_ = index;
|
arg_index_ = index;
|
||||||
|
context_.check_arg_id(index);
|
||||||
check_arg_index();
|
check_arg_index();
|
||||||
}
|
}
|
||||||
constexpr void on_arg_id(basic_string_view<Char>) {}
|
constexpr void on_arg_id(basic_string_view<Char>) {}
|
||||||
@ -2627,8 +2624,13 @@ class format_string_checker : public ErrorHandler {
|
|||||||
constexpr void on_replacement_field(const Char *) {}
|
constexpr void on_replacement_field(const Char *) {}
|
||||||
|
|
||||||
constexpr const Char *on_format_specs(const Char *s) {
|
constexpr const Char *on_format_specs(const Char *s) {
|
||||||
parse_context_type ctx(basic_string_view<Char>(s, end_ - s), *this);
|
context_.advance_to(s);
|
||||||
return arg_index_ < NUM_ARGS ? parse_funcs_[arg_index_](ctx) : s;
|
return to_unsigned(arg_index_) < NUM_ARGS ?
|
||||||
|
parse_funcs_[arg_index_](context_) : s;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void on_error(const char *message) {
|
||||||
|
context_.on_error(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -2636,16 +2638,15 @@ class format_string_checker : public ErrorHandler {
|
|||||||
constexpr static size_t NUM_ARGS = sizeof...(Args);
|
constexpr static size_t NUM_ARGS = sizeof...(Args);
|
||||||
|
|
||||||
constexpr void check_arg_index() {
|
constexpr void check_arg_index() {
|
||||||
unsigned unsigned_index = arg_index_;
|
if (internal::to_unsigned(arg_index_) >= NUM_ARGS)
|
||||||
if (arg_index_ < 0 || unsigned_index >= NUM_ARGS)
|
context_.on_error("argument index out of range");
|
||||||
this->on_error("argument index out of range");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format specifier parsing function.
|
// Format specifier parsing function.
|
||||||
using parse_func = const Char *(*)(parse_context_type &);
|
using parse_func = const Char *(*)(parse_context_type &);
|
||||||
|
|
||||||
const Char *end_;
|
|
||||||
int arg_index_ = -1;
|
int arg_index_ = -1;
|
||||||
|
parse_context_type context_;
|
||||||
parse_func parse_funcs_[NUM_ARGS > 0 ? NUM_ARGS : 1] = {
|
parse_func parse_funcs_[NUM_ARGS > 0 ? NUM_ARGS : 1] = {
|
||||||
&parse_format_specs<Args, parse_context_type>...
|
&parse_format_specs<Args, parse_context_type>...
|
||||||
};
|
};
|
||||||
@ -2654,7 +2655,7 @@ class format_string_checker : public ErrorHandler {
|
|||||||
template <typename Char, typename ErrorHandler, typename... Args>
|
template <typename Char, typename ErrorHandler, typename... Args>
|
||||||
constexpr bool check_format_string(
|
constexpr bool check_format_string(
|
||||||
basic_string_view<Char> s, ErrorHandler eh = ErrorHandler()) {
|
basic_string_view<Char> s, ErrorHandler eh = ErrorHandler()) {
|
||||||
format_string_checker<Char, ErrorHandler, Args...> checker(eh, s.end());
|
format_string_checker<Char, ErrorHandler, Args...> checker(s, eh);
|
||||||
parse_format_string(s.begin(), checker);
|
parse_format_string(s.begin(), checker);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2751,7 +2752,7 @@ class basic_context :
|
|||||||
|
|
||||||
format_arg next_arg() {
|
format_arg next_arg() {
|
||||||
const char *error = 0;
|
const char *error = 0;
|
||||||
format_arg arg = this->do_get_arg(this->next_arg_index(error), error);
|
format_arg arg = this->do_get_arg(this->next_arg_index(), error);
|
||||||
if (error)
|
if (error)
|
||||||
FMT_THROW(format_error(error));
|
FMT_THROW(format_error(error));
|
||||||
return arg;
|
return arg;
|
||||||
@ -3861,15 +3862,12 @@ struct dynamic_formatter {
|
|||||||
template <typename Char>
|
template <typename Char>
|
||||||
inline typename basic_context<Char>::format_arg
|
inline typename basic_context<Char>::format_arg
|
||||||
basic_context<Char>::get_arg(basic_string_view<Char> name) {
|
basic_context<Char>::get_arg(basic_string_view<Char> name) {
|
||||||
const char *error = 0;
|
if (this->check_no_auto_index()) {
|
||||||
if (this->check_no_auto_index(error)) {
|
|
||||||
map_.init(this->args());
|
map_.init(this->args());
|
||||||
if (const format_arg *arg = map_.find(name))
|
if (const format_arg *arg = map_.find(name))
|
||||||
return *arg;
|
return *arg;
|
||||||
error = "argument not found";
|
this->on_error("argument not found");
|
||||||
}
|
}
|
||||||
if (error)
|
|
||||||
FMT_THROW(format_error(error));
|
|
||||||
return format_arg();
|
return format_arg();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3881,8 +3879,8 @@ void vformat_to(basic_buffer<Char> &buffer, basic_string_view<Char> format_str,
|
|||||||
|
|
||||||
struct handler : internal::error_handler {
|
struct handler : internal::error_handler {
|
||||||
handler(basic_buffer<Char> &b, basic_string_view<Char> str,
|
handler(basic_buffer<Char> &b, basic_string_view<Char> str,
|
||||||
basic_args<Context> args)
|
basic_args<Context> format_args)
|
||||||
: buffer(b), context(str, args) {}
|
: buffer(b), context(str, format_args) {}
|
||||||
|
|
||||||
void on_text(iterator begin, iterator end) {
|
void on_text(iterator begin, iterator end) {
|
||||||
buffer.append(pointer_from(begin), pointer_from(end));
|
buffer.append(pointer_from(begin), pointer_from(end));
|
||||||
|
@ -370,7 +370,7 @@ typename printf_context<Char, AF>::format_arg printf_context<Char, AF>::get_arg(
|
|||||||
const char *error = 0;
|
const char *error = 0;
|
||||||
format_arg arg;
|
format_arg arg;
|
||||||
if (arg_index == std::numeric_limits<unsigned>::max()) {
|
if (arg_index == std::numeric_limits<unsigned>::max()) {
|
||||||
arg_index = this->next_arg_index(error);
|
arg_index = this->next_arg_index();
|
||||||
if (!error)
|
if (!error)
|
||||||
arg = this->do_get_arg(arg_index, error);
|
arg = this->do_get_arg(arg_index, error);
|
||||||
} else {
|
} else {
|
||||||
|
@ -32,7 +32,7 @@ struct formatter<std::tm> {
|
|||||||
return pointer_from(end);
|
return pointer_from(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
void format(buffer &buf, const std::tm &tm, context &ctx) {
|
void format(buffer &buf, const std::tm &tm, context &) {
|
||||||
std::size_t start = buf.size();
|
std::size_t start = buf.size();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
std::size_t size = buf.capacity() - start;
|
std::size_t size = buf.capacity() - start;
|
||||||
|
@ -1702,7 +1702,7 @@ struct test_context {
|
|||||||
template <typename Id>
|
template <typename Id>
|
||||||
constexpr void check_arg_id(Id) {}
|
constexpr void check_arg_id(Id) {}
|
||||||
|
|
||||||
constexpr unsigned next_arg_index(const char *&) { return 33; }
|
constexpr unsigned next_arg_index() { return 33; }
|
||||||
|
|
||||||
void on_error(const char *) {}
|
void on_error(const char *) {}
|
||||||
|
|
||||||
@ -1903,4 +1903,7 @@ TEST(FormatTest, FormatStringErrors) {
|
|||||||
EXPECT_ERROR("{:.x}", "missing precision specifier", int);
|
EXPECT_ERROR("{:.x}", "missing precision specifier", int);
|
||||||
EXPECT_ERROR("{}", "argument index out of range");
|
EXPECT_ERROR("{}", "argument index out of range");
|
||||||
EXPECT_ERROR("{1}", "argument index out of range", int);
|
EXPECT_ERROR("{1}", "argument index out of range", int);
|
||||||
|
EXPECT_ERROR("{1}{}",
|
||||||
|
"cannot switch from manual to automatic argument indexing",
|
||||||
|
int, int);
|
||||||
}
|
}
|
||||||
|
@ -87,14 +87,14 @@ TEST(PrintfTest, NumberIsTooBigInArgIndex) {
|
|||||||
|
|
||||||
TEST(PrintfTest, SwitchArgIndexing) {
|
TEST(PrintfTest, SwitchArgIndexing) {
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%1$d%", 1, 2),
|
EXPECT_THROW_MSG(fmt::sprintf("%1$d%", 1, 2),
|
||||||
format_error, "invalid format string");
|
format_error, "cannot switch from manual to automatic argument indexing");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
|
EXPECT_THROW_MSG(fmt::sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%1$d%d", 1, 2),
|
EXPECT_THROW_MSG(fmt::sprintf("%1$d%d", 1, 2),
|
||||||
format_error, "cannot switch from manual to automatic argument indexing");
|
format_error, "cannot switch from manual to automatic argument indexing");
|
||||||
|
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%d%1$", 1, 2),
|
EXPECT_THROW_MSG(fmt::sprintf("%d%1$", 1, 2),
|
||||||
format_error, "invalid format string");
|
format_error, "cannot switch from automatic to manual argument indexing");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf(format("%d%{}$d", BIG_NUM), 1, 2),
|
EXPECT_THROW_MSG(fmt::sprintf(format("%d%{}$d", BIG_NUM), 1, 2),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%d%1$d", 1, 2),
|
EXPECT_THROW_MSG(fmt::sprintf("%d%1$d", 1, 2),
|
||||||
|
Loading…
Reference in New Issue
Block a user