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

Commit b451c265 authored by Dan Albert's avatar Dan Albert Committed by Android Git Automerger
Browse files

am 928cbdd2: Merge "Add common string utilities to libbase."

* commit '928cbdd2':
  Add common string utilities to libbase.
parents 8d70646a 928cbdd2
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -19,10 +19,12 @@ LOCAL_PATH := $(call my-dir)
libbase_src_files := \
    file.cpp \
    stringprintf.cpp \
    strings.cpp \

libbase_test_src_files := \
    file_test.cpp \
    stringprintf_test.cpp \
    strings_test.cpp \

libbase_cppflags := \
    -Wall \
+47 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef BASE_STRINGS_H
#define BASE_STRINGS_H

#include <string>
#include <vector>

namespace android {
namespace base {

// Splits a string using the given separator character into a vector of strings.
// Empty strings will be omitted.
void Split(const std::string& s, char separator,
           std::vector<std::string>* result);

// 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);

// Tests whether 's' starts with 'prefix'.
bool StartsWith(const std::string& s, const char* prefix);

// Tests whether 's' ends with 'suffix'.
bool EndsWith(const std::string& s, const char* suffix);

}  // namespace base
}  // namespace android

#endif  // BASE_STRINGS_H

base/strings.cpp

0 → 100644
+111 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "base/strings.h"

#include <string>
#include <vector>

namespace android {
namespace base {

void Split(const std::string& s, char separator,
           std::vector<std::string>* result) {
  const char* p = s.data();
  const char* end = p + s.size();
  while (p != end) {
    if (*p == separator) {
      ++p;
    } else {
      const char* start = p;
      while (++p != end && *p != separator) {
        // Skip to the next occurrence of the separator.
      }
      result->push_back(std::string(start, p - start));
    }
  }
}

std::string Trim(const std::string& s) {
  std::string result;

  if (s.size() == 0) {
    return result;
  }

  size_t start_index = 0;
  size_t end_index = s.size() - 1;

  // Skip initial whitespace.
  while (start_index < s.size()) {
    if (!isspace(s[start_index])) {
      break;
    }
    start_index++;
  }

  // Skip terminating whitespace.
  while (end_index >= start_index) {
    if (!isspace(s[end_index])) {
      break;
    }
    end_index--;
  }

  // All spaces, no beef.
  if (end_index < start_index) {
    return "";
  }
  // Start_index is the first non-space, end_index is the last one.
  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);

bool StartsWith(const std::string& s, const char* prefix) {
  return s.compare(0, strlen(prefix), prefix) == 0;
}

bool EndsWith(const std::string& s, const char* suffix) {
  size_t suffix_length = strlen(suffix);
  size_t string_length = s.size();
  if (suffix_length > string_length) {
    return false;
  }
  size_t offset = string_length - suffix_length;
  return s.compare(offset, suffix_length, suffix) == 0;
}

}  // namespace base
}  // namespace android

base/strings_test.cpp

0 → 100644
+142 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "base/strings.h"

#include <gtest/gtest.h>

#include <string>
#include <vector>

TEST(strings, split_empty) {
  std::vector<std::string> parts;
  android::base::Split("", '\0', &parts);
  ASSERT_EQ(0U, parts.size());
}

TEST(strings, split_single) {
  std::vector<std::string> parts;
  android::base::Split("foo", ',', &parts);
  ASSERT_EQ(1U, parts.size());
  ASSERT_EQ("foo", parts[0]);
}

TEST(strings, split_simple) {
  std::vector<std::string> parts;
  android::base::Split("foo,bar,baz", ',', &parts);
  ASSERT_EQ(3U, parts.size());
  ASSERT_EQ("foo", parts[0]);
  ASSERT_EQ("bar", parts[1]);
  ASSERT_EQ("baz", parts[2]);
}

TEST(strings, split_with_empty_part) {
  std::vector<std::string> parts;
  android::base::Split("foo,,bar", ',', &parts);
  ASSERT_EQ(2U, parts.size());
  ASSERT_EQ("foo", parts[0]);
  ASSERT_EQ("bar", parts[1]);
}

TEST(strings, trim_empty) {
  ASSERT_EQ("", android::base::Trim(""));
}

TEST(strings, trim_already_trimmed) {
  ASSERT_EQ("foo", android::base::Trim("foo"));
}

TEST(strings, trim_left) {
  ASSERT_EQ("foo", android::base::Trim(" foo"));
}

TEST(strings, trim_right) {
  ASSERT_EQ("foo", android::base::Trim("foo "));
}

TEST(strings, trim_both) {
  ASSERT_EQ("foo", android::base::Trim(" foo "));
}

TEST(strings, trim_no_trim_middle) {
  ASSERT_EQ("foo bar", android::base::Trim("foo bar"));
}

TEST(strings, trim_other_whitespace) {
  ASSERT_EQ("foo", android::base::Trim("\v\tfoo\n\f"));
}

TEST(strings, join_nothing) {
  std::vector<std::string> list = {};
  ASSERT_EQ("", android::base::Join(list, ','));
}

TEST(strings, join_single) {
  std::vector<std::string> list = {"foo"};
  ASSERT_EQ("foo", android::base::Join(list, ','));
}

TEST(strings, join_simple) {
  std::vector<std::string> list = {"foo", "bar", "baz"};
  ASSERT_EQ("foo,bar,baz", android::base::Join(list, ','));
}

TEST(strings, join_separator_in_vector) {
  std::vector<std::string> list = {",", ","};
  ASSERT_EQ(",,,", android::base::Join(list, ','));
}

TEST(strings, startswith_empty) {
  ASSERT_FALSE(android::base::StartsWith("", "foo"));
  ASSERT_TRUE(android::base::StartsWith("", ""));
}

TEST(strings, startswith_simple) {
  ASSERT_TRUE(android::base::StartsWith("foo", ""));
  ASSERT_TRUE(android::base::StartsWith("foo", "f"));
  ASSERT_TRUE(android::base::StartsWith("foo", "fo"));
  ASSERT_TRUE(android::base::StartsWith("foo", "foo"));
}

TEST(strings, startswith_prefix_too_long) {
  ASSERT_FALSE(android::base::StartsWith("foo", "foobar"));
}

TEST(strings, startswith_contains_prefix) {
  ASSERT_FALSE(android::base::StartsWith("foobar", "oba"));
  ASSERT_FALSE(android::base::StartsWith("foobar", "bar"));
}

TEST(strings, endswith_empty) {
  ASSERT_FALSE(android::base::EndsWith("", "foo"));
  ASSERT_TRUE(android::base::EndsWith("", ""));
}

TEST(strings, endswith_simple) {
  ASSERT_TRUE(android::base::EndsWith("foo", ""));
  ASSERT_TRUE(android::base::EndsWith("foo", "o"));
  ASSERT_TRUE(android::base::EndsWith("foo", "oo"));
  ASSERT_TRUE(android::base::EndsWith("foo", "foo"));
}

TEST(strings, endswith_prefix_too_long) {
  ASSERT_FALSE(android::base::EndsWith("foo", "foobar"));
}

TEST(strings, endswith_contains_prefix) {
  ASSERT_FALSE(android::base::EndsWith("foobar", "oba"));
  ASSERT_FALSE(android::base::EndsWith("foobar", "foo"));
}