Snap for 8076125 from b57e1d16a9ec0030526102da30dc1395c2f71f83 to mainline-resolv-release
Change-Id: I32a45416c5f42f6e24cafedc4fded229a7383fbc
diff --git a/include/android-base/strings.h b/include/android-base/strings.h
index 14d534a..95d6077 100644
--- a/include/android-base/strings.h
+++ b/include/android-base/strings.h
@@ -32,6 +32,20 @@
std::vector<std::string> Split(const std::string& s,
const std::string& delimiters);
+// Splits a string into a vector of string tokens.
+//
+// The string is split at each occurrence of a character in delimiters.
+// Coalesce runs of delimiter bytes and ignore delimiter bytes at the start or
+// end of string. In other words, return only nonempty string tokens.
+// Use when you don't care about recovering the original string with Join().
+//
+// Example:
+// Tokenize(" foo bar ", " ") => {"foo", "bar"}
+// Join(Tokenize(" foo bar", " "), " ") => "foo bar"
+//
+// The empty string is not a valid delimiter list.
+std::vector<std::string> Tokenize(const std::string& s, const std::string& delimiters);
+
// Trims whitespace off both ends of the given string.
std::string Trim(const std::string& s);
diff --git a/strings.cpp b/strings.cpp
index 40b2bf2..8f3c7d9 100644
--- a/strings.cpp
+++ b/strings.cpp
@@ -46,6 +46,23 @@
return result;
}
+std::vector<std::string> Tokenize(const std::string& s, const std::string& delimiters) {
+ CHECK_NE(delimiters.size(), 0U);
+
+ std::vector<std::string> result;
+ size_t end = 0;
+
+ while (true) {
+ size_t base = s.find_first_not_of(delimiters, end);
+ if (base == s.npos) {
+ break;
+ }
+ end = s.find_first_of(delimiters, base);
+ result.push_back(s.substr(base, end - base));
+ }
+ return result;
+}
+
std::string Trim(const std::string& s) {
std::string result;
diff --git a/strings_test.cpp b/strings_test.cpp
index 5ae3094..7a57489 100644
--- a/strings_test.cpp
+++ b/strings_test.cpp
@@ -83,6 +83,52 @@
ASSERT_EQ("bar", parts[2]);
}
+TEST(strings, tokenize_empty) {
+ std::vector<std::string> parts = android::base::Tokenize("", " ");
+ ASSERT_EQ(0U, parts.size());
+}
+
+TEST(strings, tokenize_all_delimiter) {
+ std::vector<std::string> parts = android::base::Tokenize(" \t ", " \t");
+ ASSERT_EQ(0U, parts.size());
+}
+
+TEST(strings, tokenize_trivial) {
+ std::vector<std::string> parts = android::base::Tokenize("foo", "\t");
+ ASSERT_EQ(1U, parts.size());
+ ASSERT_EQ("foo", parts[0]);
+}
+
+TEST(strings, tokenize_single) {
+ std::vector<std::string> parts = android::base::Tokenize("foo\t", "\t");
+ ASSERT_EQ(1U, parts.size());
+ ASSERT_EQ("foo", parts[0]);
+}
+
+TEST(strings, tokenize_simple) {
+ std::vector<std::string> parts = android::base::Tokenize("foo bar baz", " ");
+ ASSERT_EQ(3U, parts.size());
+ ASSERT_EQ("foo", parts[0]);
+ ASSERT_EQ("bar", parts[1]);
+ ASSERT_EQ("baz", parts[2]);
+}
+
+TEST(strings, tokenize_any) {
+ std::vector<std::string> parts = android::base::Tokenize("foo \tbar\t\t baz", " \t");
+ ASSERT_EQ(3U, parts.size());
+ ASSERT_EQ("foo", parts[0]);
+ ASSERT_EQ("bar", parts[1]);
+ ASSERT_EQ("baz", parts[2]);
+}
+
+TEST(strings, tokenize_beginning_trailing_delimiters) {
+ std::vector<std::string> parts = android::base::Tokenize(" foo bar baz \t", " \t");
+ ASSERT_EQ(3U, parts.size());
+ ASSERT_EQ("foo", parts[0]);
+ ASSERT_EQ("bar", parts[1]);
+ ASSERT_EQ("baz", parts[2]);
+}
+
TEST(strings, trim_empty) {
ASSERT_EQ("", android::base::Trim(""));
}