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 <string.h>
20
21 #include <algorithm>
22
23 #include "perfetto/base/logging.h"
24
25 namespace perfetto {
26 namespace base {
27
StartsWith(const std::string & str,const std::string & prefix)28 bool StartsWith(const std::string& str, const std::string& prefix) {
29 return str.compare(0, prefix.length(), prefix) == 0;
30 }
31
EndsWith(const std::string & str,const std::string & suffix)32 bool EndsWith(const std::string& str, const std::string& suffix) {
33 if (suffix.size() > str.size())
34 return false;
35 return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
36 }
37
Contains(const std::string & haystack,const std::string & needle)38 bool Contains(const std::string& haystack, const std::string& needle) {
39 return haystack.find(needle) != std::string::npos;
40 }
41
Find(const StringView & needle,const StringView & haystack)42 size_t Find(const StringView& needle, const StringView& haystack) {
43 if (needle.size() == 0)
44 return 0;
45 if (needle.size() > haystack.size())
46 return std::string::npos;
47 for (size_t i = 0; i < haystack.size() - (needle.size() - 1); ++i) {
48 if (strncmp(haystack.data() + i, needle.data(), needle.size()) == 0)
49 return i;
50 }
51 return std::string::npos;
52 }
53
CaseInsensitiveEqual(const std::string & first,const std::string & second)54 bool CaseInsensitiveEqual(const std::string& first, const std::string& second) {
55 return first.size() == second.size() &&
56 std::equal(
57 first.begin(), first.end(), second.begin(),
58 [](char a, char b) { return Lowercase(a) == Lowercase(b); });
59 }
60
Join(const std::vector<std::string> & parts,const std::string & delim)61 std::string Join(const std::vector<std::string>& parts,
62 const std::string& delim) {
63 std::string acc;
64 for (size_t i = 0; i < parts.size(); ++i) {
65 acc += parts[i];
66 if (i + 1 != parts.size()) {
67 acc += delim;
68 }
69 }
70 return acc;
71 }
72
SplitString(const std::string & text,const std::string & delimiter)73 std::vector<std::string> SplitString(const std::string& text,
74 const std::string& delimiter) {
75 PERFETTO_CHECK(!delimiter.empty());
76
77 std::vector<std::string> output;
78 size_t start = 0;
79 size_t next;
80 for (;;) {
81 next = std::min(text.find(delimiter, start), text.size());
82 if (next > start)
83 output.emplace_back(&text[start], next - start);
84 start = next + delimiter.size();
85 if (start >= text.size())
86 break;
87 }
88 return output;
89 }
90
StripPrefix(const std::string & str,const std::string & prefix)91 std::string StripPrefix(const std::string& str, const std::string& prefix) {
92 return StartsWith(str, prefix) ? str.substr(prefix.size()) : str;
93 }
94
StripSuffix(const std::string & str,const std::string & suffix)95 std::string StripSuffix(const std::string& str, const std::string& suffix) {
96 return EndsWith(str, suffix) ? str.substr(0, str.size() - suffix.size())
97 : str;
98 }
99
ToUpper(const std::string & str)100 std::string ToUpper(const std::string& str) {
101 // Don't use toupper(), it depends on the locale.
102 std::string res(str);
103 auto end = res.end();
104 for (auto c = res.begin(); c != end; ++c)
105 *c = Uppercase(*c);
106 return res;
107 }
108
ToLower(const std::string & str)109 std::string ToLower(const std::string& str) {
110 // Don't use tolower(), it depends on the locale.
111 std::string res(str);
112 auto end = res.end();
113 for (auto c = res.begin(); c != end; ++c)
114 *c = Lowercase(*c);
115 return res;
116 }
117
ToHex(const char * data,size_t size)118 std::string ToHex(const char* data, size_t size) {
119 std::string hex(2 * size + 1, 'x');
120 for (size_t i = 0; i < size; ++i) {
121 // snprintf prints 3 characters, the two hex digits and a null byte. As we
122 // write left to right, we keep overwriting the nullbytes, except for the
123 // last call to snprintf.
124 snprintf(&(hex[2 * i]), 3, "%02hhx", data[i]);
125 }
126 // Remove the trailing nullbyte produced by the last snprintf.
127 hex.resize(2 * size);
128 return hex;
129 }
130
IntToHexString(uint32_t number)131 std::string IntToHexString(uint32_t number) {
132 size_t max_size = 11; // Max uint32 is 0xFFFFFFFF + 1 for null byte.
133 std::string buf;
134 buf.resize(max_size);
135 auto final_size = snprintf(&buf[0], max_size, "0x%02x", number);
136 PERFETTO_DCHECK(final_size >= 0);
137 buf.resize(static_cast<size_t>(final_size)); // Cuts off the final null byte.
138 return buf;
139 }
140
StripChars(const std::string & str,const std::string & chars,char replacement)141 std::string StripChars(const std::string& str,
142 const std::string& chars,
143 char replacement) {
144 std::string res(str);
145 const char* start = res.c_str();
146 const char* remove = chars.c_str();
147 for (const char* c = strpbrk(start, remove); c; c = strpbrk(c + 1, remove))
148 res[static_cast<uintptr_t>(c - start)] = replacement;
149 return res;
150 }
151
152 } // namespace base
153 } // namespace perfetto
154