mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-29 13:21:05 +00:00
Improve handling of named arguments
This commit is contained in:
parent
a9d62d3f35
commit
8a4630686e
@ -576,9 +576,9 @@ OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||
FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value &&
|
||||
std::is_base_of<internal::basic_compiled_format,
|
||||
CompiledFormat>::value)>
|
||||
FMT_ENABLE_IF(
|
||||
internal::is_output_iterator<OutputIt>::value&& std::is_base_of<
|
||||
internal::basic_compiled_format, CompiledFormat>::value)>
|
||||
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
|
||||
const CompiledFormat& cf,
|
||||
const Args&... args) {
|
||||
|
@ -762,25 +762,30 @@ template <typename T, typename Char> struct named_arg;
|
||||
|
||||
template <typename Char> struct named_arg_info {
|
||||
const Char* name;
|
||||
int arg_id;
|
||||
int id;
|
||||
};
|
||||
|
||||
template <typename T, typename Char, size_t NUM_ARGS, size_t NUM_NAMED_ARGS>
|
||||
struct arg_data {
|
||||
T args[NUM_ARGS != 0 ? NUM_ARGS : 1];
|
||||
named_arg_info<Char> named_args[NUM_NAMED_ARGS];
|
||||
template <typename... U> arg_data(const U&... init) : args{init...} {}
|
||||
// args_[0] points to named_args_ to avoid bloating format_args.
|
||||
T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : 1)];
|
||||
named_arg_info<Char> named_args_[NUM_NAMED_ARGS];
|
||||
|
||||
template <typename... U>
|
||||
arg_data(const U&... init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {}
|
||||
arg_data(const arg_data& other) = delete;
|
||||
const T* args() const { return args_ + 1; }
|
||||
named_arg_info<Char>* named_args() { return named_args_; }
|
||||
};
|
||||
|
||||
template <typename T, typename Char, size_t NUM_ARGS>
|
||||
struct arg_data<T, Char, NUM_ARGS, 0> {
|
||||
T args[NUM_ARGS != 0 ? NUM_ARGS : 1];
|
||||
static constexpr std::nullptr_t named_args = nullptr;
|
||||
template <typename... U> arg_data(const U&... init) : args{init...} {}
|
||||
};
|
||||
T args_[NUM_ARGS != 0 ? NUM_ARGS : 1];
|
||||
|
||||
template <typename T, typename Char, size_t NUM_ARGS>
|
||||
constexpr std::nullptr_t arg_data<T, Char, NUM_ARGS, 0>::named_args;
|
||||
template <typename... U> arg_data(const U&... init) : args_{init...} {}
|
||||
const T* args() const { return args_; }
|
||||
std::nullptr_t named_args() { return nullptr; }
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
inline void init_named_args(named_arg_info<Char>*, int, int) {}
|
||||
@ -880,6 +885,11 @@ template <typename Char> struct string_value {
|
||||
std::size_t size;
|
||||
};
|
||||
|
||||
template <typename Char> struct named_arg_value {
|
||||
const named_arg_info<Char>* data;
|
||||
std::size_t size;
|
||||
};
|
||||
|
||||
template <typename Context> struct custom_value {
|
||||
using parse_context = basic_format_parse_context<typename Context::char_type>;
|
||||
const void* value;
|
||||
@ -907,7 +917,8 @@ template <typename Context> class value {
|
||||
const void* pointer;
|
||||
string_value<char_type> string;
|
||||
custom_value<Context> custom;
|
||||
const named_arg_base<char_type>* named_arg;
|
||||
const named_arg_base<char_type>* named_arg; // DEPRECATED
|
||||
named_arg_value<char_type> named_args;
|
||||
};
|
||||
|
||||
FMT_CONSTEXPR value(int val = 0) : int_value(val) {}
|
||||
@ -927,6 +938,8 @@ template <typename Context> class value {
|
||||
string.size = val.size();
|
||||
}
|
||||
value(const void* val) : pointer(val) {}
|
||||
value(const named_arg_info<char_type>* args, size_t size)
|
||||
: named_args{args, size} {}
|
||||
|
||||
template <typename T> value(const T& val) {
|
||||
custom.value = &val;
|
||||
@ -1065,11 +1078,9 @@ template <typename Context> struct arg_mapper {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FMT_CONSTEXPR const named_arg_base<char_type>& map(
|
||||
const named_arg<T, char_type>& val) {
|
||||
auto arg = make_arg<Context>(val.value);
|
||||
std::memcpy(val.data, &arg, sizeof(arg));
|
||||
return val;
|
||||
FMT_CONSTEXPR auto map(const named_arg<T, char_type>& val)
|
||||
-> decltype(std::declval<arg_mapper>().map(val.value)) {
|
||||
return map(val.value);
|
||||
}
|
||||
|
||||
int map(...) {
|
||||
@ -1091,8 +1102,9 @@ using mapped_type_constant =
|
||||
|
||||
enum { packed_arg_bits = 5 };
|
||||
// Maximum number of arguments with packed types.
|
||||
enum { max_packed_args = 63 / packed_arg_bits };
|
||||
enum { max_packed_args = 62 / packed_arg_bits };
|
||||
enum : unsigned long long { is_unpacked_bit = 1ULL << 63 };
|
||||
enum : unsigned long long { has_named_args_bit = 1ULL << 62 };
|
||||
|
||||
template <typename Context> class arg_map;
|
||||
} // namespace internal
|
||||
@ -1118,6 +1130,12 @@ template <typename Context> class basic_format_arg {
|
||||
|
||||
using char_type = typename Context::char_type;
|
||||
|
||||
template <typename T, typename Char, size_t NUM_ARGS, size_t NUM_NAMED_ARGS>
|
||||
friend struct internal::arg_data;
|
||||
|
||||
basic_format_arg(const internal::named_arg_info<char_type>* args, size_t size)
|
||||
: value_(args, size) {}
|
||||
|
||||
public:
|
||||
class handle {
|
||||
public:
|
||||
@ -1204,13 +1222,11 @@ FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis,
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
// A map from argument names to their values for named arguments.
|
||||
// DEPRECATED.
|
||||
template <typename Context> class arg_map {
|
||||
private:
|
||||
using char_type = typename Context::char_type;
|
||||
|
||||
struct entry {
|
||||
basic_string_view<char_type> name;
|
||||
basic_string_view<typename Context::char_type> name;
|
||||
basic_format_arg<Context> arg;
|
||||
};
|
||||
|
||||
@ -1224,19 +1240,7 @@ template <typename Context> class arg_map {
|
||||
}
|
||||
|
||||
public:
|
||||
arg_map(const arg_map&) = delete;
|
||||
void operator=(const arg_map&) = delete;
|
||||
arg_map() : map_(nullptr), size_(0) {}
|
||||
void init(const basic_format_args<Context>& args);
|
||||
~arg_map() { delete[] map_; }
|
||||
|
||||
basic_format_arg<Context> find(basic_string_view<char_type> name) const {
|
||||
// The list is unsorted, so just return the first matching name.
|
||||
for (entry *it = map_, *end = map_ + size_; it != end; ++it) {
|
||||
if (it->name == name) return it->arg;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
// A type-erased reference to an std::locale to avoid heavy <locale> include.
|
||||
@ -1328,7 +1332,6 @@ template <typename OutputIt, typename Char> class basic_format_context {
|
||||
private:
|
||||
OutputIt out_;
|
||||
basic_format_args<basic_format_context> args_;
|
||||
internal::arg_map<basic_format_context> map_;
|
||||
internal::locale_ref loc_;
|
||||
|
||||
public:
|
||||
@ -1352,7 +1355,7 @@ template <typename OutputIt, typename Char> class basic_format_context {
|
||||
|
||||
// Checks if manual indexing is used and returns the argument with the
|
||||
// specified name.
|
||||
format_arg arg(basic_string_view<char_type> name);
|
||||
format_arg arg(basic_string_view<char_type> name) { return args_.get(name); }
|
||||
|
||||
internal::error_handler error_handler() { return {}; }
|
||||
void on_error(const char* message) { error_handler().on_error(message); }
|
||||
@ -1389,20 +1392,24 @@ class format_arg_store
|
||||
{
|
||||
private:
|
||||
static const size_t num_args = sizeof...(Args);
|
||||
static const size_t num_named_args = internal::count_named_args<Args...>();
|
||||
static const bool is_packed = num_args <= internal::max_packed_args;
|
||||
|
||||
using value_type = conditional_t<is_packed, internal::value<Context>,
|
||||
basic_format_arg<Context>>;
|
||||
|
||||
internal::arg_data<value_type, typename Context::char_type, num_args,
|
||||
internal::count_named_args<Args...>()>
|
||||
num_named_args>
|
||||
data_;
|
||||
|
||||
friend class basic_format_args<Context>;
|
||||
|
||||
static constexpr unsigned long long desc =
|
||||
is_packed ? internal::encode_types<Context, Args...>()
|
||||
: internal::is_unpacked_bit | num_args;
|
||||
(is_packed ? internal::encode_types<Context, Args...>()
|
||||
: internal::is_unpacked_bit | num_args) |
|
||||
(num_named_args != 0
|
||||
? static_cast<unsigned long long>(internal::has_named_args_bit)
|
||||
: 0);
|
||||
|
||||
public:
|
||||
FMT_DEPRECATED static constexpr unsigned long long types = desc;
|
||||
@ -1413,7 +1420,7 @@ class format_arg_store
|
||||
basic_format_args<Context>(*this),
|
||||
#endif
|
||||
data_{internal::make_arg<is_packed, Context>(args)...} {
|
||||
internal::init_named_args(data_.named_args, 0, 0, args...);
|
||||
internal::init_named_args(data_.named_args(), 0, 0, args...);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1559,6 +1566,9 @@ template <typename Context> class basic_format_args {
|
||||
};
|
||||
|
||||
bool is_packed() const { return (desc_ & internal::is_unpacked_bit) == 0; }
|
||||
bool has_named_args() const {
|
||||
return (desc_ & internal::has_named_args_bit) != 0;
|
||||
}
|
||||
|
||||
internal::type type(int index) const {
|
||||
int shift = index * internal::packed_arg_bits;
|
||||
@ -1597,7 +1607,7 @@ template <typename Context> class basic_format_args {
|
||||
template <typename... Args>
|
||||
basic_format_args(const format_arg_store<Context, Args...>& store)
|
||||
: desc_(store.desc) {
|
||||
set_data(store.data_.args);
|
||||
set_data(store.data_.args());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1621,14 +1631,24 @@ template <typename Context> class basic_format_args {
|
||||
set_data(args);
|
||||
}
|
||||
|
||||
/** Returns the argument at specified index. */
|
||||
format_arg get(int index) const {
|
||||
format_arg arg = do_get(index);
|
||||
/** Returns the argument with the specified id. */
|
||||
format_arg get(int id) const {
|
||||
format_arg arg = do_get(id);
|
||||
if (arg.type_ == internal::type::named_arg_type)
|
||||
arg = arg.value_.named_arg->template deserialize<Context>();
|
||||
return arg;
|
||||
}
|
||||
|
||||
template <typename Char> format_arg get(basic_string_view<Char> name) const {
|
||||
if (!has_named_args()) return {};
|
||||
const auto& named_args =
|
||||
(is_packed() ? values_[-1] : args_[-1].value_).named_args;
|
||||
for (size_t i = 0; i < named_args.size; ++i) {
|
||||
if (named_args.data[i].name == name) return get(named_args.data[i].id);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
int max_size() const {
|
||||
unsigned long long max_packed = internal::max_packed_args;
|
||||
return static_cast<int>(is_packed() ? max_packed
|
||||
|
@ -1367,24 +1367,6 @@ class cstring_type_checker : public ErrorHandler {
|
||||
FMT_CONSTEXPR void on_pointer() {}
|
||||
};
|
||||
|
||||
template <typename Context>
|
||||
void arg_map<Context>::init(const basic_format_args<Context>& args) {
|
||||
if (map_) return;
|
||||
map_ = new entry[internal::to_unsigned(args.max_size())];
|
||||
if (args.is_packed()) {
|
||||
for (int i = 0;; ++i) {
|
||||
internal::type arg_type = args.type(i);
|
||||
if (arg_type == internal::type::none_type) return;
|
||||
if (arg_type == internal::type::named_arg_type)
|
||||
push_back(args.values_[i]);
|
||||
}
|
||||
}
|
||||
for (int i = 0, n = args.max_size(); i < n; ++i) {
|
||||
auto type = args.args_[i].type_;
|
||||
if (type == internal::type::named_arg_type) push_back(args.args_[i].value_);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char> struct nonfinite_writer {
|
||||
sign_t sign;
|
||||
const char* str;
|
||||
@ -2195,10 +2177,10 @@ FMT_CONSTEXPR int get_dynamic_spec(FormatArg arg, ErrorHandler eh) {
|
||||
|
||||
struct auto_id {};
|
||||
|
||||
template <typename Context>
|
||||
FMT_CONSTEXPR typename Context::format_arg get_arg(Context& ctx, int id) {
|
||||
template <typename Context, typename ID>
|
||||
FMT_CONSTEXPR typename Context::format_arg get_arg(Context& ctx, ID id) {
|
||||
auto arg = ctx.arg(id);
|
||||
if (!arg) ctx.on_error("argument index out of range");
|
||||
if (!arg) ctx.on_error("argument not found");
|
||||
return arg;
|
||||
}
|
||||
|
||||
@ -2241,7 +2223,7 @@ class specs_handler : public specs_setter<typename Context::char_type> {
|
||||
|
||||
FMT_CONSTEXPR format_arg get_arg(basic_string_view<char_type> arg_id) {
|
||||
parse_context_.check_arg_id(arg_id);
|
||||
return context_.arg(arg_id);
|
||||
return internal::get_arg(context_, arg_id);
|
||||
}
|
||||
|
||||
ParseContext& parse_context_;
|
||||
@ -2682,7 +2664,7 @@ class format_string_checker {
|
||||
enum { num_args = sizeof...(Args) };
|
||||
|
||||
FMT_CONSTEXPR void check_arg_id() {
|
||||
if (arg_id_ >= num_args) context_.on_error("argument index out of range");
|
||||
if (arg_id_ >= num_args) context_.on_error("argument not found");
|
||||
}
|
||||
|
||||
// Format specifier parsing function.
|
||||
@ -3127,16 +3109,6 @@ template <typename Char = char> class dynamic_formatter {
|
||||
const Char* format_str_;
|
||||
};
|
||||
|
||||
template <typename Range, typename Char>
|
||||
typename basic_format_context<Range, Char>::format_arg
|
||||
basic_format_context<Range, Char>::arg(basic_string_view<char_type> name) {
|
||||
map_.init(args_);
|
||||
format_arg arg = map_.find(name);
|
||||
if (arg.type() == internal::type::none_type)
|
||||
this->on_error("argument not found");
|
||||
return arg;
|
||||
}
|
||||
|
||||
template <typename Char, typename ErrorHandler>
|
||||
FMT_CONSTEXPR void advance_to(
|
||||
basic_format_parse_context<Char, ErrorHandler>& ctx, const Char* p) {
|
||||
@ -3160,14 +3132,16 @@ struct format_handler : internal::error_handler {
|
||||
context.advance_to(out);
|
||||
}
|
||||
|
||||
void get_arg(int id) { arg = internal::get_arg(context, id); }
|
||||
template <typename ID> void get_arg(ID id) {
|
||||
arg = internal::get_arg(context, id);
|
||||
}
|
||||
|
||||
void on_arg_id() { get_arg(parse_context.next_arg_id()); }
|
||||
void on_arg_id(int id) {
|
||||
parse_context.check_arg_id(id);
|
||||
get_arg(id);
|
||||
}
|
||||
void on_arg_id(basic_string_view<Char> id) { arg = context.arg(id); }
|
||||
void on_arg_id(basic_string_view<Char> id) { get_arg(id); }
|
||||
|
||||
void on_replacement_field(const Char* p) {
|
||||
advance_to(parse_context, p);
|
||||
|
@ -476,7 +476,7 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
|
||||
|
||||
// Parse argument index, flags and width.
|
||||
int arg_index = parse_header(it, end, specs);
|
||||
if (arg_index == 0) on_error("argument index out of range");
|
||||
if (arg_index == 0) on_error("argument not found");
|
||||
|
||||
// Parse precision.
|
||||
if (it != end && *it == '.') {
|
||||
|
@ -114,6 +114,25 @@ char* sprintf_format(Double value, internal::buffer<char>& buf,
|
||||
}
|
||||
return decimal_point_pos;
|
||||
}
|
||||
|
||||
// This is deprecated and is kept only to preserve ABI compatibility.
|
||||
template <typename Context>
|
||||
void arg_map<Context>::init(const basic_format_args<Context>& args) {
|
||||
if (map_) return;
|
||||
map_ = new entry[internal::to_unsigned(args.max_size())];
|
||||
if (args.is_packed()) {
|
||||
for (int i = 0;; ++i) {
|
||||
internal::type arg_type = args.type(i);
|
||||
if (arg_type == internal::type::none_type) return;
|
||||
if (arg_type == internal::type::named_arg_type)
|
||||
push_back(args.values_[i]);
|
||||
}
|
||||
}
|
||||
for (int i = 0, n = args.max_size(); i < n; ++i) {
|
||||
auto type = args.args_[i].type_;
|
||||
if (type == internal::type::named_arg_type) push_back(args.args_[i].value_);
|
||||
}
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
template FMT_API char* internal::sprintf_format(double, internal::buffer<char>&,
|
||||
|
@ -456,28 +456,6 @@ TEST(FormatDynArgsTest, CustomFormat) {
|
||||
EXPECT_EQ("cust=0 and cust=1 and cust=3", result);
|
||||
}
|
||||
|
||||
TEST(FormatDynArgsTest, NamedArgByRef) {
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||
|
||||
// Note: fmt::arg() constructs an object which holds a reference
|
||||
// to its value. It's not an aggregate, so it doesn't extend the
|
||||
// reference lifetime. As a result, it's a very bad idea passing temporary
|
||||
// as a named argument value. Only GCC with optimization level >0
|
||||
// complains about this.
|
||||
//
|
||||
// A real life usecase is when you have both name and value alive
|
||||
// guarantee their lifetime and thus don't want them to be copied into
|
||||
// storages.
|
||||
int a1_val{42};
|
||||
auto a1 = fmt::arg("a1_", a1_val);
|
||||
store.push_back(std::cref(a1));
|
||||
|
||||
std::string result = fmt::vformat("{a1_}", // and {} and {}",
|
||||
store);
|
||||
|
||||
EXPECT_EQ("42", result);
|
||||
}
|
||||
|
||||
struct copy_throwable {
|
||||
copy_throwable() {}
|
||||
copy_throwable(const copy_throwable&) { throw "deal with it"; }
|
||||
|
@ -640,7 +640,7 @@ TEST(FormatterTest, ArgErrors) {
|
||||
EXPECT_THROW_MSG(format("{"), format_error, "invalid format string");
|
||||
EXPECT_THROW_MSG(format("{?}"), format_error, "invalid format string");
|
||||
EXPECT_THROW_MSG(format("{0"), format_error, "invalid format string");
|
||||
EXPECT_THROW_MSG(format("{0}"), format_error, "argument index out of range");
|
||||
EXPECT_THROW_MSG(format("{0}"), format_error, "argument not found");
|
||||
EXPECT_THROW_MSG(format("{00}", 42), format_error, "invalid format string");
|
||||
|
||||
char format_str[BUFFER_SIZE];
|
||||
@ -648,7 +648,7 @@ TEST(FormatterTest, ArgErrors) {
|
||||
EXPECT_THROW_MSG(format(format_str), format_error, "invalid format string");
|
||||
safe_sprintf(format_str, "{%u}", INT_MAX);
|
||||
EXPECT_THROW_MSG(format(format_str), format_error,
|
||||
"argument index out of range");
|
||||
"argument not found");
|
||||
|
||||
safe_sprintf(format_str, "{%u", INT_MAX + 1u);
|
||||
EXPECT_THROW_MSG(format(format_str), format_error, "number is too big");
|
||||
@ -673,13 +673,13 @@ template <> struct TestFormat<0> {
|
||||
TEST(FormatterTest, ManyArgs) {
|
||||
EXPECT_EQ("19", TestFormat<20>::format("{19}"));
|
||||
EXPECT_THROW_MSG(TestFormat<20>::format("{20}"), format_error,
|
||||
"argument index out of range");
|
||||
"argument not found");
|
||||
EXPECT_THROW_MSG(TestFormat<21>::format("{21}"), format_error,
|
||||
"argument index out of range");
|
||||
"argument not found");
|
||||
enum { max_packed_args = fmt::internal::max_packed_args };
|
||||
std::string format_str = fmt::format("{{{}}}", max_packed_args + 1);
|
||||
EXPECT_THROW_MSG(TestFormat<max_packed_args>::format(format_str),
|
||||
format_error, "argument index out of range");
|
||||
format_error, "argument not found");
|
||||
}
|
||||
|
||||
TEST(FormatterTest, NamedArg) {
|
||||
@ -708,7 +708,7 @@ TEST(FormatterTest, AutoArgIndex) {
|
||||
"cannot switch from manual to automatic argument indexing");
|
||||
EXPECT_THROW_MSG(format("{:.{0}}", 1.2345, 2), format_error,
|
||||
"cannot switch from automatic to manual argument indexing");
|
||||
EXPECT_THROW_MSG(format("{}"), format_error, "argument index out of range");
|
||||
EXPECT_THROW_MSG(format("{}"), format_error, "argument not found");
|
||||
}
|
||||
|
||||
TEST(FormatterTest, EmptySpecs) { EXPECT_EQ("42", format("{0:}", 42)); }
|
||||
@ -1012,7 +1012,7 @@ TEST(FormatterTest, RuntimeWidth) {
|
||||
"cannot switch from manual to automatic argument indexing");
|
||||
EXPECT_THROW_MSG(format("{0:{?}}", 0), format_error, "invalid format string");
|
||||
EXPECT_THROW_MSG(format("{0:{1}}", 0), format_error,
|
||||
"argument index out of range");
|
||||
"argument not found");
|
||||
|
||||
EXPECT_THROW_MSG(format("{0:{0:}}", 0), format_error,
|
||||
"invalid format string");
|
||||
@ -1161,7 +1161,7 @@ TEST(FormatterTest, RuntimePrecision) {
|
||||
EXPECT_THROW_MSG(format("{0:.{1}", 0, 0), format_error,
|
||||
"precision not allowed for this argument type");
|
||||
EXPECT_THROW_MSG(format("{0:.{1}}", 0), format_error,
|
||||
"argument index out of range");
|
||||
"argument not found");
|
||||
|
||||
EXPECT_THROW_MSG(format("{0:.{0:}}", 0), format_error,
|
||||
"invalid format string");
|
||||
@ -2441,7 +2441,7 @@ TEST(FormatTest, FormatStringErrors) {
|
||||
EXPECT_ERROR("{:{<}", "invalid fill character '{'", int);
|
||||
EXPECT_ERROR("{:10000000000}", "number is too big", int);
|
||||
EXPECT_ERROR("{:.10000000000}", "number is too big", int);
|
||||
EXPECT_ERROR_NOARGS("{:x}", "argument index out of range");
|
||||
EXPECT_ERROR_NOARGS("{:x}", "argument not found");
|
||||
# if FMT_NUMERIC_ALIGN
|
||||
EXPECT_ERROR("{0:=5", "unknown format specifier", int);
|
||||
EXPECT_ERROR("{:=}", "format specifier requires numeric argument",
|
||||
@ -2482,8 +2482,8 @@ TEST(FormatTest, FormatStringErrors) {
|
||||
EXPECT_ERROR("{:.{0x}}", "invalid format string", int);
|
||||
EXPECT_ERROR("{:.{-}}", "invalid format string", int);
|
||||
EXPECT_ERROR("{:.x}", "missing precision specifier", int);
|
||||
EXPECT_ERROR_NOARGS("{}", "argument index out of range");
|
||||
EXPECT_ERROR("{1}", "argument index out of range", int);
|
||||
EXPECT_ERROR_NOARGS("{}", "argument not found");
|
||||
EXPECT_ERROR("{1}", "argument not found", int);
|
||||
EXPECT_ERROR("{1}{}",
|
||||
"cannot switch from manual to automatic argument indexing", int,
|
||||
int);
|
||||
|
@ -113,14 +113,14 @@ TEST(PrintfTest, SwitchArgIndexing) {
|
||||
|
||||
TEST(PrintfTest, InvalidArgIndex) {
|
||||
EXPECT_THROW_MSG(test_sprintf("%0$d", 42), format_error,
|
||||
"argument index out of range");
|
||||
"argument not found");
|
||||
EXPECT_THROW_MSG(test_sprintf("%2$d", 42), format_error,
|
||||
"argument index out of range");
|
||||
"argument not found");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", INT_MAX), 42), format_error,
|
||||
"argument index out of range");
|
||||
"argument not found");
|
||||
|
||||
EXPECT_THROW_MSG(test_sprintf("%2$", 42), format_error,
|
||||
"argument index out of range");
|
||||
"argument not found");
|
||||
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM), 42), format_error,
|
||||
"number is too big");
|
||||
}
|
||||
@ -223,7 +223,7 @@ TEST(PrintfTest, DynamicWidth) {
|
||||
EXPECT_THROW_MSG(test_sprintf("%*d", 5.0, 42), format_error,
|
||||
"width is not integer");
|
||||
EXPECT_THROW_MSG(test_sprintf("%*d"), format_error,
|
||||
"argument index out of range");
|
||||
"argument not found");
|
||||
EXPECT_THROW_MSG(test_sprintf("%*d", BIG_NUM, 42), format_error,
|
||||
"number is too big");
|
||||
}
|
||||
@ -269,7 +269,7 @@ TEST(PrintfTest, DynamicPrecision) {
|
||||
EXPECT_THROW_MSG(test_sprintf("%.*d", 5.0, 42), format_error,
|
||||
"precision is not integer");
|
||||
EXPECT_THROW_MSG(test_sprintf("%.*d"), format_error,
|
||||
"argument index out of range");
|
||||
"argument not found");
|
||||
EXPECT_THROW_MSG(test_sprintf("%.*d", BIG_NUM, 42), format_error,
|
||||
"number is too big");
|
||||
if (sizeof(long long) != sizeof(int)) {
|
||||
|
Loading…
Reference in New Issue
Block a user