• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_
18 #define INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_
19 
20 #include <stdarg.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include <charconv>
25 #include <cinttypes>
26 #include <optional>
27 #include <string>
28 #include <system_error>
29 #include <vector>
30 
31 #include "perfetto/ext/base/string_view.h"
32 
33 namespace perfetto {
34 namespace base {
35 
Lowercase(char c)36 inline char Lowercase(char c) {
37   return ('A' <= c && c <= 'Z') ? static_cast<char>(c - ('A' - 'a')) : c;
38 }
39 
Uppercase(char c)40 inline char Uppercase(char c) {
41   return ('a' <= c && c <= 'z') ? static_cast<char>(c + ('A' - 'a')) : c;
42 }
43 
44 inline std::optional<uint32_t> CStringToUInt32(const char* s, int base = 10) {
45   char* endptr = nullptr;
46   auto value = static_cast<uint32_t>(strtoul(s, &endptr, base));
47   return (*s && !*endptr) ? std::make_optional(value) : std::nullopt;
48 }
49 
50 inline std::optional<int32_t> CStringToInt32(const char* s, int base = 10) {
51   char* endptr = nullptr;
52   auto value = static_cast<int32_t>(strtol(s, &endptr, base));
53   return (*s && !*endptr) ? std::make_optional(value) : std::nullopt;
54 }
55 
56 // Note: it saturates to 7fffffffffffffff if parsing a hex number >= 0x8000...
57 inline std::optional<int64_t> CStringToInt64(const char* s, int base = 10) {
58   char* endptr = nullptr;
59   auto value = static_cast<int64_t>(strtoll(s, &endptr, base));
60   return (*s && !*endptr) ? std::make_optional(value) : std::nullopt;
61 }
62 
63 inline std::optional<uint64_t> CStringToUInt64(const char* s, int base = 10) {
64   char* endptr = nullptr;
65   auto value = static_cast<uint64_t>(strtoull(s, &endptr, base));
66   return (*s && !*endptr) ? std::make_optional(value) : std::nullopt;
67 }
68 
69 double StrToD(const char* nptr, char** endptr);
70 
CStringToDouble(const char * s)71 inline std::optional<double> CStringToDouble(const char* s) {
72   char* endptr = nullptr;
73   double value = StrToD(s, &endptr);
74   std::optional<double> result(std::nullopt);
75   if (*s != '\0' && *endptr == '\0')
76     result = value;
77   return result;
78 }
79 
80 inline std::optional<uint32_t> StringToUInt32(const std::string& s,
81                                               int base = 10) {
82   return CStringToUInt32(s.c_str(), base);
83 }
84 
85 inline std::optional<int32_t> StringToInt32(const std::string& s,
86                                             int base = 10) {
87   return CStringToInt32(s.c_str(), base);
88 }
89 
90 inline std::optional<uint64_t> StringToUInt64(const std::string& s,
91                                               int base = 10) {
92   return CStringToUInt64(s.c_str(), base);
93 }
94 
95 inline std::optional<int64_t> StringToInt64(const std::string& s,
96                                             int base = 10) {
97   return CStringToInt64(s.c_str(), base);
98 }
99 
StringToDouble(const std::string & s)100 inline std::optional<double> StringToDouble(const std::string& s) {
101   return CStringToDouble(s.c_str());
102 }
103 
104 template <typename T>
105 inline std::optional<T> StringViewToNumber(const base::StringView& sv,
106                                            int base = 10) {
107   // std::from_chars() does not regonize the leading '+' character and only
108   // recognizes '-' so remove the '+' if it exists to avoid errors and match
109   // the behavior of the other string conversion utilities above.
110   size_t start_offset = !sv.empty() && sv.at(0) == '+' ? 1 : 0;
111   T value;
112   auto result =
113       std::from_chars(sv.begin() + start_offset, sv.end(), value, base);
114   if (result.ec == std::errc() && result.ptr == sv.end()) {
115     return value;
116   } else {
117     return std::nullopt;
118   }
119 }
120 
121 inline std::optional<uint32_t> StringViewToUInt32(const base::StringView& sv,
122                                                   int base = 10) {
123   // std::from_chars() does not recognize the leading '-' character for
124   // unsigned conversions, but strtol does. To Mimic the behavior of strtol,
125   // attempt a signed converion if we see a leading '-', and then cast the
126   // result back to unsigned.
127   if (sv.size() > 0 && sv.at(0) == '-') {
128     return static_cast<std::optional<uint32_t> >(
129         StringViewToNumber<int32_t>(sv, base));
130   } else {
131     return StringViewToNumber<uint32_t>(sv, base);
132   }
133 }
134 
135 inline std::optional<int32_t> StringViewToInt32(const base::StringView& sv,
136                                                 int base = 10) {
137   return StringViewToNumber<int32_t>(sv, base);
138 }
139 
140 inline std::optional<uint64_t> StringViewToUInt64(const base::StringView& sv,
141                                                   int base = 10) {
142   // std::from_chars() does not recognize the leading '-' character for
143   // unsigned conversions, but strtol does. To Mimic the behavior of strtol,
144   // attempt a signed converion if we see a leading '-', and then cast the
145   // result back to unsigned.
146   if (sv.size() > 0 && sv.at(0) == '-') {
147     return static_cast<std::optional<uint64_t> >(
148         StringViewToNumber<int64_t>(sv, base));
149   } else {
150     return StringViewToNumber<uint64_t>(sv, base);
151   }
152 }
153 
154 inline std::optional<int64_t> StringViewToInt64(const base::StringView& sv,
155                                                 int base = 10) {
156   return StringViewToNumber<int64_t>(sv, base);
157 }
158 
159 // TODO: As of Clang 19.0 std::from_chars is unimplemented for type double
160 // despite being part of C++17 standard, and already being supported by GCC and
161 // MSVC. Enable this once we have double support in Clang.
162 // inline std::optional<double> StringViewToDouble(const base::StringView& sv) {
163 //   return StringViewToNumber<double>(sv);
164 // }
165 
166 bool StartsWith(const std::string& str, const std::string& prefix);
167 bool EndsWith(const std::string& str, const std::string& suffix);
168 bool StartsWithAny(const std::string& str,
169                    const std::vector<std::string>& prefixes);
170 bool Contains(const std::string& haystack, const std::string& needle);
171 bool Contains(const std::string& haystack, char needle);
172 size_t Find(const StringView& needle, const StringView& haystack);
173 bool CaseInsensitiveEqual(const std::string& first, const std::string& second);
174 std::string Join(const std::vector<std::string>& parts,
175                  const std::string& delim);
176 std::vector<std::string> SplitString(const std::string& text,
177                                      const std::string& delimiter);
178 std::string StripPrefix(const std::string& str, const std::string& prefix);
179 std::string StripSuffix(const std::string& str, const std::string& suffix);
180 std::string TrimWhitespace(const std::string& str);
181 std::string ToLower(const std::string& str);
182 std::string ToUpper(const std::string& str);
183 std::string StripChars(const std::string& str,
184                        const std::string& chars,
185                        char replacement);
186 std::string ToHex(const char* data, size_t size);
ToHex(const std::string & s)187 inline std::string ToHex(const std::string& s) {
188   return ToHex(s.c_str(), s.size());
189 }
190 std::string IntToHexString(uint32_t number);
191 std::string Uint64ToHexString(uint64_t number);
192 std::string Uint64ToHexStringNoPrefix(uint64_t number);
193 std::string ReplaceAll(std::string str,
194                        const std::string& to_replace,
195                        const std::string& replacement);
196 
197 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
198 bool WideToUTF8(const std::wstring& source, std::string& output);
199 bool UTF8ToWide(const std::string& source, std::wstring& output);
200 #endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
201 
202 // A BSD-style strlcpy without the return value.
203 // Copies at most |dst_size|-1 characters. Unlike strncpy, it always \0
204 // terminates |dst|, as long as |dst_size| is not 0.
205 // Unlike strncpy and like strlcpy it does not zero-pad the rest of |dst|.
206 // Returns nothing. The BSD strlcpy returns the size of |src|, which might
207 // be > |dst_size|. Anecdotal experience suggests people assume the return value
208 // is the number of bytes written in |dst|. That assumption can lead to
209 // dangerous bugs.
210 // In order to avoid being subtly uncompliant with strlcpy AND avoid misuse,
211 // the choice here is to return nothing.
StringCopy(char * dst,const char * src,size_t dst_size)212 inline void StringCopy(char* dst, const char* src, size_t dst_size) {
213   for (size_t i = 0; i < dst_size; ++i) {
214     if ((dst[i] = src[i]) == '\0') {
215       return;  // We hit and copied the null terminator.
216     }
217   }
218 
219   // We were left off at dst_size. We over copied 1 byte. Null terminate.
220   if (PERFETTO_LIKELY(dst_size > 0))
221     dst[dst_size - 1] = 0;
222 }
223 
224 // Like snprintf() but returns the number of chars *actually* written (without
225 // counting the null terminator) NOT "the number of chars which would have been
226 // written to the final string if enough  space had been available".
227 // This should be used in almost all cases when the caller uses the return value
228 // of snprintf(). If the return value is not used, there is no benefit in using
229 // this wrapper, as this just calls snprintf() and mangles the return value.
230 // It always null-terminates |dst| (even in case of errors), unless
231 // |dst_size| == 0.
232 // Examples:
233 //   SprintfTrunc(x, 4, "123whatever"): returns 3 and writes "123\0".
234 //   SprintfTrunc(x, 4, "123"): returns 3 and writes "123\0".
235 //   SprintfTrunc(x, 3, "123"): returns 2 and writes "12\0".
236 //   SprintfTrunc(x, 2, "123"): returns 1 and writes "1\0".
237 //   SprintfTrunc(x, 1, "123"): returns 0 and writes "\0".
238 //   SprintfTrunc(x, 0, "123"): returns 0 and writes nothing.
239 // NOTE: This means that the caller has no way to tell when truncation happens
240 //   vs the edge case of *just* fitting in the buffer.
241 size_t SprintfTrunc(char* dst, size_t dst_size, const char* fmt, ...)
242     PERFETTO_PRINTF_FORMAT(3, 4);
243 
244 // Line number starts from 1
245 struct LineWithOffset {
246   base::StringView line;
247   uint32_t line_offset;
248   uint32_t line_num;
249 };
250 
251 // For given string and offset Pfinds a line with character for
252 // which offset points, what number is this line (starts from 1), and the offset
253 // inside this line. returns std::nullopt if the offset points to
254 // line break character or exceeds string length.
255 std::optional<LineWithOffset> FindLineWithOffset(base::StringView str,
256                                                  uint32_t offset);
257 
258 // A helper class to facilitate construction and usage of write-once stack
259 // strings.
260 // Example usage:
261 //   StackString<32> x("format %d %s", 42, string_arg);
262 //   TakeString(x.c_str() | x.string_view() | x.ToStdString());
263 // Rather than char x[32] + sprintf.
264 // Advantages:
265 // - Avoids useless zero-fills caused by people doing `char buf[32] {}` (mainly
266 //   by fearing unknown snprintf failure modes).
267 // - Makes the code more robust in case of snprintf truncations (len() and
268 //  string_view() will return the truncated length, unlike snprintf).
269 template <size_t N>
270 class StackString {
271  public:
272   explicit PERFETTO_PRINTF_FORMAT(/* 1=this */ 2, 3)
StackString(const char * fmt,...)273       StackString(const char* fmt, ...) {
274     buf_[0] = '\0';
275     va_list args;
276     va_start(args, fmt);
277     int res = vsnprintf(buf_, sizeof(buf_), fmt, args);
278     va_end(args);
279     buf_[sizeof(buf_) - 1] = '\0';
280     len_ = res < 0 ? 0 : std::min(static_cast<size_t>(res), sizeof(buf_) - 1);
281   }
282 
string_view()283   StringView string_view() const { return StringView(buf_, len_); }
ToStdString()284   std::string ToStdString() const { return std::string(buf_, len_); }
c_str()285   const char* c_str() const { return buf_; }
len()286   size_t len() const { return len_; }
mutable_data()287   char* mutable_data() { return buf_; }
288 
289  private:
290   char buf_[N];
291   size_t len_ = 0;  // Does not include the \0.
292 };
293 
294 }  // namespace base
295 }  // namespace perfetto
296 
297 #endif  // INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_
298