make `usingJEMalloc()` a constexpr when USE_JEMALLOC is defined
[folly.git] / folly / String-inl.h
1 /*
2  * Copyright 2017 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
19 #include <iterator>
20 #include <stdexcept>
21
22 #include <folly/CppAttributes.h>
23
24 #ifndef FOLLY_STRING_H_
25 #error This file may only be included from String.h
26 #endif
27
28 namespace folly {
29
30 namespace detail {
31 // Map from character code to value of one-character escape sequence
32 // ('\n' = 10 maps to 'n'), 'O' if the character should be printed as
33 // an octal escape sequence, or 'P' if the character is printable and
34 // should be printed as is.
35 extern const char cEscapeTable[];
36 } // namespace detail
37
38 template <class String>
39 void cEscape(StringPiece str, String& out) {
40   char esc[4];
41   esc[0] = '\\';
42   out.reserve(out.size() + str.size());
43   auto p = str.begin();
44   auto last = p;  // last regular character
45   // We advance over runs of regular characters (printable, not double-quote or
46   // backslash) and copy them in one go; this is faster than calling push_back
47   // repeatedly.
48   while (p != str.end()) {
49     char c = *p;
50     unsigned char v = static_cast<unsigned char>(c);
51     char e = detail::cEscapeTable[v];
52     if (e == 'P') {  // printable
53       ++p;
54     } else if (e == 'O') {  // octal
55       out.append(&*last, size_t(p - last));
56       esc[1] = '0' + ((v >> 6) & 7);
57       esc[2] = '0' + ((v >> 3) & 7);
58       esc[3] = '0' + (v & 7);
59       out.append(esc, 4);
60       ++p;
61       last = p;
62     } else {  // special 1-character escape
63       out.append(&*last, size_t(p - last));
64       esc[1] = e;
65       out.append(esc, 2);
66       ++p;
67       last = p;
68     }
69   }
70   out.append(&*last, size_t(p - last));
71 }
72
73 namespace detail {
74 // Map from the character code of the character following a backslash to
75 // the unescaped character if a valid one-character escape sequence
76 // ('n' maps to 10 = '\n'), 'O' if this is the first character of an
77 // octal escape sequence, 'X' if this is the first character of a
78 // hexadecimal escape sequence, or 'I' if this escape sequence is invalid.
79 extern const char cUnescapeTable[];
80
81 // Map from the character code to the hex value, or 16 if invalid hex char.
82 extern const unsigned char hexTable[];
83 } // namespace detail
84
85 template <class String>
86 void cUnescape(StringPiece str, String& out, bool strict) {
87   out.reserve(out.size() + str.size());
88   auto p = str.begin();
89   auto last = p;  // last regular character (not part of an escape sequence)
90   // We advance over runs of regular characters (not backslash) and copy them
91   // in one go; this is faster than calling push_back repeatedly.
92   while (p != str.end()) {
93     char c = *p;
94     if (c != '\\') {  // normal case
95       ++p;
96       continue;
97     }
98     out.append(&*last, p - last);
99     if (p == str.end()) {  // backslash at end of string
100       if (strict) {
101         throw std::invalid_argument("incomplete escape sequence");
102       }
103       out.push_back('\\');
104       last = p;
105       continue;
106     }
107     ++p;
108     char e = detail::cUnescapeTable[static_cast<unsigned char>(*p)];
109     if (e == 'O') {  // octal
110       unsigned char val = 0;
111       for (int i = 0; i < 3 && p != str.end() && *p >= '0' && *p <= '7';
112            ++i, ++p) {
113         val = (val << 3) | (*p - '0');
114       }
115       out.push_back(val);
116       last = p;
117     } else if (e == 'X') {  // hex
118       ++p;
119       if (p == str.end()) {  // \x at end of string
120         if (strict) {
121           throw std::invalid_argument("incomplete hex escape sequence");
122         }
123         out.append("\\x");
124         last = p;
125         continue;
126       }
127       unsigned char val = 0;
128       unsigned char h;
129       for (; (p != str.end() &&
130               (h = detail::hexTable[static_cast<unsigned char>(*p)]) < 16);
131            ++p) {
132         val = (val << 4) | h;
133       }
134       out.push_back(val);
135       last = p;
136     } else if (e == 'I') {  // invalid
137       if (strict) {
138         throw std::invalid_argument("invalid escape sequence");
139       }
140       out.push_back('\\');
141       out.push_back(*p);
142       ++p;
143       last = p;
144     } else {  // standard escape sequence, \' etc
145       out.push_back(e);
146       ++p;
147       last = p;
148     }
149   }
150   out.append(&*last, p - last);
151 }
152
153 namespace detail {
154 // Map from character code to escape mode:
155 // 0 = pass through
156 // 1 = unused
157 // 2 = pass through in PATH mode
158 // 3 = space, replace with '+' in QUERY mode
159 // 4 = percent-encode
160 extern const unsigned char uriEscapeTable[];
161 } // namespace detail
162
163 template <class String>
164 void uriEscape(StringPiece str, String& out, UriEscapeMode mode) {
165   static const char hexValues[] = "0123456789abcdef";
166   char esc[3];
167   esc[0] = '%';
168   // Preallocate assuming that 25% of the input string will be escaped
169   out.reserve(out.size() + str.size() + 3 * (str.size() / 4));
170   auto p = str.begin();
171   auto last = p;  // last regular character
172   // We advance over runs of passthrough characters and copy them in one go;
173   // this is faster than calling push_back repeatedly.
174   unsigned char minEncode = static_cast<unsigned char>(mode);
175   while (p != str.end()) {
176     char c = *p;
177     unsigned char v = static_cast<unsigned char>(c);
178     unsigned char discriminator = detail::uriEscapeTable[v];
179     if (LIKELY(discriminator <= minEncode)) {
180       ++p;
181     } else if (mode == UriEscapeMode::QUERY && discriminator == 3) {
182       out.append(&*last, size_t(p - last));
183       out.push_back('+');
184       ++p;
185       last = p;
186     } else {
187       out.append(&*last, size_t(p - last));
188       esc[1] = hexValues[v >> 4];
189       esc[2] = hexValues[v & 0x0f];
190       out.append(esc, 3);
191       ++p;
192       last = p;
193     }
194   }
195   out.append(&*last, size_t(p - last));
196 }
197
198 template <class String>
199 void uriUnescape(StringPiece str, String& out, UriEscapeMode mode) {
200   out.reserve(out.size() + str.size());
201   auto p = str.begin();
202   auto last = p;
203   // We advance over runs of passthrough characters and copy them in one go;
204   // this is faster than calling push_back repeatedly.
205   while (p != str.end()) {
206     char c = *p;
207     switch (c) {
208     case '%':
209       {
210         if (UNLIKELY(std::distance(p, str.end()) < 3)) {
211           throw std::invalid_argument("incomplete percent encode sequence");
212         }
213         auto h1 = detail::hexTable[static_cast<unsigned char>(p[1])];
214         auto h2 = detail::hexTable[static_cast<unsigned char>(p[2])];
215         if (UNLIKELY(h1 == 16 || h2 == 16)) {
216           throw std::invalid_argument("invalid percent encode sequence");
217         }
218         out.append(&*last, size_t(p - last));
219         out.push_back((h1 << 4) | h2);
220         p += 3;
221         last = p;
222         break;
223       }
224     case '+':
225       if (mode == UriEscapeMode::QUERY) {
226         out.append(&*last, size_t(p - last));
227         out.push_back(' ');
228         ++p;
229         last = p;
230         break;
231       }
232       // else fallthrough
233       FOLLY_FALLTHROUGH;
234     default:
235       ++p;
236       break;
237     }
238   }
239   out.append(&*last, size_t(p - last));
240 }
241
242 namespace detail {
243
244 /*
245  * The following functions are type-overloaded helpers for
246  * internalSplit().
247  */
248 inline size_t delimSize(char)          { return 1; }
249 inline size_t delimSize(StringPiece s) { return s.size(); }
250 inline bool atDelim(const char* s, char c) {
251  return *s == c;
252 }
253 inline bool atDelim(const char* s, StringPiece sp) {
254   return !std::memcmp(s, sp.start(), sp.size());
255 }
256
257 // These are used to short-circuit internalSplit() in the case of
258 // 1-character strings.
259 inline char delimFront(char c) {
260   // This one exists only for compile-time; it should never be called.
261   std::abort();
262   return c;
263 }
264 inline char delimFront(StringPiece s) {
265   assert(!s.empty() && s.start() != nullptr);
266   return *s.start();
267 }
268
269 /*
270  * Shared implementation for all the split() overloads.
271  *
272  * This uses some external helpers that are overloaded to let this
273  * algorithm be more performant if the deliminator is a single
274  * character instead of a whole string.
275  *
276  * @param ignoreEmpty iff true, don't copy empty segments to output
277  */
278 template <class OutStringT, class DelimT, class OutputIterator>
279 void internalSplit(DelimT delim, StringPiece sp, OutputIterator out,
280     bool ignoreEmpty) {
281   assert(sp.empty() || sp.start() != nullptr);
282
283   const char* s = sp.start();
284   const size_t strSize = sp.size();
285   const size_t dSize = delimSize(delim);
286
287   if (dSize > strSize || dSize == 0) {
288     if (!ignoreEmpty || strSize > 0) {
289       *out++ = to<OutStringT>(sp);
290     }
291     return;
292   }
293   if (boost::is_same<DelimT,StringPiece>::value && dSize == 1) {
294     // Call the char version because it is significantly faster.
295     return internalSplit<OutStringT>(delimFront(delim), sp, out,
296       ignoreEmpty);
297   }
298
299   size_t tokenStartPos = 0;
300   size_t tokenSize = 0;
301   for (size_t i = 0; i <= strSize - dSize; ++i) {
302     if (atDelim(&s[i], delim)) {
303       if (!ignoreEmpty || tokenSize > 0) {
304         *out++ = to<OutStringT>(sp.subpiece(tokenStartPos, tokenSize));
305       }
306
307       tokenStartPos = i + dSize;
308       tokenSize = 0;
309       i += dSize - 1;
310     } else {
311       ++tokenSize;
312     }
313   }
314   tokenSize = strSize - tokenStartPos;
315   if (!ignoreEmpty || tokenSize > 0) {
316     *out++ = to<OutStringT>(sp.subpiece(tokenStartPos, tokenSize));
317   }
318 }
319
320 template <class String> StringPiece prepareDelim(const String& s) {
321   return StringPiece(s);
322 }
323 inline char prepareDelim(char c) { return c; }
324
325 template <bool exact, class Delim, class OutputType>
326 bool splitFixed(const Delim& delimiter, StringPiece input, OutputType& output) {
327   static_assert(
328       exact || std::is_same<OutputType, StringPiece>::value ||
329           IsSomeString<OutputType>::value,
330       "split<false>() requires that the last argument be a string type");
331   if (exact && UNLIKELY(std::string::npos != input.find(delimiter))) {
332     return false;
333   }
334   output = folly::to<OutputType>(input);
335   return true;
336 }
337
338 template <bool exact, class Delim, class OutputType, class... OutputTypes>
339 bool splitFixed(
340     const Delim& delimiter,
341     StringPiece input,
342     OutputType& outHead,
343     OutputTypes&... outTail) {
344   size_t cut = input.find(delimiter);
345   if (UNLIKELY(cut == std::string::npos)) {
346     return false;
347   }
348   StringPiece head(input.begin(), input.begin() + cut);
349   StringPiece tail(input.begin() + cut + detail::delimSize(delimiter),
350                    input.end());
351   if (LIKELY(splitFixed<exact>(delimiter, tail, outTail...))) {
352     outHead = folly::to<OutputType>(head);
353     return true;
354   }
355   return false;
356 }
357
358 } // namespace detail
359
360 //////////////////////////////////////////////////////////////////////
361
362 template <class Delim, class String, class OutputType>
363 void split(const Delim& delimiter,
364            const String& input,
365            std::vector<OutputType>& out,
366            bool ignoreEmpty) {
367   detail::internalSplit<OutputType>(
368     detail::prepareDelim(delimiter),
369     StringPiece(input),
370     std::back_inserter(out),
371     ignoreEmpty);
372 }
373
374 template <class Delim, class String, class OutputType>
375 void split(const Delim& delimiter,
376            const String& input,
377            fbvector<OutputType>& out,
378            bool ignoreEmpty) {
379   detail::internalSplit<OutputType>(
380     detail::prepareDelim(delimiter),
381     StringPiece(input),
382     std::back_inserter(out),
383     ignoreEmpty);
384 }
385
386 template <
387     class OutputValueType,
388     class Delim,
389     class String,
390     class OutputIterator>
391 void splitTo(const Delim& delimiter,
392              const String& input,
393              OutputIterator out,
394              bool ignoreEmpty) {
395   detail::internalSplit<OutputValueType>(
396     detail::prepareDelim(delimiter),
397     StringPiece(input),
398     out,
399     ignoreEmpty);
400 }
401
402 template <bool exact, class Delim, class... OutputTypes>
403 typename std::enable_if<
404     AllConvertible<OutputTypes...>::value && sizeof...(OutputTypes) >= 1,
405     bool>::type
406 split(const Delim& delimiter, StringPiece input, OutputTypes&... outputs) {
407   return detail::splitFixed<exact>(
408       detail::prepareDelim(delimiter), input, outputs...);
409 }
410
411 namespace detail {
412
413 /*
414  * If a type can have its string size determined cheaply, we can more
415  * efficiently append it in a loop (see internalJoinAppend). Note that the
416  * struct need not conform to the std::string api completely (ex. does not need
417  * to implement append()).
418  */
419 template <class T> struct IsSizableString {
420   enum { value = IsSomeString<T>::value
421          || std::is_same<T, StringPiece>::value };
422 };
423
424 template <class Iterator>
425 struct IsSizableStringContainerIterator :
426   IsSizableString<typename std::iterator_traits<Iterator>::value_type> {
427 };
428
429 template <class Delim, class Iterator, class String>
430 void internalJoinAppend(Delim delimiter,
431                         Iterator begin,
432                         Iterator end,
433                         String& output) {
434   assert(begin != end);
435   if (std::is_same<Delim, StringPiece>::value &&
436       delimSize(delimiter) == 1) {
437     internalJoinAppend(delimFront(delimiter), begin, end, output);
438     return;
439   }
440   toAppend(*begin, &output);
441   while (++begin != end) {
442     toAppend(delimiter, *begin, &output);
443   }
444 }
445
446 template <class Delim, class Iterator, class String>
447 typename std::enable_if<IsSizableStringContainerIterator<Iterator>::value>::type
448 internalJoin(Delim delimiter,
449              Iterator begin,
450              Iterator end,
451              String& output) {
452   output.clear();
453   if (begin == end) {
454     return;
455   }
456   const size_t dsize = delimSize(delimiter);
457   Iterator it = begin;
458   size_t size = it->size();
459   while (++it != end) {
460     size += dsize + it->size();
461   }
462   output.reserve(size);
463   internalJoinAppend(delimiter, begin, end, output);
464 }
465
466 template <class Delim, class Iterator, class String>
467 typename
468 std::enable_if<!IsSizableStringContainerIterator<Iterator>::value>::type
469 internalJoin(Delim delimiter,
470              Iterator begin,
471              Iterator end,
472              String& output) {
473   output.clear();
474   if (begin == end) {
475     return;
476   }
477   internalJoinAppend(delimiter, begin, end, output);
478 }
479
480 } // namespace detail
481
482 template <class Delim, class Iterator, class String>
483 void join(const Delim& delimiter,
484           Iterator begin,
485           Iterator end,
486           String& output) {
487   detail::internalJoin(
488     detail::prepareDelim(delimiter),
489     begin,
490     end,
491     output);
492 }
493
494 template <class OutputString>
495 void backslashify(
496     folly::StringPiece input,
497     OutputString& output,
498     bool hex_style) {
499   static const char hexValues[] = "0123456789abcdef";
500   output.clear();
501   output.reserve(3 * input.size());
502   for (unsigned char c : input) {
503     // less than space or greater than '~' are considered unprintable
504     if (c < 0x20 || c > 0x7e || c == '\\') {
505       bool hex_append = false;
506       output.push_back('\\');
507       if (hex_style) {
508         hex_append = true;
509       } else {
510         if (c == '\r') {
511           output += 'r';
512         } else if (c == '\n') {
513           output += 'n';
514         } else if (c == '\t') {
515           output += 't';
516         } else if (c == '\a') {
517           output += 'a';
518         } else if (c == '\b') {
519           output += 'b';
520         } else if (c == '\0') {
521           output += '0';
522         } else if (c == '\\') {
523           output += '\\';
524         } else {
525           hex_append = true;
526         }
527       }
528       if (hex_append) {
529         output.push_back('x');
530         output.push_back(hexValues[(c >> 4) & 0xf]);
531         output.push_back(hexValues[c & 0xf]);
532       }
533     } else {
534       output += c;
535     }
536   }
537 }
538
539 template <class String1, class String2>
540 void humanify(const String1& input, String2& output) {
541   size_t numUnprintable = 0;
542   size_t numPrintablePrefix = 0;
543   for (unsigned char c : input) {
544     if (c < 0x20 || c > 0x7e || c == '\\') {
545       ++numUnprintable;
546     }
547     if (numUnprintable == 0) {
548       ++numPrintablePrefix;
549     }
550   }
551
552   // hexlify doubles a string's size; backslashify can potentially
553   // explode it by 4x.  Now, the printable range of the ascii
554   // "spectrum" is around 95 out of 256 values, so a "random" binary
555   // string should be around 60% unprintable.  We use a 50% hueristic
556   // here, so if a string is 60% unprintable, then we just use hex
557   // output.  Otherwise we backslash.
558   //
559   // UTF8 is completely ignored; as a result, utf8 characters will
560   // likely be \x escaped (since most common glyphs fit in two bytes).
561   // This is a tradeoff of complexity/speed instead of a convenience
562   // that likely would rarely matter.  Moreover, this function is more
563   // about displaying underlying bytes, not about displaying glyphs
564   // from languages.
565   if (numUnprintable == 0) {
566     output = input;
567   } else if (5 * numUnprintable >= 3 * input.size()) {
568     // However!  If we have a "meaningful" prefix of printable
569     // characters, say 20% of the string, we backslashify under the
570     // assumption viewing the prefix as ascii is worth blowing the
571     // output size up a bit.
572     if (5 * numPrintablePrefix >= input.size()) {
573       backslashify(input, output);
574     } else {
575       output = "0x";
576       hexlify(input, output, true /* append output */);
577     }
578   } else {
579     backslashify(input, output);
580   }
581 }
582
583 template <class InputString, class OutputString>
584 bool hexlify(const InputString& input, OutputString& output,
585              bool append_output) {
586   if (!append_output) {
587     output.clear();
588   }
589
590   static char hexValues[] = "0123456789abcdef";
591   auto j = output.size();
592   output.resize(2 * input.size() + output.size());
593   for (size_t i = 0; i < input.size(); ++i) {
594     int ch = input[i];
595     output[j++] = hexValues[(ch >> 4) & 0xf];
596     output[j++] = hexValues[ch & 0xf];
597   }
598   return true;
599 }
600
601 template <class InputString, class OutputString>
602 bool unhexlify(const InputString& input, OutputString& output) {
603   if (input.size() % 2 != 0) {
604     return false;
605   }
606   output.resize(input.size() / 2);
607   int j = 0;
608
609   for (size_t i = 0; i < input.size(); i += 2) {
610     int highBits = detail::hexTable[static_cast<uint8_t>(input[i])];
611     int lowBits = detail::hexTable[static_cast<uint8_t>(input[i + 1])];
612     if ((highBits | lowBits) & 0x10) {
613       // One of the characters wasn't a hex digit
614       return false;
615     }
616     output[j++] = (highBits << 4) + lowBits;
617   }
618   return true;
619 }
620
621 namespace detail {
622 /**
623  * Hex-dump at most 16 bytes starting at offset from a memory area of size
624  * bytes.  Return the number of bytes actually dumped.
625  */
626 size_t hexDumpLine(const void* ptr, size_t offset, size_t size,
627                    std::string& line);
628 } // namespace detail
629
630 template <class OutIt>
631 void hexDump(const void* ptr, size_t size, OutIt out) {
632   size_t offset = 0;
633   std::string line;
634   while (offset < size) {
635     offset += detail::hexDumpLine(ptr, offset, size, line);
636     *out++ = line;
637   }
638 }
639
640 } // namespace folly