1 | /* |
2 | * Copyright 2011-present Facebook, Inc. |
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 | #pragma once |
18 | #define FOLLY_STRING_H_ |
19 | |
20 | #include <cstdarg> |
21 | #include <exception> |
22 | #include <string> |
23 | #include <unordered_map> |
24 | #include <unordered_set> |
25 | #include <vector> |
26 | |
27 | #include <folly/Conv.h> |
28 | #include <folly/ExceptionString.h> |
29 | #include <folly/FBString.h> |
30 | #include <folly/Portability.h> |
31 | #include <folly/Range.h> |
32 | #include <folly/ScopeGuard.h> |
33 | #include <folly/Traits.h> |
34 | |
35 | // Compatibility function, to make sure toStdString(s) can be called |
36 | // to convert a std::string or fbstring variable s into type std::string |
37 | // with very little overhead if s was already std::string |
38 | namespace folly { |
39 | |
40 | inline std::string toStdString(const folly::fbstring& s) { |
41 | return std::string(s.data(), s.size()); |
42 | } |
43 | |
44 | inline const std::string& toStdString(const std::string& s) { |
45 | return s; |
46 | } |
47 | |
48 | // If called with a temporary, the compiler will select this overload instead |
49 | // of the above, so we don't return a (lvalue) reference to a temporary. |
50 | inline std::string&& toStdString(std::string&& s) { |
51 | return std::move(s); |
52 | } |
53 | |
54 | /** |
55 | * C-Escape a string, making it suitable for representation as a C string |
56 | * literal. Appends the result to the output string. |
57 | * |
58 | * Backslashes all occurrences of backslash and double-quote: |
59 | * " -> \" |
60 | * \ -> \\ |
61 | * |
62 | * Replaces all non-printable ASCII characters with backslash-octal |
63 | * representation: |
64 | * <ASCII 254> -> \376 |
65 | * |
66 | * Note that we use backslash-octal instead of backslash-hex because the octal |
67 | * representation is guaranteed to consume no more than 3 characters; "\3760" |
68 | * represents two characters, one with value 254, and one with value 48 ('0'), |
69 | * whereas "\xfe0" represents only one character (with value 4064, which leads |
70 | * to implementation-defined behavior). |
71 | */ |
72 | template <class String> |
73 | void cEscape(StringPiece str, String& out); |
74 | |
75 | /** |
76 | * Similar to cEscape above, but returns the escaped string. |
77 | */ |
78 | template <class String> |
79 | String cEscape(StringPiece str) { |
80 | String out; |
81 | cEscape(str, out); |
82 | return out; |
83 | } |
84 | |
85 | /** |
86 | * C-Unescape a string; the opposite of cEscape above. Appends the result |
87 | * to the output string. |
88 | * |
89 | * Recognizes the standard C escape sequences: |
90 | * |
91 | * \' \" \? \\ \a \b \f \n \r \t \v |
92 | * \[0-7]+ |
93 | * \x[0-9a-fA-F]+ |
94 | * |
95 | * In strict mode (default), throws std::invalid_argument if it encounters |
96 | * an unrecognized escape sequence. In non-strict mode, it leaves |
97 | * the escape sequence unchanged. |
98 | */ |
99 | template <class String> |
100 | void cUnescape(StringPiece str, String& out, bool strict = true); |
101 | |
102 | /** |
103 | * Similar to cUnescape above, but returns the escaped string. |
104 | */ |
105 | template <class String> |
106 | String cUnescape(StringPiece str, bool strict = true) { |
107 | String out; |
108 | cUnescape(str, out, strict); |
109 | return out; |
110 | } |
111 | |
112 | /** |
113 | * URI-escape a string. Appends the result to the output string. |
114 | * |
115 | * Alphanumeric characters and other characters marked as "unreserved" in RFC |
116 | * 3986 ( -_.~ ) are left unchanged. In PATH mode, the forward slash (/) is |
117 | * also left unchanged. In QUERY mode, spaces are replaced by '+'. All other |
118 | * characters are percent-encoded. |
119 | */ |
120 | enum class UriEscapeMode : unsigned char { |
121 | // The values are meaningful, see generate_escape_tables.py |
122 | ALL = 0, |
123 | QUERY = 1, |
124 | PATH = 2 |
125 | }; |
126 | template <class String> |
127 | void uriEscape( |
128 | StringPiece str, |
129 | String& out, |
130 | UriEscapeMode mode = UriEscapeMode::ALL); |
131 | |
132 | /** |
133 | * Similar to uriEscape above, but returns the escaped string. |
134 | */ |
135 | template <class String> |
136 | String uriEscape(StringPiece str, UriEscapeMode mode = UriEscapeMode::ALL) { |
137 | String out; |
138 | uriEscape(str, out, mode); |
139 | return out; |
140 | } |
141 | |
142 | /** |
143 | * URI-unescape a string. Appends the result to the output string. |
144 | * |
145 | * In QUERY mode, '+' are replaced by space. %XX sequences are decoded if |
146 | * XX is a valid hex sequence, otherwise we throw invalid_argument. |
147 | */ |
148 | template <class String> |
149 | void uriUnescape( |
150 | StringPiece str, |
151 | String& out, |
152 | UriEscapeMode mode = UriEscapeMode::ALL); |
153 | |
154 | /** |
155 | * Similar to uriUnescape above, but returns the unescaped string. |
156 | */ |
157 | template <class String> |
158 | String uriUnescape(StringPiece str, UriEscapeMode mode = UriEscapeMode::ALL) { |
159 | String out; |
160 | uriUnescape(str, out, mode); |
161 | return out; |
162 | } |
163 | |
164 | /** |
165 | * stringPrintf is much like printf but deposits its result into a |
166 | * string. Two signatures are supported: the first simply returns the |
167 | * resulting string, and the second appends the produced characters to |
168 | * the specified string and returns a reference to it. |
169 | */ |
170 | std::string stringPrintf(FOLLY_PRINTF_FORMAT const char* format, ...) |
171 | FOLLY_PRINTF_FORMAT_ATTR(1, 2); |
172 | |
173 | /* Similar to stringPrintf, with different signature. */ |
174 | void stringPrintf(std::string* out, FOLLY_PRINTF_FORMAT const char* fmt, ...) |
175 | FOLLY_PRINTF_FORMAT_ATTR(2, 3); |
176 | |
177 | std::string& stringAppendf( |
178 | std::string* output, |
179 | FOLLY_PRINTF_FORMAT const char* format, |
180 | ...) FOLLY_PRINTF_FORMAT_ATTR(2, 3); |
181 | |
182 | /** |
183 | * Similar to stringPrintf, but accepts a va_list argument. |
184 | * |
185 | * As with vsnprintf() itself, the value of ap is undefined after the call. |
186 | * These functions do not call va_end() on ap. |
187 | */ |
188 | std::string stringVPrintf(const char* format, va_list ap); |
189 | void stringVPrintf(std::string* out, const char* format, va_list ap); |
190 | std::string& stringVAppendf(std::string* out, const char* format, va_list ap); |
191 | |
192 | /** |
193 | * Backslashify a string, that is, replace non-printable characters |
194 | * with C-style (but NOT C compliant) "\xHH" encoding. If hex_style |
195 | * is false, then shorthand notations like "\0" will be used instead |
196 | * of "\x00" for the most common backslash cases. |
197 | * |
198 | * There are two forms, one returning the input string, and one |
199 | * creating output in the specified output string. |
200 | * |
201 | * This is mainly intended for printing to a terminal, so it is not |
202 | * particularly optimized. |
203 | * |
204 | * Do *not* use this in situations where you expect to be able to feed |
205 | * the string to a C or C++ compiler, as there are nuances with how C |
206 | * parses such strings that lead to failures. This is for display |
207 | * purposed only. If you want a string you can embed for use in C or |
208 | * C++, use cEscape instead. This function is for display purposes |
209 | * only. |
210 | */ |
211 | template <class OutputString> |
212 | void backslashify( |
213 | folly::StringPiece input, |
214 | OutputString& output, |
215 | bool hex_style = false); |
216 | |
217 | template <class OutputString = std::string> |
218 | OutputString backslashify(StringPiece input, bool hex_style = false) { |
219 | OutputString output; |
220 | backslashify(input, output, hex_style); |
221 | return output; |
222 | } |
223 | |
224 | /** |
225 | * Take a string and "humanify" it -- that is, make it look better. |
226 | * Since "better" is subjective, caveat emptor. The basic approach is |
227 | * to count the number of unprintable characters. If there are none, |
228 | * then the output is the input. If there are relatively few, or if |
229 | * there is a long "enough" prefix of printable characters, use |
230 | * backslashify. If it is mostly binary, then simply hex encode. |
231 | * |
232 | * This is an attempt to make a computer smart, and so likely is wrong |
233 | * most of the time. |
234 | */ |
235 | template <class String1, class String2> |
236 | void humanify(const String1& input, String2& output); |
237 | |
238 | template <class String> |
239 | String humanify(const String& input) { |
240 | String output; |
241 | humanify(input, output); |
242 | return output; |
243 | } |
244 | |
245 | /** |
246 | * Same functionality as Python's binascii.hexlify. Returns true |
247 | * on successful conversion. |
248 | * |
249 | * If append_output is true, append data to the output rather than |
250 | * replace it. |
251 | */ |
252 | template <class InputString, class OutputString> |
253 | bool hexlify( |
254 | const InputString& input, |
255 | OutputString& output, |
256 | bool append = false); |
257 | |
258 | template <class OutputString = std::string> |
259 | OutputString hexlify(ByteRange input) { |
260 | OutputString output; |
261 | if (!hexlify(input, output)) { |
262 | // hexlify() currently always returns true, so this can't really happen |
263 | throw_exception<std::runtime_error>("hexlify failed" ); |
264 | } |
265 | return output; |
266 | } |
267 | |
268 | template <class OutputString = std::string> |
269 | OutputString hexlify(StringPiece input) { |
270 | return hexlify<OutputString>(ByteRange{input}); |
271 | } |
272 | |
273 | /** |
274 | * Same functionality as Python's binascii.unhexlify. Returns true |
275 | * on successful conversion. |
276 | */ |
277 | template <class InputString, class OutputString> |
278 | bool unhexlify(const InputString& input, OutputString& output); |
279 | |
280 | template <class OutputString = std::string> |
281 | OutputString unhexlify(StringPiece input) { |
282 | OutputString output; |
283 | if (!unhexlify(input, output)) { |
284 | // unhexlify() fails if the input has non-hexidecimal characters, |
285 | // or if it doesn't consist of a whole number of bytes |
286 | throw_exception<std::domain_error>("unhexlify() called with non-hex input" ); |
287 | } |
288 | return output; |
289 | } |
290 | |
291 | /** |
292 | * A pretty-printer for numbers that appends suffixes of units of the |
293 | * given type. It prints 4 sig-figs of value with the most |
294 | * appropriate unit. |
295 | * |
296 | * If `addSpace' is true, we put a space between the units suffix and |
297 | * the value. |
298 | * |
299 | * Current types are: |
300 | * PRETTY_TIME - s, ms, us, ns, etc. |
301 | * PRETTY_TIME_HMS - h, m, s, ms, us, ns, etc. |
302 | * PRETTY_BYTES_METRIC - kB, MB, GB, etc (goes up by 10^3 = 1000 each time) |
303 | * PRETTY_BYTES - kB, MB, GB, etc (goes up by 2^10 = 1024 each time) |
304 | * PRETTY_BYTES_IEC - KiB, MiB, GiB, etc |
305 | * PRETTY_UNITS_METRIC - k, M, G, etc (goes up by 10^3 = 1000 each time) |
306 | * PRETTY_UNITS_BINARY - k, M, G, etc (goes up by 2^10 = 1024 each time) |
307 | * PRETTY_UNITS_BINARY_IEC - Ki, Mi, Gi, etc |
308 | * PRETTY_SI - full SI metric prefixes from yocto to Yotta |
309 | * http://en.wikipedia.org/wiki/Metric_prefix |
310 | * |
311 | * @author Mark Rabkin <mrabkin@fb.com> |
312 | */ |
313 | enum PrettyType { |
314 | PRETTY_TIME, |
315 | PRETTY_TIME_HMS, |
316 | |
317 | PRETTY_BYTES_METRIC, |
318 | PRETTY_BYTES_BINARY, |
319 | PRETTY_BYTES = PRETTY_BYTES_BINARY, |
320 | PRETTY_BYTES_BINARY_IEC, |
321 | PRETTY_BYTES_IEC = PRETTY_BYTES_BINARY_IEC, |
322 | |
323 | PRETTY_UNITS_METRIC, |
324 | PRETTY_UNITS_BINARY, |
325 | PRETTY_UNITS_BINARY_IEC, |
326 | |
327 | PRETTY_SI, |
328 | PRETTY_NUM_TYPES, |
329 | }; |
330 | |
331 | std::string prettyPrint(double val, PrettyType, bool addSpace = true); |
332 | |
333 | /** |
334 | * This utility converts StringPiece in pretty format (look above) to double, |
335 | * with progress information. Alters the StringPiece parameter |
336 | * to get rid of the already-parsed characters. |
337 | * Expects string in form <floating point number> {space}* [<suffix>] |
338 | * If string is not in correct format, utility finds longest valid prefix and |
339 | * if there at least one, returns double value based on that prefix and |
340 | * modifies string to what is left after parsing. Throws and std::range_error |
341 | * exception if there is no correct parse. |
342 | * Examples(for PRETTY_UNITS_METRIC): |
343 | * '10M' => 10 000 000 |
344 | * '10 M' => 10 000 000 |
345 | * '10' => 10 |
346 | * '10 Mx' => 10 000 000, prettyString == "x" |
347 | * 'abc' => throws std::range_error |
348 | */ |
349 | double prettyToDouble( |
350 | folly::StringPiece* const prettyString, |
351 | const PrettyType type); |
352 | |
353 | /** |
354 | * Same as prettyToDouble(folly::StringPiece*, PrettyType), but |
355 | * expects whole string to be correctly parseable. Throws std::range_error |
356 | * otherwise |
357 | */ |
358 | double prettyToDouble(folly::StringPiece prettyString, const PrettyType type); |
359 | |
360 | /** |
361 | * Write a hex dump of size bytes starting at ptr to out. |
362 | * |
363 | * The hex dump is formatted as follows: |
364 | * |
365 | * for the string "abcdefghijklmnopqrstuvwxyz\x02" |
366 | 00000000 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 |abcdefghijklmnop| |
367 | 00000010 71 72 73 74 75 76 77 78 79 7a 02 |qrstuvwxyz. | |
368 | * |
369 | * that is, we write 16 bytes per line, both as hex bytes and as printable |
370 | * characters. Non-printable characters are replaced with '.' |
371 | * Lines are written to out one by one (one StringPiece at a time) without |
372 | * delimiters. |
373 | */ |
374 | template <class OutIt> |
375 | void hexDump(const void* ptr, size_t size, OutIt out); |
376 | |
377 | /** |
378 | * Return the hex dump of size bytes starting at ptr as a string. |
379 | */ |
380 | std::string hexDump(const void* ptr, size_t size); |
381 | |
382 | /** |
383 | * Return a fbstring containing the description of the given errno value. |
384 | * Takes care not to overwrite the actual system errno, so calling |
385 | * errnoStr(errno) is valid. |
386 | */ |
387 | fbstring errnoStr(int err); |
388 | |
389 | /* |
390 | * Split a string into a list of tokens by delimiter. |
391 | * |
392 | * The split interface here supports different output types, selected |
393 | * at compile time: StringPiece, fbstring, or std::string. If you are |
394 | * using a vector to hold the output, it detects the type based on |
395 | * what your vector contains. If the output vector is not empty, split |
396 | * will append to the end of the vector. |
397 | * |
398 | * You can also use splitTo() to write the output to an arbitrary |
399 | * OutputIterator (e.g. std::inserter() on a std::set<>), in which |
400 | * case you have to tell the function the type. (Rationale: |
401 | * OutputIterators don't have a value_type, so we can't detect the |
402 | * type in splitTo without being told.) |
403 | * |
404 | * Examples: |
405 | * |
406 | * std::vector<folly::StringPiece> v; |
407 | * folly::split(":", "asd:bsd", v); |
408 | * |
409 | * std::set<StringPiece> s; |
410 | * folly::splitTo<StringPiece>(":", "asd:bsd:asd:csd", |
411 | * std::inserter(s, s.begin())); |
412 | * |
413 | * Split also takes a flag (ignoreEmpty) that indicates whether adjacent |
414 | * delimiters should be treated as one single separator (ignoring empty tokens) |
415 | * or not (generating empty tokens). |
416 | */ |
417 | |
418 | template <class Delim, class String, class OutputType> |
419 | void split( |
420 | const Delim& delimiter, |
421 | const String& input, |
422 | std::vector<OutputType>& out, |
423 | const bool ignoreEmpty = false); |
424 | |
425 | template <class T, class Allocator> |
426 | class fbvector; |
427 | |
428 | template <class Delim, class String, class OutputType> |
429 | void split( |
430 | const Delim& delimiter, |
431 | const String& input, |
432 | folly::fbvector<OutputType, std::allocator<OutputType>>& out, |
433 | const bool ignoreEmpty = false); |
434 | |
435 | template < |
436 | class OutputValueType, |
437 | class Delim, |
438 | class String, |
439 | class OutputIterator> |
440 | void splitTo( |
441 | const Delim& delimiter, |
442 | const String& input, |
443 | OutputIterator out, |
444 | const bool ignoreEmpty = false); |
445 | |
446 | /* |
447 | * Split a string into a fixed number of string pieces and/or numeric types |
448 | * by delimiter. Conversions are supported for any type which folly:to<> can |
449 | * target, including all overloads of parseTo(). Returns 'true' if the fields |
450 | * were all successfully populated. Returns 'false' if there were too few |
451 | * fields in the input, or too many fields if exact=true. Casting exceptions |
452 | * will not be caught. |
453 | * |
454 | * Examples: |
455 | * |
456 | * folly::StringPiece name, key, value; |
457 | * if (folly::split('\t', line, name, key, value)) |
458 | * ... |
459 | * |
460 | * folly::StringPiece name; |
461 | * double value; |
462 | * int id; |
463 | * if (folly::split('\t', line, name, value, id)) |
464 | * ... |
465 | * |
466 | * The 'exact' template parameter specifies how the function behaves when too |
467 | * many fields are present in the input string. When 'exact' is set to its |
468 | * default value of 'true', a call to split will fail if the number of fields in |
469 | * the input string does not exactly match the number of output parameters |
470 | * passed. If 'exact' is overridden to 'false', all remaining fields will be |
471 | * stored, unsplit, in the last field, as shown below: |
472 | * |
473 | * folly::StringPiece x, y. |
474 | * if (folly::split<false>(':', "a:b:c", x, y)) |
475 | * assert(x == "a" && y == "b:c"); |
476 | * |
477 | * Note that this will likely not work if the last field's target is of numeric |
478 | * type, in which case folly::to<> will throw an exception. |
479 | */ |
480 | namespace detail { |
481 | template <typename Void, typename OutputType> |
482 | struct IsConvertible : std::false_type {}; |
483 | |
484 | template <> |
485 | struct IsConvertible<void, decltype(std::ignore)> : std::true_type {}; |
486 | |
487 | template <typename OutputType> |
488 | struct IsConvertible< |
489 | void_t<decltype(parseTo(StringPiece{}, std::declval<OutputType&>()))>, |
490 | OutputType> : std::true_type {}; |
491 | } // namespace detail |
492 | template <typename OutputType> |
493 | struct IsConvertible : detail::IsConvertible<void, OutputType> {}; |
494 | |
495 | template <bool exact = true, class Delim, class... OutputTypes> |
496 | typename std::enable_if< |
497 | StrictConjunction<IsConvertible<OutputTypes>...>::value && |
498 | sizeof...(OutputTypes) >= 1, |
499 | bool>::type |
500 | split(const Delim& delimiter, StringPiece input, OutputTypes&... outputs); |
501 | |
502 | /* |
503 | * Join list of tokens. |
504 | * |
505 | * Stores a string representation of tokens in the same order with |
506 | * deliminer between each element. |
507 | */ |
508 | |
509 | template <class Delim, class Iterator, class String> |
510 | void join(const Delim& delimiter, Iterator begin, Iterator end, String& output); |
511 | |
512 | template <class Delim, class Container, class String> |
513 | void join(const Delim& delimiter, const Container& container, String& output) { |
514 | join(delimiter, container.begin(), container.end(), output); |
515 | } |
516 | |
517 | template <class Delim, class Value, class String> |
518 | void join( |
519 | const Delim& delimiter, |
520 | const std::initializer_list<Value>& values, |
521 | String& output) { |
522 | join(delimiter, values.begin(), values.end(), output); |
523 | } |
524 | |
525 | template <class Delim, class Container> |
526 | std::string join(const Delim& delimiter, const Container& container) { |
527 | std::string output; |
528 | join(delimiter, container.begin(), container.end(), output); |
529 | return output; |
530 | } |
531 | |
532 | template <class Delim, class Value> |
533 | std::string join( |
534 | const Delim& delimiter, |
535 | const std::initializer_list<Value>& values) { |
536 | std::string output; |
537 | join(delimiter, values.begin(), values.end(), output); |
538 | return output; |
539 | } |
540 | |
541 | template < |
542 | class Delim, |
543 | class Iterator, |
544 | typename std::enable_if<std::is_base_of< |
545 | std::forward_iterator_tag, |
546 | typename std::iterator_traits<Iterator>::iterator_category>::value>:: |
547 | type* = nullptr> |
548 | std::string join(const Delim& delimiter, Iterator begin, Iterator end) { |
549 | std::string output; |
550 | join(delimiter, begin, end, output); |
551 | return output; |
552 | } |
553 | |
554 | /** |
555 | * Returns a subpiece with all whitespace removed from the front of @sp. |
556 | * Whitespace means any of [' ', '\n', '\r', '\t']. |
557 | */ |
558 | StringPiece ltrimWhitespace(StringPiece sp); |
559 | |
560 | /** |
561 | * Returns a subpiece with all whitespace removed from the back of @sp. |
562 | * Whitespace means any of [' ', '\n', '\r', '\t']. |
563 | */ |
564 | StringPiece rtrimWhitespace(StringPiece sp); |
565 | |
566 | /** |
567 | * Returns a subpiece with all whitespace removed from the back and front of |
568 | * @sp. Whitespace means any of [' ', '\n', '\r', '\t']. |
569 | */ |
570 | inline StringPiece trimWhitespace(StringPiece sp) { |
571 | return ltrimWhitespace(rtrimWhitespace(sp)); |
572 | } |
573 | |
574 | /** |
575 | * Returns a subpiece with all whitespace removed from the front of @sp. |
576 | * Whitespace means any of [' ', '\n', '\r', '\t']. |
577 | * DEPRECATED: @see ltrimWhitespace @see rtrimWhitespace |
578 | */ |
579 | inline StringPiece skipWhitespace(StringPiece sp) { |
580 | return ltrimWhitespace(sp); |
581 | } |
582 | |
583 | /** |
584 | * Strips the leading and the trailing whitespace-only lines. Then looks for |
585 | * the least indented non-whitespace-only line and removes its amount of |
586 | * leading whitespace from every line. Assumes leading whitespace is either all |
587 | * spaces or all tabs. |
588 | * |
589 | * Purpose: including a multiline string literal in source code, indented to |
590 | * the level expected from context. |
591 | */ |
592 | std::string stripLeftMargin(std::string s); |
593 | |
594 | /** |
595 | * Fast, in-place lowercasing of ASCII alphabetic characters in strings. |
596 | * Leaves all other characters unchanged, including those with the 0x80 |
597 | * bit set. |
598 | * @param str String to convert |
599 | * @param length Length of str, in bytes |
600 | */ |
601 | void toLowerAscii(char* str, size_t length); |
602 | |
603 | inline void toLowerAscii(MutableStringPiece str) { |
604 | toLowerAscii(str.begin(), str.size()); |
605 | } |
606 | |
607 | inline void toLowerAscii(std::string& str) { |
608 | // str[0] is legal also if the string is empty. |
609 | toLowerAscii(&str[0], str.size()); |
610 | } |
611 | |
612 | } // namespace folly |
613 | |
614 | #include <folly/String-inl.h> |
615 | |