1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "perfetto/ext/base/string_utils.h"
18
19 #include <inttypes.h>
20 #include <string.h>
21
22 #include <algorithm>
23
24 #include "perfetto/base/logging.h"
25
26 namespace perfetto {
27 namespace base {
28
StartsWith(const std::string & str,const std::string & prefix)29 bool StartsWith(const std::string& str, const std::string& prefix) {
30 return str.compare(0, prefix.length(), prefix) == 0;
31 }
32
EndsWith(const std::string & str,const std::string & suffix)33 bool EndsWith(const std::string& str, const std::string& suffix) {
34 if (suffix.size() > str.size())
35 return false;
36 return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
37 }
38
Contains(const std::string & haystack,const std::string & needle)39 bool Contains(const std::string& haystack, const std::string& needle) {
40 return haystack.find(needle) != std::string::npos;
41 }
42
Find(const StringView & needle,const StringView & haystack)43 size_t Find(const StringView& needle, const StringView& haystack) {
44 if (needle.empty())
45 return 0;
46 if (needle.size() > haystack.size())
47 return std::string::npos;
48 for (size_t i = 0; i < haystack.size() - (needle.size() - 1); ++i) {
49 if (strncmp(haystack.data() + i, needle.data(), needle.size()) == 0)
50 return i;
51 }
52 return std::string::npos;
53 }
54
CaseInsensitiveEqual(const std::string & first,const std::string & second)55 bool CaseInsensitiveEqual(const std::string& first, const std::string& second) {
56 return first.size() == second.size() &&
57 std::equal(
58 first.begin(), first.end(), second.begin(),
59 [](char a, char b) { return Lowercase(a) == Lowercase(b); });
60 }
61
Join(const std::vector<std::string> & parts,const std::string & delim)62 std::string Join(const std::vector<std::string>& parts,
63 const std::string& delim) {
64 std::string acc;
65 for (size_t i = 0; i < parts.size(); ++i) {
66 acc += parts[i];
67 if (i + 1 != parts.size()) {
68 acc += delim;
69 }
70 }
71 return acc;
72 }
73
SplitString(const std::string & text,const std::string & delimiter)74 std::vector<std::string> SplitString(const std::string& text,
75 const std::string& delimiter) {
76 PERFETTO_CHECK(!delimiter.empty());
77
78 std::vector<std::string> output;
79 size_t start = 0;
80 size_t next;
81 for (;;) {
82 next = std::min(text.find(delimiter, start), text.size());
83 if (next > start)
84 output.emplace_back(&text[start], next - start);
85 start = next + delimiter.size();
86 if (start >= text.size())
87 break;
88 }
89 return output;
90 }
91
StripPrefix(const std::string & str,const std::string & prefix)92 std::string StripPrefix(const std::string& str, const std::string& prefix) {
93 return StartsWith(str, prefix) ? str.substr(prefix.size()) : str;
94 }
95
StripSuffix(const std::string & str,const std::string & suffix)96 std::string StripSuffix(const std::string& str, const std::string& suffix) {
97 return EndsWith(str, suffix) ? str.substr(0, str.size() - suffix.size())
98 : str;
99 }
100
ToUpper(const std::string & str)101 std::string ToUpper(const std::string& str) {
102 // Don't use toupper(), it depends on the locale.
103 std::string res(str);
104 auto end = res.end();
105 for (auto c = res.begin(); c != end; ++c)
106 *c = Uppercase(*c);
107 return res;
108 }
109
ToLower(const std::string & str)110 std::string ToLower(const std::string& str) {
111 // Don't use tolower(), it depends on the locale.
112 std::string res(str);
113 auto end = res.end();
114 for (auto c = res.begin(); c != end; ++c)
115 *c = Lowercase(*c);
116 return res;
117 }
118
ToHex(const char * data,size_t size)119 std::string ToHex(const char* data, size_t size) {
120 std::string hex(2 * size + 1, 'x');
121 for (size_t i = 0; i < size; ++i) {
122 // snprintf prints 3 characters, the two hex digits and a null byte. As we
123 // write left to right, we keep overwriting the nullbytes, except for the
124 // last call to snprintf.
125 snprintf(&(hex[2 * i]), 3, "%02hhx", data[i]);
126 }
127 // Remove the trailing nullbyte produced by the last snprintf.
128 hex.resize(2 * size);
129 return hex;
130 }
131
IntToHexString(uint32_t number)132 std::string IntToHexString(uint32_t number) {
133 size_t max_size = 11; // Max uint32 is 0xFFFFFFFF + 1 for null byte.
134 std::string buf;
135 buf.resize(max_size);
136 auto final_size = snprintf(&buf[0], max_size, "0x%02x", number);
137 PERFETTO_DCHECK(final_size >= 0);
138 buf.resize(static_cast<size_t>(final_size)); // Cuts off the final null byte.
139 return buf;
140 }
141
Uint64ToHexString(uint64_t number)142 std::string Uint64ToHexString(uint64_t number) {
143 return "0x" + Uint64ToHexStringNoPrefix(number);
144 }
145
Uint64ToHexStringNoPrefix(uint64_t number)146 std::string Uint64ToHexStringNoPrefix(uint64_t number) {
147 size_t max_size = 17; // Max uint64 is FFFFFFFFFFFFFFFF + 1 for null byte.
148 std::string buf;
149 buf.resize(max_size);
150 auto final_size = snprintf(&buf[0], max_size, "%" PRIx64 "", number);
151 PERFETTO_DCHECK(final_size >= 0);
152 buf.resize(static_cast<size_t>(final_size)); // Cuts off the final null byte.
153 return buf;
154 }
155
StripChars(const std::string & str,const std::string & chars,char replacement)156 std::string StripChars(const std::string& str,
157 const std::string& chars,
158 char replacement) {
159 std::string res(str);
160 const char* start = res.c_str();
161 const char* remove = chars.c_str();
162 for (const char* c = strpbrk(start, remove); c; c = strpbrk(c + 1, remove))
163 res[static_cast<uintptr_t>(c - start)] = replacement;
164 return res;
165 }
166
ReplaceAll(std::string str,const std::string & to_replace,const std::string & replacement)167 std::string ReplaceAll(std::string str,
168 const std::string& to_replace,
169 const std::string& replacement) {
170 PERFETTO_CHECK(!to_replace.empty());
171 size_t pos = 0;
172 while ((pos = str.find(to_replace, pos)) != std::string::npos) {
173 str.replace(pos, to_replace.length(), replacement);
174 pos += replacement.length();
175 }
176 return str;
177 }
178
TrimLeading(const std::string & str)179 std::string TrimLeading(const std::string& str) {
180 size_t idx = str.find_first_not_of(' ');
181 return idx == std::string::npos ? str : str.substr(idx);
182 }
183
184 } // namespace base
185 } // namespace perfetto
186