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