diff options
author | Dan Albert <danalbert@google.com> | 2015-05-21 18:37:36 -0700 |
---|---|---|
committer | Dan Albert <danalbert@google.com> | 2015-05-22 10:07:06 -0700 |
commit | e0da8a1d377c22d1956376302294ee988b44fd47 (patch) | |
tree | 0813d979ad3b68c1e0269f7caca54651b8933471 /base | |
parent | 3ff23e2461de5a5aae4343147486df84e8a77d90 (diff) | |
download | core-e0da8a1d377c22d1956376302294ee988b44fd47.tar.gz core-e0da8a1d377c22d1956376302294ee988b44fd47.tar.bz2 core-e0da8a1d377c22d1956376302294ee988b44fd47.zip |
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
Diffstat (limited to 'base')
-rw-r--r-- | base/include/base/strings.h | 22 | ||||
-rw-r--r-- | base/strings.cpp | 23 | ||||
-rw-r--r-- | base/strings_test.cpp | 13 |
3 files changed, 36 insertions, 22 deletions
diff --git a/base/include/base/strings.h b/base/include/base/strings.h index 5dbc5fbfb..638f845db 100644 --- a/base/include/base/strings.h +++ b/base/include/base/strings.h @@ -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); diff --git a/base/strings.cpp b/base/strings.cpp index d3375d9fa..bac983b01 100644 --- a/base/strings.cpp +++ b/base/strings.cpp @@ -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; diff --git a/base/strings_test.cpp b/base/strings_test.cpp index 46a1ab543..5f675750c 100644 --- a/base/strings_test.cpp +++ b/base/strings_test.cpp @@ -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("", "")); |