Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e0da8a1d authored by Dan Albert's avatar Dan Albert
Browse files

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
parent 3ff23e24
Loading
Loading
Loading
Loading
+19 −3
Original line number Diff line number Diff line
@@ -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);
+4 −19
Original line number Diff line number Diff line
@@ -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;
+13 −0
Original line number Diff line number Diff line
@@ -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("", ""));