Fix handling of types with to_string_view and formatter specialization (#2180)
This commit is contained in:
parent
a6408a3b09
commit
6ae402fd0b
@ -95,7 +95,9 @@ class dynamic_format_arg_store
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using stored_type = conditional_t<detail::is_string<T>::value,
|
using stored_type = conditional_t<detail::is_string<T>::value &&
|
||||||
|
!has_formatter<T, Context>::value &&
|
||||||
|
!detail::is_reference_wrapper<T>::value,
|
||||||
std::basic_string<char_type>, T>;
|
std::basic_string<char_type>, T>;
|
||||||
|
|
||||||
// Storage of basic_format_arg must be contiguous.
|
// Storage of basic_format_arg must be contiguous.
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#include "gmock.h"
|
#include "gmock.h"
|
||||||
|
|
||||||
TEST(ArgsTest, Basic) {
|
TEST(ArgsTest, Basic) {
|
||||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||||
store.push_back(42);
|
store.push_back(42);
|
||||||
store.push_back("abc1");
|
store.push_back("abc1");
|
||||||
store.push_back(1.5f);
|
store.push_back(1.5f);
|
||||||
@ -19,14 +19,14 @@ TEST(ArgsTest, Basic) {
|
|||||||
|
|
||||||
TEST(ArgsTest, StringsAndRefs) {
|
TEST(ArgsTest, StringsAndRefs) {
|
||||||
// Unfortunately the tests are compiled with old ABI so strings use COW.
|
// Unfortunately the tests are compiled with old ABI so strings use COW.
|
||||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||||
char str[] = "1234567890";
|
char str[] = "1234567890";
|
||||||
store.push_back(str);
|
store.push_back(str);
|
||||||
store.push_back(std::cref(str));
|
store.push_back(std::cref(str));
|
||||||
store.push_back(fmt::string_view{str});
|
store.push_back(fmt::string_view{str});
|
||||||
str[0] = 'X';
|
str[0] = 'X';
|
||||||
|
|
||||||
std::string result = fmt::vformat("{} and {} and {}", store);
|
auto result = fmt::vformat("{} and {} and {}", store);
|
||||||
EXPECT_EQ("1234567890 and X234567890 and X234567890", result);
|
EXPECT_EQ("1234567890 and X234567890 and X234567890", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,27 +48,52 @@ template <> struct formatter<custom_type> {
|
|||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
TEST(ArgsTest, CustomFormat) {
|
TEST(ArgsTest, CustomFormat) {
|
||||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||||
custom_type c{};
|
auto c = custom_type();
|
||||||
store.push_back(c);
|
store.push_back(c);
|
||||||
++c.i;
|
++c.i;
|
||||||
store.push_back(c);
|
store.push_back(c);
|
||||||
++c.i;
|
++c.i;
|
||||||
store.push_back(std::cref(c));
|
store.push_back(std::cref(c));
|
||||||
++c.i;
|
++c.i;
|
||||||
std::string result = fmt::vformat("{} and {} and {}", store);
|
auto result = fmt::vformat("{} and {} and {}", store);
|
||||||
EXPECT_EQ("cust=0 and cust=1 and cust=3", result);
|
EXPECT_EQ("cust=0 and cust=1 and cust=3", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct to_stringable {
|
||||||
|
friend fmt::string_view to_string_view(to_stringable) { return {}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
template <> struct formatter<to_stringable> {
|
||||||
|
auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const to_stringable&, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||||
|
return ctx.out();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
TEST(ArgsTest, ToStringAndFormatter) {
|
||||||
|
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||||
|
auto s = to_stringable();
|
||||||
|
store.push_back(s);
|
||||||
|
store.push_back(std::cref(s));
|
||||||
|
fmt::vformat("", store);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ArgsTest, NamedInt) {
|
TEST(ArgsTest, NamedInt) {
|
||||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||||
store.push_back(fmt::arg("a1", 42));
|
store.push_back(fmt::arg("a1", 42));
|
||||||
EXPECT_EQ("42", fmt::vformat("{a1}", store));
|
EXPECT_EQ("42", fmt::vformat("{a1}", store));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ArgsTest, NamedStrings) {
|
TEST(ArgsTest, NamedStrings) {
|
||||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||||
char str[]{"1234567890"};
|
char str[] = "1234567890";
|
||||||
store.push_back(fmt::arg("a1", str));
|
store.push_back(fmt::arg("a1", str));
|
||||||
store.push_back(fmt::arg("a2", std::cref(str)));
|
store.push_back(fmt::arg("a2", std::cref(str)));
|
||||||
str[0] = 'X';
|
str[0] = 'X';
|
||||||
@ -76,7 +101,7 @@ TEST(ArgsTest, NamedStrings) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ArgsTest, NamedArgByRef) {
|
TEST(ArgsTest, NamedArgByRef) {
|
||||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||||
char band[] = "Rolling Stones";
|
char band[] = "Rolling Stones";
|
||||||
store.push_back(fmt::arg("band", std::cref(band)));
|
store.push_back(fmt::arg("band", std::cref(band)));
|
||||||
band[9] = 'c'; // Changing band affects the output.
|
band[9] = 'c'; // Changing band affects the output.
|
||||||
@ -84,23 +109,23 @@ TEST(ArgsTest, NamedArgByRef) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ArgsTest, NamedCustomFormat) {
|
TEST(ArgsTest, NamedCustomFormat) {
|
||||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||||
custom_type c{};
|
auto c = custom_type();
|
||||||
store.push_back(fmt::arg("c1", c));
|
store.push_back(fmt::arg("c1", c));
|
||||||
++c.i;
|
++c.i;
|
||||||
store.push_back(fmt::arg("c2", c));
|
store.push_back(fmt::arg("c2", c));
|
||||||
++c.i;
|
++c.i;
|
||||||
store.push_back(fmt::arg("c_ref", std::cref(c)));
|
store.push_back(fmt::arg("c_ref", std::cref(c)));
|
||||||
++c.i;
|
++c.i;
|
||||||
std::string result = fmt::vformat("{c1} and {c2} and {c_ref}", store);
|
auto result = fmt::vformat("{c1} and {c2} and {c_ref}", store);
|
||||||
EXPECT_EQ("cust=0 and cust=1 and cust=3", result);
|
EXPECT_EQ("cust=0 and cust=1 and cust=3", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ArgsTest, Clear) {
|
TEST(ArgsTest, Clear) {
|
||||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||||
store.push_back(42);
|
store.push_back(42);
|
||||||
|
|
||||||
std::string result = fmt::vformat("{}", store);
|
auto result = fmt::vformat("{}", store);
|
||||||
EXPECT_EQ("42", result);
|
EXPECT_EQ("42", result);
|
||||||
|
|
||||||
store.push_back(43);
|
store.push_back(43);
|
||||||
@ -114,11 +139,11 @@ TEST(ArgsTest, Clear) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ArgsTest, Reserve) {
|
TEST(ArgsTest, Reserve) {
|
||||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||||
store.reserve(2, 1);
|
store.reserve(2, 1);
|
||||||
store.push_back(1.5f);
|
store.push_back(1.5f);
|
||||||
store.push_back(fmt::arg("a1", 42));
|
store.push_back(fmt::arg("a1", 42));
|
||||||
std::string result = fmt::vformat("{a1} and {}", store);
|
auto result = fmt::vformat("{a1} and {}", store);
|
||||||
EXPECT_EQ("42 and 1.5", result);
|
EXPECT_EQ("42 and 1.5", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +164,7 @@ template <> struct formatter<copy_throwable> {
|
|||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
TEST(ArgsTest, ThrowOnCopy) {
|
TEST(ArgsTest, ThrowOnCopy) {
|
||||||
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
||||||
store.push_back(std::string("foo"));
|
store.push_back(std::string("foo"));
|
||||||
try {
|
try {
|
||||||
store.push_back(copy_throwable());
|
store.push_back(copy_throwable());
|
||||||
|
Loading…
Reference in New Issue
Block a user