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(""));
 }