• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2015 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "android/base/misc/StringUtils.h"
16 
17 #include <stdlib.h>
18 #include <string.h>
19 
20 #ifdef _MSC_VER
21 #include "msvc-posix.h"
22 #endif
23 
24 #include <algorithm>
25 #include <string>
26 #include <vector>
27 
28 
29 #ifdef _WIN32
memmem(const void * haystack,size_t haystackLen,const void * needle,size_t needleLen)30 const void* memmem(const void* haystack, size_t haystackLen,
31                    const void* needle, size_t needleLen) {
32     if (!haystack || !needle) {
33         return nullptr;
34     }
35 
36     const auto it = std::search(
37                         static_cast<const char*>(haystack),
38                         static_cast<const char*>(haystack) + haystackLen,
39                         static_cast<const char*>(needle),
40                         static_cast<const char*>(needle) + needleLen);
41     return it == static_cast<const char*>(haystack) + haystackLen
42             ? nullptr
43             : it;
44 }
45 #endif  // _WIN32
46 
47 namespace android {
48 namespace base {
49 
strDup(StringView view)50 char* strDup(StringView view) {
51     // Same as strdup(str.c_str()) but avoids a strlen() call.
52     char* ret = static_cast<char*>(malloc(view.size() + 1u));
53     ::memcpy(ret, view.data(), view.size());
54     ret[view.size()] = '\0';
55     return ret;
56 }
57 
strContains(StringView haystack,const char * needle)58 bool strContains(StringView haystack, const char* needle) {
59     return ::memmem(haystack.data(), haystack.size(), needle,
60                     ::strlen(needle)) != nullptr;
61 }
62 
Trim(const std::string & s)63 std::string Trim(const std::string& s) {
64     std::string result;
65 
66     if (s.size() == 0) {
67         return result;
68     }
69 
70     size_t start_index = 0;
71     size_t end_index = s.size() - 1;
72 
73     // Skip initial whitespace.
74     while (start_index < s.size()) {
75         if (!isspace(s[start_index])) {
76             break;
77         }
78         start_index++;
79     }
80 
81     // Skip terminating whitespace.
82     while (end_index >= start_index) {
83         if (!isspace(s[end_index])) {
84             break;
85         }
86         end_index--;
87     }
88 
89     // All spaces, no beef.
90     if (end_index < start_index) {
91         return "";
92     }
93     // Start_index is the first non-space, end_index is the last one.
94     return s.substr(start_index, end_index - start_index + 1);
95 }
96 
trim(const std::string & in)97 std::string trim(const std::string& in) {
98     return Trim(in);
99 }
100 
StartsWith(std::string_view s,std::string_view prefix)101 bool StartsWith(std::string_view s, std::string_view prefix) {
102     return s.substr(0, prefix.size()) == prefix;
103 }
104 
startsWith(StringView string,StringView prefix)105 bool startsWith(StringView string, StringView prefix) {
106     return string.size() >= prefix.size() &&
107             memcmp(string.data(), prefix.data(), prefix.size()) == 0;
108 }
109 
endsWith(StringView string,StringView suffix)110 bool endsWith(StringView string, StringView suffix) {
111     return string.size() >= suffix.size() &&
112             memcmp(string.data() + string.size() - suffix.size(),
113                    suffix.data(), suffix.size()) == 0;
114 }
115 
splitTokens(const std::string & input,std::vector<std::string> * out,StringView splitBy)116 void splitTokens(const std::string& input,
117                  std::vector<std::string>* out,
118                  StringView splitBy) {
119     auto removeWhiteSpace = [out](StringView strView) {
120         std::string s = strView.str();
121         s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
122         out->push_back(s);
123     };
124     out->clear();
125     split(input, splitBy, removeWhiteSpace);
126 }
127 
Split(const std::string & s,const std::string & delimiters)128 std::vector<std::string> Split(const std::string& s,
129                                const std::string& delimiters) {
130     if (delimiters.empty()) {
131         return {}
132     }
133 
134     std::vector<std::string> result;
135 
136     size_t base = 0;
137     size_t found;
138     while (true) {
139         found = s.find_first_of(delimiters, base);
140         result.push_back(s.substr(base, found - base));
141         if (found == s.npos)
142             break;
143         base = found + 1;
144     }
145 
146     return result;
147 }
148 
149 // These cases are probably the norm, so we mark them extern in the header to
150 // aid compile time and binary size.
151 template std::string Join(const std::vector<std::string>&, char);
152 template std::string Join(const std::vector<const char*>&, char);
153 template std::string Join(const std::vector<std::string>&, const std::string&);
154 template std::string Join(const std::vector<const char*>&, const std::string&);
155 
StartsWith(std::string_view s,char prefix)156 bool StartsWith(std::string_view s, char prefix) {
157     return !s.empty() && s.front() == prefix;
158 }
159 
StartsWithIgnoreCase(std::string_view s,std::string_view prefix)160 bool StartsWithIgnoreCase(std::string_view s, std::string_view prefix) {
161     return s.size() >= prefix.size() &&
162            strncasecmp(s.data(), prefix.data(), prefix.size()) == 0;
163 }
164 
EndsWith(std::string_view s,std::string_view suffix)165 bool EndsWith(std::string_view s, std::string_view suffix) {
166     return s.size() >= suffix.size() &&
167            s.substr(s.size() - suffix.size(), suffix.size()) == suffix;
168 }
169 
EndsWith(std::string_view s,char suffix)170 bool EndsWith(std::string_view s, char suffix) {
171     return !s.empty() && s.back() == suffix;
172 }
173 
EndsWithIgnoreCase(std::string_view s,std::string_view suffix)174 bool EndsWithIgnoreCase(std::string_view s, std::string_view suffix) {
175     return s.size() >= suffix.size() &&
176            strncasecmp(s.data() + (s.size() - suffix.size()), suffix.data(),
177                        suffix.size()) == 0;
178 }
179 
EqualsIgnoreCase(std::string_view lhs,std::string_view rhs)180 bool EqualsIgnoreCase(std::string_view lhs, std::string_view rhs) {
181     return lhs.size() == rhs.size() &&
182            strncasecmp(lhs.data(), rhs.data(), lhs.size()) == 0;
183 }
184 
StringReplace(std::string_view s,std::string_view from,std::string_view to,bool all)185 std::string StringReplace(std::string_view s,
186                           std::string_view from,
187                           std::string_view to,
188                           bool all) {
189     if (from.empty())
190         return std::string(s);
191 
192     std::string result;
193     std::string_view::size_type start_pos = 0;
194     do {
195         std::string_view::size_type pos = s.find(from, start_pos);
196         if (pos == std::string_view::npos)
197             break;
198 
199         result.append(s.data() + start_pos, pos - start_pos);
200         result.append(to.data(), to.size());
201 
202         start_pos = pos + from.size();
203     } while (all);
204     result.append(s.data() + start_pos, s.size() - start_pos);
205     return result;
206 }
207 
208 }  // namespace base
209 }  // namespace android
210