Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit b93468a

Browse files
author
Zachary Turner
committed
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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@282502 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 09e2479 commit b93468a

File tree

3 files changed

+108
-1
lines changed

3 files changed

+108
-1
lines changed

include/llvm/ADT/StringExtras.h

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ static inline StringRef getOrdinalSuffix(unsigned Val) {
155155
/// it if it is not printable or if it is an escape char.
156156
void PrintEscapedString(StringRef Name, raw_ostream &Out);
157157

158+
namespace detail {
159+
158160
template <typename IteratorT>
159161
inline std::string join_impl(IteratorT Begin, IteratorT End,
160162
StringRef Separator, std::input_iterator_tag) {
@@ -189,12 +191,64 @@ inline std::string join_impl(IteratorT Begin, IteratorT End,
189191
return S;
190192
}
191193

194+
template <typename Sep>
195+
inline void join_items_impl(std::string &Result, Sep Separator) {}
196+
197+
template <typename Sep, typename Arg>
198+
inline void join_items_impl(std::string &Result, Sep Separator,
199+
const Arg &Item) {
200+
Result += Item;
201+
}
202+
203+
template <typename Sep, typename Arg1, typename... Args>
204+
inline void join_items_impl(std::string &Result, Sep Separator, const Arg1 &A1,
205+
Args &&... Items) {
206+
Result += A1;
207+
Result += Separator;
208+
join_items_impl(Result, Separator, std::forward<Args>(Items)...);
209+
}
210+
211+
inline size_t join_one_item_size(char C) { return 1; }
212+
inline size_t join_one_item_size(const char *S) { return S ? ::strlen(S) : 0; }
213+
214+
template <typename T> inline size_t join_one_item_size(const T &Str) {
215+
return Str.size();
216+
}
217+
218+
inline size_t join_items_size() { return 0; }
219+
220+
template <typename A1> inline size_t join_items_size(const A1 &A) {
221+
return join_one_item_size(A);
222+
}
223+
template <typename A1, typename... Args>
224+
inline size_t join_items_size(const A1 &A, Args &&... Items) {
225+
return join_one_item_size(A) + join_items_size(std::forward<Args>(Items)...);
226+
}
227+
}
228+
192229
/// Joins the strings in the range [Begin, End), adding Separator between
193230
/// the elements.
194231
template <typename IteratorT>
195232
inline std::string join(IteratorT Begin, IteratorT End, StringRef Separator) {
196233
typedef typename std::iterator_traits<IteratorT>::iterator_category tag;
197-
return join_impl(Begin, End, Separator, tag());
234+
return detail::join_impl(Begin, End, Separator, tag());
235+
}
236+
237+
/// Joins the strings in the parameter pack \p Items, adding \p Separator
238+
/// between the elements. All arguments must be implicitly convertible to
239+
/// std::string, or there should be an overload of std::string::operator+=()
240+
/// that accepts the argument explicitly.
241+
template <typename Sep, typename... Args>
242+
inline std::string join_items(Sep Separator, Args &&... Items) {
243+
std::string Result;
244+
if (sizeof...(Items) == 0)
245+
return Result;
246+
247+
size_t NS = detail::join_one_item_size(Separator);
248+
size_t NI = detail::join_items_size(std::forward<Args>(Items)...);
249+
Result.reserve(NI + (sizeof...(Items) - 1) * NS + 1);
250+
detail::join_items_impl(Result, Separator, std::forward<Args>(Items)...);
251+
return Result;
198252
}
199253

200254
} // End llvm namespace

unittests/ADT/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ set(ADTSources
5353
SparseBitVectorTest.cpp
5454
SparseMultiSetTest.cpp
5555
SparseSetTest.cpp
56+
StringExtrasTest.cpp
5657
StringMapTest.cpp
5758
StringRefTest.cpp
5859
TinyPtrVectorTest.cpp

unittests/ADT/StringExtrasTest.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//===- StringExtrasTest.cpp - Unit tests for String extras ----------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "llvm/ADT/StringExtras.h"
11+
#include "gtest/gtest.h"
12+
13+
using namespace llvm;
14+
15+
TEST(StringExtrasTest, Join) {
16+
std::vector<std::string> Items;
17+
EXPECT_EQ("", join(Items.begin(), Items.end(), " <sep> "));
18+
19+
Items = {"foo"};
20+
EXPECT_EQ("foo", join(Items.begin(), Items.end(), " <sep> "));
21+
22+
Items = {"foo", "bar"};
23+
EXPECT_EQ("foo <sep> bar", join(Items.begin(), Items.end(), " <sep> "));
24+
25+
Items = {"foo", "bar", "baz"};
26+
EXPECT_EQ("foo <sep> bar <sep> baz",
27+
join(Items.begin(), Items.end(), " <sep> "));
28+
}
29+
30+
TEST(StringExtrasTest, JoinItems) {
31+
const char *Foo = "foo";
32+
std::string Bar = "bar";
33+
llvm::StringRef Baz = "baz";
34+
char X = 'x';
35+
36+
EXPECT_EQ("", join_items(" <sep> "));
37+
EXPECT_EQ("", join_items('/'));
38+
39+
EXPECT_EQ("foo", join_items(" <sep> ", Foo));
40+
EXPECT_EQ("foo", join_items('/', Foo));
41+
42+
EXPECT_EQ("foo <sep> bar", join_items(" <sep> ", Foo, Bar));
43+
EXPECT_EQ("foo/bar", join_items('/', Foo, Bar));
44+
45+
EXPECT_EQ("foo <sep> bar <sep> baz", join_items(" <sep> ", Foo, Bar, Baz));
46+
EXPECT_EQ("foo/bar/baz", join_items('/', Foo, Bar, Baz));
47+
48+
EXPECT_EQ("foo <sep> bar <sep> baz <sep> x",
49+
join_items(" <sep> ", Foo, Bar, Baz, X));
50+
51+
EXPECT_EQ("foo/bar/baz/x", join_items('/', Foo, Bar, Baz, X));
52+
}

0 commit comments

Comments
 (0)