Add llvm::join_items to StringExtras.
llvm::join_items is similar to llvm::join, which produces a string by concatenating a sequence of values together separated by a given separator. But it differs in that the arguments to llvm::join() are same-type members of a container, whereas the arguments to llvm::join_items are arbitrary types passed into a variadic template. The only requirement on parameters to llvm::join_items (including for the separator themselves) is that they be implicitly convertible to std::string or have an overload of std::string::operator+ Differential Revision: https://reviews.llvm.org/D24880 llvm-svn: 282502
This commit is contained in:
parent
1280004d5e
commit
0e31a38418
|
@ -155,6 +155,8 @@ static inline StringRef getOrdinalSuffix(unsigned Val) {
|
|||
/// it if it is not printable or if it is an escape char.
|
||||
void PrintEscapedString(StringRef Name, raw_ostream &Out);
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename IteratorT>
|
||||
inline std::string join_impl(IteratorT Begin, IteratorT End,
|
||||
StringRef Separator, std::input_iterator_tag) {
|
||||
|
@ -189,12 +191,64 @@ inline std::string join_impl(IteratorT Begin, IteratorT End,
|
|||
return S;
|
||||
}
|
||||
|
||||
template <typename Sep>
|
||||
inline void join_items_impl(std::string &Result, Sep Separator) {}
|
||||
|
||||
template <typename Sep, typename Arg>
|
||||
inline void join_items_impl(std::string &Result, Sep Separator,
|
||||
const Arg &Item) {
|
||||
Result += Item;
|
||||
}
|
||||
|
||||
template <typename Sep, typename Arg1, typename... Args>
|
||||
inline void join_items_impl(std::string &Result, Sep Separator, const Arg1 &A1,
|
||||
Args &&... Items) {
|
||||
Result += A1;
|
||||
Result += Separator;
|
||||
join_items_impl(Result, Separator, std::forward<Args>(Items)...);
|
||||
}
|
||||
|
||||
inline size_t join_one_item_size(char C) { return 1; }
|
||||
inline size_t join_one_item_size(const char *S) { return S ? ::strlen(S) : 0; }
|
||||
|
||||
template <typename T> inline size_t join_one_item_size(const T &Str) {
|
||||
return Str.size();
|
||||
}
|
||||
|
||||
inline size_t join_items_size() { return 0; }
|
||||
|
||||
template <typename A1> inline size_t join_items_size(const A1 &A) {
|
||||
return join_one_item_size(A);
|
||||
}
|
||||
template <typename A1, typename... Args>
|
||||
inline size_t join_items_size(const A1 &A, Args &&... Items) {
|
||||
return join_one_item_size(A) + join_items_size(std::forward<Args>(Items)...);
|
||||
}
|
||||
}
|
||||
|
||||
/// Joins the strings in the range [Begin, End), adding Separator between
|
||||
/// the elements.
|
||||
template <typename IteratorT>
|
||||
inline std::string join(IteratorT Begin, IteratorT End, StringRef Separator) {
|
||||
typedef typename std::iterator_traits<IteratorT>::iterator_category tag;
|
||||
return join_impl(Begin, End, Separator, tag());
|
||||
return detail::join_impl(Begin, End, Separator, tag());
|
||||
}
|
||||
|
||||
/// Joins the strings in the parameter pack \p Items, adding \p Separator
|
||||
/// between the elements. All arguments must be implicitly convertible to
|
||||
/// std::string, or there should be an overload of std::string::operator+=()
|
||||
/// that accepts the argument explicitly.
|
||||
template <typename Sep, typename... Args>
|
||||
inline std::string join_items(Sep Separator, Args &&... Items) {
|
||||
std::string Result;
|
||||
if (sizeof...(Items) == 0)
|
||||
return Result;
|
||||
|
||||
size_t NS = detail::join_one_item_size(Separator);
|
||||
size_t NI = detail::join_items_size(std::forward<Args>(Items)...);
|
||||
Result.reserve(NI + (sizeof...(Items) - 1) * NS + 1);
|
||||
detail::join_items_impl(Result, Separator, std::forward<Args>(Items)...);
|
||||
return Result;
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
||||
|
|
|
@ -53,6 +53,7 @@ set(ADTSources
|
|||
SparseBitVectorTest.cpp
|
||||
SparseMultiSetTest.cpp
|
||||
SparseSetTest.cpp
|
||||
StringExtrasTest.cpp
|
||||
StringMapTest.cpp
|
||||
StringRefTest.cpp
|
||||
TinyPtrVectorTest.cpp
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
//===- StringExtrasTest.cpp - Unit tests for String extras ----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
TEST(StringExtrasTest, Join) {
|
||||
std::vector<std::string> Items;
|
||||
EXPECT_EQ("", join(Items.begin(), Items.end(), " <sep> "));
|
||||
|
||||
Items = {"foo"};
|
||||
EXPECT_EQ("foo", join(Items.begin(), Items.end(), " <sep> "));
|
||||
|
||||
Items = {"foo", "bar"};
|
||||
EXPECT_EQ("foo <sep> bar", join(Items.begin(), Items.end(), " <sep> "));
|
||||
|
||||
Items = {"foo", "bar", "baz"};
|
||||
EXPECT_EQ("foo <sep> bar <sep> baz",
|
||||
join(Items.begin(), Items.end(), " <sep> "));
|
||||
}
|
||||
|
||||
TEST(StringExtrasTest, JoinItems) {
|
||||
const char *Foo = "foo";
|
||||
std::string Bar = "bar";
|
||||
llvm::StringRef Baz = "baz";
|
||||
char X = 'x';
|
||||
|
||||
EXPECT_EQ("", join_items(" <sep> "));
|
||||
EXPECT_EQ("", join_items('/'));
|
||||
|
||||
EXPECT_EQ("foo", join_items(" <sep> ", Foo));
|
||||
EXPECT_EQ("foo", join_items('/', Foo));
|
||||
|
||||
EXPECT_EQ("foo <sep> bar", join_items(" <sep> ", Foo, Bar));
|
||||
EXPECT_EQ("foo/bar", join_items('/', Foo, Bar));
|
||||
|
||||
EXPECT_EQ("foo <sep> bar <sep> baz", join_items(" <sep> ", Foo, Bar, Baz));
|
||||
EXPECT_EQ("foo/bar/baz", join_items('/', Foo, Bar, Baz));
|
||||
|
||||
EXPECT_EQ("foo <sep> bar <sep> baz <sep> x",
|
||||
join_items(" <sep> ", Foo, Bar, Baz, X));
|
||||
|
||||
EXPECT_EQ("foo/bar/baz/x", join_items('/', Foo, Bar, Baz, X));
|
||||
}
|
Loading…
Reference in New Issue