Generalize Join to work for any container/element.
This is more scalable than explicitly instantiating templates for the cross product of containers and element types. Specifically I'm adding this so I can join an unordered_set in adb. Change-Id: I0055f3390a0ff26a886a0d41bbf0d4fe3d210f9c
This commit is contained in:
parent
3ff23e2461
commit
e0da8a1d37
|
@ -17,6 +17,7 @@
|
|||
#ifndef BASE_STRINGS_H
|
||||
#define BASE_STRINGS_H
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -34,9 +35,24 @@ std::vector<std::string> Split(const std::string& s,
|
|||
// Trims whitespace off both ends of the given string.
|
||||
std::string Trim(const std::string& s);
|
||||
|
||||
// Joins a vector of strings into a single string, using the given separator.
|
||||
template <typename StringT>
|
||||
std::string Join(const std::vector<StringT>& strings, char separator);
|
||||
// Joins a container of things into a single string, using the given separator.
|
||||
template <typename ContainerT>
|
||||
std::string Join(const ContainerT& things, char separator) {
|
||||
if (things.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::ostringstream result;
|
||||
result << *things.begin();
|
||||
for (auto it = std::next(things.begin()); it != things.end(); ++it) {
|
||||
result << separator << *it;
|
||||
}
|
||||
return result.str();
|
||||
}
|
||||
|
||||
// We instantiate the common cases in strings.cpp.
|
||||
extern template std::string Join(const std::vector<std::string>&, char);
|
||||
extern template std::string Join(const std::vector<const char*>&, char);
|
||||
|
||||
// Tests whether 's' starts with 'prefix'.
|
||||
bool StartsWith(const std::string& s, const char* prefix);
|
||||
|
|
|
@ -79,25 +79,10 @@ std::string Trim(const std::string& s) {
|
|||
return s.substr(start_index, end_index - start_index + 1);
|
||||
}
|
||||
|
||||
template <typename StringT>
|
||||
std::string Join(const std::vector<StringT>& strings, char separator) {
|
||||
if (strings.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string result(strings[0]);
|
||||
for (size_t i = 1; i < strings.size(); ++i) {
|
||||
result += separator;
|
||||
result += strings[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Explicit instantiations.
|
||||
template std::string Join<std::string>(const std::vector<std::string>& strings,
|
||||
char separator);
|
||||
template std::string Join<const char*>(const std::vector<const char*>& strings,
|
||||
char separator);
|
||||
// These cases are probably the norm, so we mark them extern in the header to
|
||||
// aid compile time and binary size.
|
||||
template std::string Join(const std::vector<std::string>&, char);
|
||||
template std::string Join(const std::vector<const char*>&, char);
|
||||
|
||||
bool StartsWith(const std::string& s, const char* prefix) {
|
||||
return s.compare(0, strlen(prefix), prefix) == 0;
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
|
||||
TEST(strings, split_empty) {
|
||||
std::vector<std::string> parts = android::base::Split("", ",");
|
||||
|
@ -121,6 +123,17 @@ TEST(strings, join_separator_in_vector) {
|
|||
ASSERT_EQ(",,,", android::base::Join(list, ','));
|
||||
}
|
||||
|
||||
TEST(strings, join_simple_ints) {
|
||||
std::set<int> list = {1, 2, 3};
|
||||
ASSERT_EQ("1,2,3", android::base::Join(list, ','));
|
||||
}
|
||||
|
||||
TEST(strings, join_unordered_set) {
|
||||
std::unordered_set<int> list = {1, 2};
|
||||
ASSERT_TRUE("1,2" == android::base::Join(list, ',') ||
|
||||
"2,1" == android::base::Join(list, ','));
|
||||
}
|
||||
|
||||
TEST(strings, startswith_empty) {
|
||||
ASSERT_FALSE(android::base::StartsWith("", "foo"));
|
||||
ASSERT_TRUE(android::base::StartsWith("", ""));
|
||||
|
|
Loading…
Reference in New Issue