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:
Andreas Wass 2017-11-02 09:24:01 +01:00
parent 7a9c1ba190
commit f0ad179a13
2 changed files with 103 additions and 0 deletions

View File

@ -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

View File

@ -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);