Add concat and concat_separated
Concat simply concatenates all arguments and will replace a single placeholder
with the concatenation. Example:
format("({})", concat("hello ", "world")) will result in "(hello world)"
concat_separated concatenates all arguments with a separator between them.
Example: format("({})", concat(", ", 1, 2, 3)) will result in "(1, 2, 3)"
This commit is contained in:
parent
7a9c1ba190
commit
f0ad179a13
79
fmt/format.h
79
fmt/format.h
@ -4085,6 +4085,85 @@ void format_arg(fmt::BasicFormatter<Char, ArgFormatter> &f,
|
||||
}
|
||||
format_str = end + 1;
|
||||
}
|
||||
|
||||
struct ArgConcatNoSeparator
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Char>
|
||||
struct ArgConcatSeparator {
|
||||
BasicCStringRef<Char> sep;
|
||||
//ArgConcatSeparator<Char>(const BasicCStringRef<Char> &sep): sep(sep) {}
|
||||
};
|
||||
|
||||
template<typename Separator, typename ...Args>
|
||||
struct ArgConcat: public Separator {
|
||||
std::tuple<Args...> a;
|
||||
ArgConcat(const Separator &sep, Args&&...args):
|
||||
Separator(sep), a(std::forward<Args>(args)...){
|
||||
}
|
||||
|
||||
template<std::size_t I, typename Char, typename ArgFormatter>
|
||||
std::enable_if_t<I == sizeof...(Args), void>
|
||||
format(fmt::BasicFormatter<Char, ArgFormatter> &,
|
||||
const Char *&) const {
|
||||
}
|
||||
|
||||
template<std::size_t I, typename Char, typename ArgFormatter>
|
||||
std::enable_if_t<I < sizeof...(Args) &&
|
||||
std::is_same<Separator, ArgConcatNoSeparator>::value, void>
|
||||
format(fmt::BasicFormatter<Char, ArgFormatter> &f,
|
||||
const Char *&format_str) const {
|
||||
const Char* save = format_str;
|
||||
f.format(format_str,
|
||||
internal::MakeArg<fmt::BasicFormatter<Char, ArgFormatter> >(std::get<I>(a)));
|
||||
format<I+1>(f, save);
|
||||
}
|
||||
|
||||
template<std::size_t I, typename Char, typename ArgFormatter>
|
||||
std::enable_if_t<I < sizeof...(Args) &&
|
||||
std::is_same<Separator,ArgConcatSeparator<Char>>::value, void>
|
||||
format(fmt::BasicFormatter<Char, ArgFormatter> &f,
|
||||
const Char *&format_str) const {
|
||||
const Char* save = format_str;
|
||||
if(I != 0) {
|
||||
f.writer().write(Separator::sep);
|
||||
}
|
||||
f.format(format_str,
|
||||
internal::MakeArg<fmt::BasicFormatter<Char, ArgFormatter> >(std::get<I>(a)));
|
||||
format<I+1>(f, save);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ...Args>
|
||||
ArgConcat<ArgConcatNoSeparator, Args...> concat(Args&&...args) {
|
||||
return ArgConcat<ArgConcatNoSeparator, Args...>{ArgConcatNoSeparator{}, std::forward<Args>(args)...};
|
||||
}
|
||||
|
||||
template<typename ...Args>
|
||||
ArgConcat<ArgConcatSeparator<char>, Args...> concat_separated(const BasicCStringRef<char> &sep, Args&&...args) {
|
||||
return ArgConcat<ArgConcatSeparator<char>, Args...>{ArgConcatSeparator<char>{sep}, std::forward<Args>(args)...};
|
||||
}
|
||||
|
||||
template<typename ...Args>
|
||||
ArgConcat<ArgConcatSeparator<wchar_t>, Args...> concat_separated(const BasicCStringRef<wchar_t> &sep, Args&&...args) {
|
||||
return ArgConcat<ArgConcatSeparator<wchar_t>, Args...>{ArgConcatSeparator<wchar_t>{sep}, std::forward<Args>(args)...};
|
||||
}
|
||||
|
||||
template<typename ArgFormatter, typename Char, typename Separator, typename ...Args>
|
||||
void format_arg(fmt::BasicFormatter<Char, ArgFormatter> &f,
|
||||
const Char *&format_str, const ArgConcat<Separator, Args...> &e) {
|
||||
const Char* end = format_str;
|
||||
if (*end == ':')
|
||||
++end;
|
||||
while (*end && *end != '}')
|
||||
++end;
|
||||
if (*end != '}')
|
||||
FMT_THROW(FormatError("missing '}' in format string"));
|
||||
|
||||
e.format<0>(f, format_str);
|
||||
format_str = end + 1;
|
||||
}
|
||||
} // namespace fmt
|
||||
|
||||
#if FMT_USE_USER_DEFINED_LITERALS
|
||||
|
||||
@ -1604,6 +1604,30 @@ TEST(FormatTest, JoinArg) {
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(FormatTest, ConcatArg) {
|
||||
using fmt::concat;
|
||||
EXPECT_EQ("123", format("{}", concat(1,2,3)));
|
||||
EXPECT_EQ("()", format("({})", concat()));
|
||||
EXPECT_EQ("(001002003)", format("({:03})", concat(1,2,3)));
|
||||
EXPECT_EQ("(1 hello world 2)", format("({})", concat(1," hello"," world ", 2)));
|
||||
EXPECT_EQ("(1 hello world 2)", format("({}{})", concat(1," hello"," world "), 2));
|
||||
EXPECT_EQ("(+01.20+03.40)", format("({:+06.2f})", concat(1.2f, 3.4f)));
|
||||
|
||||
EXPECT_EQ(L"(1, 2, 3)", format(L"({})", concat(1, L", ", 2, L", ", 3)));
|
||||
}
|
||||
|
||||
TEST(FormatTest, ConcatSeparatedArg) {
|
||||
using fmt::concat_separated;
|
||||
EXPECT_EQ("(1, 2, 3)", format("({})", concat_separated(", ", 1,2,3)));
|
||||
EXPECT_EQ("()", format("({})", concat_separated(", ")));
|
||||
EXPECT_EQ("(001, 002, 003)", format("({:03})", concat_separated(", ", 1,2,3)));
|
||||
EXPECT_EQ("(1 hello world 2)", format("({})", concat_separated(" ", 1,"hello","world", 2)));
|
||||
EXPECT_EQ("(1 hello world 2)", format("({} {})", concat_separated(" ", 1,"hello","world"), 2));
|
||||
EXPECT_EQ("(+01.20, +03.40)", format("({:+06.2f})", concat_separated(", ", 1.2f, 3.4f)));
|
||||
|
||||
EXPECT_EQ(L"(1, 2, 3)", format(L"({})", concat_separated(L", ", 1, 2, 3)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string str(const T &value) {
|
||||
return fmt::format("{}", value);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user