1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
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 <folly/String.h>
18 
19 #include <cctype>
20 #include <cerrno>
21 #include <cstdarg>
22 #include <cstring>
23 #include <iterator>
24 #include <sstream>
25 #include <stdexcept>
26 
27 #include <glog/logging.h>
28 
29 #include <folly/Portability.h>
30 #include <folly/ScopeGuard.h>
31 #include <folly/container/Array.h>
32 
33 namespace folly {
34 
35 static_assert(IsConvertible<float>::value, "");
36 static_assert(IsConvertible<int>::value, "");
37 static_assert(IsConvertible<bool>::value, "");
38 static_assert(IsConvertible<int>::value, "");
39 static_assert(!IsConvertible<std::vector<int>>::value, "");
40 
41 namespace detail {
42 
43 struct string_table_c_escape_make_item {
operator ()folly::detail::string_table_c_escape_make_item44   constexpr char operator()(std::size_t index) const {
45     // clang-format off
46     return
47         index == '"' ? '"' :
48         index == '\\' ? '\\' :
49         index == '?' ? '?' :
50         index == '\n' ? 'n' :
51         index == '\r' ? 'r' :
52         index == '\t' ? 't' :
53         index < 32 || index > 126 ? 'O' : // octal
54         'P'; // printable
55     // clang-format on
56   }
57 };
58 
59 struct string_table_c_unescape_make_item {
operator ()folly::detail::string_table_c_unescape_make_item60   constexpr char operator()(std::size_t index) const {
61     // clang-format off
62     return
63         index == '\'' ? '\'' :
64         index == '?' ? '?' :
65         index == '\\' ? '\\' :
66         index == '"' ? '"' :
67         index == 'a' ? '\a' :
68         index == 'b' ? '\b' :
69         index == 'f' ? '\f' :
70         index == 'n' ? '\n' :
71         index == 'r' ? '\r' :
72         index == 't' ? '\t' :
73         index == 'v' ? '\v' :
74         index >= '0' && index <= '7' ? 'O' : // octal
75         index == 'x' ? 'X' : // hex
76         'I'; // invalid
77     // clang-format on
78   }
79 };
80 
81 struct string_table_hex_make_item {
operator ()folly::detail::string_table_hex_make_item82   constexpr unsigned char operator()(std::size_t index) const {
83     // clang-format off
84     return static_cast<unsigned char>(
85         index >= '0' && index <= '9' ? index - '0' :
86         index >= 'a' && index <= 'f' ? index - 'a' + 10 :
87         index >= 'A' && index <= 'F' ? index - 'A' + 10 :
88         16);
89     // clang-format on
90   }
91 };
92 
93 struct string_table_uri_escape_make_item {
94   //  0 = passthrough
95   //  1 = unused
96   //  2 = safe in path (/)
97   //  3 = space (replace with '+' in query)
98   //  4 = always percent-encode
operator ()folly::detail::string_table_uri_escape_make_item99   constexpr unsigned char operator()(std::size_t index) const {
100     // clang-format off
101     return
102         index >= '0' && index <= '9' ? 0 :
103         index >= 'A' && index <= 'Z' ? 0 :
104         index >= 'a' && index <= 'z' ? 0 :
105         index == '-' ? 0 :
106         index == '_' ? 0 :
107         index == '.' ? 0 :
108         index == '~' ? 0 :
109         index == '/' ? 2 :
110         index == ' ' ? 3 :
111         4;
112     // clang-format on
113   }
114 };
115 
116 FOLLY_STORAGE_CONSTEXPR decltype(cEscapeTable) cEscapeTable =
117     make_array_with<256>(string_table_c_escape_make_item{});
118 FOLLY_STORAGE_CONSTEXPR decltype(cUnescapeTable) cUnescapeTable =
119     make_array_with<256>(string_table_c_unescape_make_item{});
120 FOLLY_STORAGE_CONSTEXPR decltype(hexTable) hexTable =
121     make_array_with<256>(string_table_hex_make_item{});
122 FOLLY_STORAGE_CONSTEXPR decltype(uriEscapeTable) uriEscapeTable =
123     make_array_with<256>(string_table_uri_escape_make_item{});
124 
125 } // namespace detail
126 
is_oddspace(char c)127 static inline bool is_oddspace(char c) {
128   return c == '\n' || c == '\t' || c == '\r';
129 }
130 
ltrimWhitespace(StringPiece sp)131 StringPiece ltrimWhitespace(StringPiece sp) {
132   // Spaces other than ' ' characters are less common but should be
133   // checked.  This configuration where we loop on the ' '
134   // separately from oddspaces was empirically fastest.
135 
136   while (true) {
137     while (!sp.empty() && sp.front() == ' ') {
138       sp.pop_front();
139     }
140     if (!sp.empty() && is_oddspace(sp.front())) {
141       sp.pop_front();
142       continue;
143     }
144 
145     return sp;
146   }
147 }
148 
rtrimWhitespace(StringPiece sp)149 StringPiece rtrimWhitespace(StringPiece sp) {
150   // Spaces other than ' ' characters are less common but should be
151   // checked.  This configuration where we loop on the ' '
152   // separately from oddspaces was empirically fastest.
153 
154   while (true) {
155     while (!sp.empty() && sp.back() == ' ') {
156       sp.pop_back();
157     }
158     if (!sp.empty() && is_oddspace(sp.back())) {
159       sp.pop_back();
160       continue;
161     }
162 
163     return sp;
164   }
165 }
166 
167 namespace {
168 
stringAppendfImplHelper(char * buf,size_t bufsize,const char * format,va_list args)169 int stringAppendfImplHelper(
170     char* buf, size_t bufsize, const char* format, va_list args) {
171   va_list args_copy;
172   va_copy(args_copy, args);
173   int bytes_used = vsnprintf(buf, bufsize, format, args_copy);
174   va_end(args_copy);
175   return bytes_used;
176 }
177 
stringAppendfImpl(std::string & output,const char * format,va_list args)178 void stringAppendfImpl(std::string& output, const char* format, va_list args) {
179   // Very simple; first, try to avoid an allocation by using an inline
180   // buffer.  If that fails to hold the output string, allocate one on
181   // the heap, use it instead.
182   //
183   // It is hard to guess the proper size of this buffer; some
184   // heuristics could be based on the number of format characters, or
185   // static analysis of a codebase.  Or, we can just pick a number
186   // that seems big enough for simple cases (say, one line of text on
187   // a terminal) without being large enough to be concerning as a
188   // stack variable.
189   std::array<char, 128> inline_buffer;
190 
191   int bytes_used = stringAppendfImplHelper(
192       inline_buffer.data(), inline_buffer.size(), format, args);
193   if (bytes_used < 0) {
194     throw std::runtime_error(to<std::string>(
195         "Invalid format string; snprintf returned negative "
196         "with format string: ",
197         format));
198   }
199 
200   if (static_cast<size_t>(bytes_used) < inline_buffer.size()) {
201     output.append(inline_buffer.data(), size_t(bytes_used));
202     return;
203   }
204 
205   // Couldn't fit.  Heap allocate a buffer, oh well.
206   std::unique_ptr<char[]> heap_buffer(new char[size_t(bytes_used + 1)]);
207   int final_bytes_used = stringAppendfImplHelper(
208       heap_buffer.get(), size_t(bytes_used + 1), format, args);
209   // The second call can take fewer bytes if, for example, we were printing a
210   // string buffer with null-terminating char using a width specifier -
211   // vsnprintf("%.*s", buf.size(), buf)
212   CHECK(bytes_used >= final_bytes_used);
213 
214   // We don't keep the trailing '\0' in our output string
215   output.append(heap_buffer.get(), size_t(final_bytes_used));
216 }
217 
218 } // namespace
219 
stringPrintf(const char * format,...)220 std::string stringPrintf(const char* format, ...) {
221   va_list ap;
222   va_start(ap, format);
223   SCOPE_EXIT { va_end(ap); };
224   return stringVPrintf(format, ap);
225 }
226 
stringVPrintf(const char * format,va_list ap)227 std::string stringVPrintf(const char* format, va_list ap) {
228   std::string ret;
229   stringAppendfImpl(ret, format, ap);
230   return ret;
231 }
232 
233 // Basic declarations; allow for parameters of strings and string
234 // pieces to be specified.
stringAppendf(std::string * output,const char * format,...)235 std::string& stringAppendf(std::string* output, const char* format, ...) {
236   va_list ap;
237   va_start(ap, format);
238   SCOPE_EXIT { va_end(ap); };
239   return stringVAppendf(output, format, ap);
240 }
241 
stringVAppendf(std::string * output,const char * format,va_list ap)242 std::string& stringVAppendf(
243     std::string* output, const char* format, va_list ap) {
244   stringAppendfImpl(*output, format, ap);
245   return *output;
246 }
247 
stringPrintf(std::string * output,const char * format,...)248 void stringPrintf(std::string* output, const char* format, ...) {
249   va_list ap;
250   va_start(ap, format);
251   SCOPE_EXIT { va_end(ap); };
252   return stringVPrintf(output, format, ap);
253 }
254 
stringVPrintf(std::string * output,const char * format,va_list ap)255 void stringVPrintf(std::string* output, const char* format, va_list ap) {
256   output->clear();
257   stringAppendfImpl(*output, format, ap);
258 }
259 
260 namespace {
261 
262 struct PrettySuffix {
263   const char* suffix;
264   double val;
265 };
266 
267 const PrettySuffix kPrettyTimeSuffixes[] = {
268     {"s ", 1e0L},
269     {"ms", 1e-3L},
270     {"us", 1e-6L},
271     {"ns", 1e-9L},
272     {"ps", 1e-12L},
273     {"s ", 0},
274     {nullptr, 0},
275 };
276 
277 const PrettySuffix kPrettyTimeHmsSuffixes[] = {
278     {"h ", 60L * 60L},
279     {"m ", 60L},
280     {"s ", 1e0L},
281     {"ms", 1e-3L},
282     {"us", 1e-6L},
283     {"ns", 1e-9L},
284     {"ps", 1e-12L},
285     {"s ", 0},
286     {nullptr, 0},
287 };
288 
289 const PrettySuffix kPrettyBytesMetricSuffixes[] = {
290     {"EB", 1e18L},
291     {"PB", 1e15L},
292     {"TB", 1e12L},
293     {"GB", 1e9L},
294     {"MB", 1e6L},
295     {"kB", 1e3L},
296     {"B ", 0L},
297     {nullptr, 0},
298 };
299 
300 const PrettySuffix kPrettyBytesBinarySuffixes[] = {
301     {"EB", int64_t(1) << 60},
302     {"PB", int64_t(1) << 50},
303     {"TB", int64_t(1) << 40},
304     {"GB", int64_t(1) << 30},
305     {"MB", int64_t(1) << 20},
306     {"kB", int64_t(1) << 10},
307     {"B ", 0L},
308     {nullptr, 0},
309 };
310 
311 const PrettySuffix kPrettyBytesBinaryIECSuffixes[] = {
312     {"EiB", int64_t(1) << 60},
313     {"PiB", int64_t(1) << 50},
314     {"TiB", int64_t(1) << 40},
315     {"GiB", int64_t(1) << 30},
316     {"MiB", int64_t(1) << 20},
317     {"KiB", int64_t(1) << 10},
318     {"B  ", 0L},
319     {nullptr, 0},
320 };
321 
322 const PrettySuffix kPrettyUnitsMetricSuffixes[] = {
323     {"qntl", 1e18L},
324     {"qdrl", 1e15L},
325     {"tril", 1e12L},
326     {"bil", 1e9L},
327     {"M", 1e6L},
328     {"k", 1e3L},
329     {" ", 0},
330     {nullptr, 0},
331 };
332 
333 const PrettySuffix kPrettyUnitsBinarySuffixes[] = {
334     {"E", int64_t(1) << 60},
335     {"P", int64_t(1) << 50},
336     {"T", int64_t(1) << 40},
337     {"G", int64_t(1) << 30},
338     {"M", int64_t(1) << 20},
339     {"k", int64_t(1) << 10},
340     {" ", 0},
341     {nullptr, 0},
342 };
343 
344 const PrettySuffix kPrettyUnitsBinaryIECSuffixes[] = {
345     {"Ei", int64_t(1) << 60},
346     {"Pi", int64_t(1) << 50},
347     {"Ti", int64_t(1) << 40},
348     {"Gi", int64_t(1) << 30},
349     {"Mi", int64_t(1) << 20},
350     {"Ki", int64_t(1) << 10},
351     {"  ", 0},
352     {nullptr, 0},
353 };
354 
355 const PrettySuffix kPrettySISuffixes[] = {
356     {"Y", 1e24L},  {"Z", 1e21L},  {"E", 1e18L},  {"P", 1e15L},  {"T", 1e12L},
357     {"G", 1e9L},   {"M", 1e6L},   {"k", 1e3L},   {"h", 1e2L},   {"da", 1e1L},
358     {"d", 1e-1L},  {"c", 1e-2L},  {"m", 1e-3L},  {"u", 1e-6L},  {"n", 1e-9L},
359     {"p", 1e-12L}, {"f", 1e-15L}, {"a", 1e-18L}, {"z", 1e-21L}, {"y", 1e-24L},
360     {" ", 0},      {nullptr, 0},
361 };
362 
363 const PrettySuffix* const kPrettySuffixes[PRETTY_NUM_TYPES] = {
364     kPrettyTimeSuffixes,
365     kPrettyTimeHmsSuffixes,
366     kPrettyBytesMetricSuffixes,
367     kPrettyBytesBinarySuffixes,
368     kPrettyBytesBinaryIECSuffixes,
369     kPrettyUnitsMetricSuffixes,
370     kPrettyUnitsBinarySuffixes,
371     kPrettyUnitsBinaryIECSuffixes,
372     kPrettySISuffixes,
373 };
374 
375 } // namespace
376 
prettyPrint(double val,PrettyType type,bool addSpace)377 std::string prettyPrint(double val, PrettyType type, bool addSpace) {
378   char buf[100];
379 
380   // pick the suffixes to use
381   assert(type >= 0);
382   assert(type < PRETTY_NUM_TYPES);
383   const PrettySuffix* suffixes = kPrettySuffixes[type];
384 
385   // find the first suffix we're bigger than -- then use it
386   double abs_val = fabs(val);
387   for (int i = 0; suffixes[i].suffix; ++i) {
388     if (abs_val >= suffixes[i].val) {
389       snprintf(
390           buf,
391           sizeof buf,
392           "%.4g%s%s",
393           (suffixes[i].val ? (val / suffixes[i].val) : val),
394           (addSpace ? " " : ""),
395           suffixes[i].suffix);
396       return std::string(buf);
397     }
398   }
399 
400   // no suffix, we've got a tiny value -- just print it in sci-notation
401   snprintf(buf, sizeof buf, "%.4g", val);
402   return std::string(buf);
403 }
404 
405 // TODO:
406 // 1) Benchmark & optimize
prettyToDouble(folly::StringPiece * const prettyString,const PrettyType type)407 double prettyToDouble(
408     folly::StringPiece* const prettyString, const PrettyType type) {
409   auto value = folly::to<double>(prettyString);
410   while (!prettyString->empty() && std::isspace(prettyString->front())) {
411     prettyString->advance(1); // Skipping spaces between number and suffix
412   }
413   const PrettySuffix* suffixes = kPrettySuffixes[type];
414   int longestPrefixLen = -1;
415   int bestPrefixId = -1;
416   for (int j = 0; suffixes[j].suffix; ++j) {
417     if (suffixes[j].suffix[0] == ' ') { // Checking for " " -> number rule.
418       if (longestPrefixLen == -1) {
419         longestPrefixLen = 0; // No characters to skip
420         bestPrefixId = j;
421       }
422     } else if (prettyString->startsWith(suffixes[j].suffix)) {
423       int suffixLen = int(strlen(suffixes[j].suffix));
424       // We are looking for a longest suffix matching prefix of the string
425       // after numeric value. We need this in case suffixes have common prefix.
426       if (suffixLen > longestPrefixLen) {
427         longestPrefixLen = suffixLen;
428         bestPrefixId = j;
429       }
430     }
431   }
432   if (bestPrefixId == -1) { // No valid suffix rule found
433     throw std::invalid_argument(folly::to<std::string>(
434         "Unable to parse suffix \"", *prettyString, "\""));
435   }
436   prettyString->advance(size_t(longestPrefixLen));
437   return suffixes[bestPrefixId].val ? value * suffixes[bestPrefixId].val
438                                     : value;
439 }
440 
prettyToDouble(folly::StringPiece prettyString,const PrettyType type)441 double prettyToDouble(folly::StringPiece prettyString, const PrettyType type) {
442   double result = prettyToDouble(&prettyString, type);
443   detail::enforceWhitespace(prettyString);
444   return result;
445 }
446 
hexDump(const void * ptr,size_t size)447 std::string hexDump(const void* ptr, size_t size) {
448   std::ostringstream os;
449   hexDump(ptr, size, std::ostream_iterator<StringPiece>(os, "\n"));
450   return os.str();
451 }
452 
453 // There are two variants of `strerror_r` function, one returns
454 // `int`, and another returns `char*`. Selecting proper version using
455 // preprocessor macros portably is extremely hard.
456 //
457 // For example, on Android function signature depends on `__USE_GNU` and
458 // `__ANDROID_API__` macros (https://git.io/fjBBE).
459 //
460 // So we are using C++ overloading trick: we pass a pointer of
461 // `strerror_r` to `invoke_strerror_r` function, and C++ compiler
462 // selects proper function.
463 
464 FOLLY_MAYBE_UNUSED
invoke_strerror_r(int (* strerror_r)(int,char *,size_t),int err,char * buf,size_t buflen)465 static std::string invoke_strerror_r(
466     int (*strerror_r)(int, char*, size_t), int err, char* buf, size_t buflen) {
467   // Using XSI-compatible strerror_r
468   int r = strerror_r(err, buf, buflen);
469 
470   // OSX/FreeBSD use EINVAL and Linux uses -1 so just check for non-zero
471   if (r != 0) {
472     return to<std::string>(
473         "Unknown error ", err, " (strerror_r failed with error ", errno, ")");
474   } else {
475     return buf;
476   }
477 }
478 
479 FOLLY_MAYBE_UNUSED
invoke_strerror_r(char * (* strerror_r)(int,char *,size_t),int err,char * buf,size_t buflen)480 static std::string invoke_strerror_r(
481     char* (*strerror_r)(int, char*, size_t),
482     int err,
483     char* buf,
484     size_t buflen) {
485   // Using GNU strerror_r
486   return strerror_r(err, buf, buflen);
487 }
488 
errnoStr(int err)489 std::string errnoStr(int err) {
490   int savedErrno = errno;
491 
492   // Ensure that we reset errno upon exit.
493   auto guard(makeGuard([&] { errno = savedErrno; }));
494 
495   char buf[1024];
496   buf[0] = '\0';
497 
498   std::string result;
499 
500   // https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/strerror_r.3.html
501   // http://www.kernel.org/doc/man-pages/online/pages/man3/strerror.3.html
502 #if defined(_WIN32) && (defined(__MINGW32__) || defined(_MSC_VER))
503   // mingw64 has no strerror_r, but Windows has strerror_s, which C11 added
504   // as well. So maybe we should use this across all platforms (together
505   // with strerrorlen_s). Note strerror_r and _s have swapped args.
506   int r = strerror_s(buf, sizeof(buf), err);
507   if (r != 0) {
508     result = to<std::string>(
509         "Unknown error ", err, " (strerror_r failed with error ", errno, ")");
510   } else {
511     result.assign(buf);
512   }
513 #else
514   // Using any strerror_r
515   result.assign(invoke_strerror_r(strerror_r, err, buf, sizeof(buf)));
516 #endif
517 
518   return result;
519 }
520 
521 namespace {
522 
toLowerAscii8(char & c)523 void toLowerAscii8(char& c) {
524   // Branchless tolower, based on the input-rotating trick described
525   // at http://www.azillionmonkeys.com/qed/asmexample.html
526   //
527   // This algorithm depends on an observation: each uppercase
528   // ASCII character can be converted to its lowercase equivalent
529   // by adding 0x20.
530 
531   // Step 1: Clear the high order bit. We'll deal with it in Step 5.
532   auto rotated = uint8_t(c & 0x7f);
533   // Currently, the value of rotated, as a function of the original c is:
534   //   below 'A':   0- 64
535   //   'A'-'Z':    65- 90
536   //   above 'Z':  91-127
537 
538   // Step 2: Add 0x25 (37)
539   rotated += 0x25;
540   // Now the value of rotated, as a function of the original c is:
541   //   below 'A':   37-101
542   //   'A'-'Z':    102-127
543   //   above 'Z':  128-164
544 
545   // Step 3: clear the high order bit
546   rotated &= 0x7f;
547   //   below 'A':   37-101
548   //   'A'-'Z':    102-127
549   //   above 'Z':    0- 36
550 
551   // Step 4: Add 0x1a (26)
552   rotated += 0x1a;
553   //   below 'A':   63-127
554   //   'A'-'Z':    128-153
555   //   above 'Z':   25- 62
556 
557   // At this point, note that only the uppercase letters have been
558   // transformed into values with the high order bit set (128 and above).
559 
560   // Step 5: Shift the high order bit 2 spaces to the right: the spot
561   // where the only 1 bit in 0x20 is.  But first, how we ignored the
562   // high order bit of the original c in step 1?  If that bit was set,
563   // we may have just gotten a false match on a value in the range
564   // 128+'A' to 128+'Z'.  To correct this, need to clear the high order
565   // bit of rotated if the high order bit of c is set.  Since we don't
566   // care about the other bits in rotated, the easiest thing to do
567   // is invert all the bits in c and bitwise-and them with rotated.
568   rotated &= ~c;
569   rotated >>= 2;
570 
571   // Step 6: Apply a mask to clear everything except the 0x20 bit
572   // in rotated.
573   rotated &= 0x20;
574 
575   // At this point, rotated is 0x20 if c is 'A'-'Z' and 0x00 otherwise
576 
577   // Step 7: Add rotated to c
578   c += char(rotated);
579 }
580 
toLowerAscii32(uint32_t & c)581 void toLowerAscii32(uint32_t& c) {
582   // Besides being branchless, the algorithm in toLowerAscii8() has another
583   // interesting property: None of the addition operations will cause
584   // an overflow in the 8-bit value.  So we can pack four 8-bit values
585   // into a uint32_t and run each operation on all four values in parallel
586   // without having to use any CPU-specific SIMD instructions.
587   uint32_t rotated = c & uint32_t(0x7f7f7f7fL);
588   rotated += uint32_t(0x25252525L);
589   rotated &= uint32_t(0x7f7f7f7fL);
590   rotated += uint32_t(0x1a1a1a1aL);
591 
592   // Step 5 involves a shift, so some bits will spill over from each
593   // 8-bit value into the next.  But that's okay, because they're bits
594   // that will be cleared by the mask in step 6 anyway.
595   rotated &= ~c;
596   rotated >>= 2;
597   rotated &= uint32_t(0x20202020L);
598   c += rotated;
599 }
600 
toLowerAscii64(uint64_t & c)601 void toLowerAscii64(uint64_t& c) {
602   // 64-bit version of toLower32
603   uint64_t rotated = c & uint64_t(0x7f7f7f7f7f7f7f7fL);
604   rotated += uint64_t(0x2525252525252525L);
605   rotated &= uint64_t(0x7f7f7f7f7f7f7f7fL);
606   rotated += uint64_t(0x1a1a1a1a1a1a1a1aL);
607   rotated &= ~c;
608   rotated >>= 2;
609   rotated &= uint64_t(0x2020202020202020L);
610   c += rotated;
611 }
612 
613 } // namespace
614 
toLowerAscii(char * str,size_t length)615 void toLowerAscii(char* str, size_t length) {
616   static const size_t kAlignMask64 = 7;
617   static const size_t kAlignMask32 = 3;
618 
619   // Convert a character at a time until we reach an address that
620   // is at least 32-bit aligned
621   auto n = (size_t)str;
622   n &= kAlignMask32;
623   n = std::min(n, length);
624   size_t offset = 0;
625   if (n != 0) {
626     n = std::min(4 - n, length);
627     do {
628       toLowerAscii8(str[offset]);
629       offset++;
630     } while (offset < n);
631   }
632 
633   n = (size_t)(str + offset);
634   n &= kAlignMask64;
635   if ((n != 0) && (offset + 4 <= length)) {
636     // The next address is 32-bit aligned but not 64-bit aligned.
637     // Convert the next 4 bytes in order to get to the 64-bit aligned
638     // part of the input.
639     toLowerAscii32(*(uint32_t*)(str + offset));
640     offset += 4;
641   }
642 
643   // Convert 8 characters at a time
644   while (offset + 8 <= length) {
645     toLowerAscii64(*(uint64_t*)(str + offset));
646     offset += 8;
647   }
648 
649   // Convert 4 characters at a time
650   while (offset + 4 <= length) {
651     toLowerAscii32(*(uint32_t*)(str + offset));
652     offset += 4;
653   }
654 
655   // Convert any characters remaining after the last 4-byte aligned group
656   while (offset < length) {
657     toLowerAscii8(str[offset]);
658     offset++;
659   }
660 }
661 
662 namespace detail {
663 
hexDumpLine(const void * ptr,size_t offset,size_t size,std::string & line)664 size_t hexDumpLine(
665     const void* ptr, size_t offset, size_t size, std::string& line) {
666   static char hexValues[] = "0123456789abcdef";
667   // Line layout:
668   // 8: address
669   // 1: space
670   // (1+2)*16: hex bytes, each preceded by a space
671   // 1: space separating the two halves
672   // 3: "  |"
673   // 16: characters
674   // 1: "|"
675   // Total: 78
676   line.clear();
677   line.reserve(78);
678   const uint8_t* p = reinterpret_cast<const uint8_t*>(ptr) + offset;
679   size_t n = std::min(size - offset, size_t(16));
680   line.push_back(hexValues[(offset >> 28) & 0xf]);
681   line.push_back(hexValues[(offset >> 24) & 0xf]);
682   line.push_back(hexValues[(offset >> 20) & 0xf]);
683   line.push_back(hexValues[(offset >> 16) & 0xf]);
684   line.push_back(hexValues[(offset >> 12) & 0xf]);
685   line.push_back(hexValues[(offset >> 8) & 0xf]);
686   line.push_back(hexValues[(offset >> 4) & 0xf]);
687   line.push_back(hexValues[offset & 0xf]);
688   line.push_back(' ');
689 
690   for (size_t i = 0; i < n; i++) {
691     if (i == 8) {
692       line.push_back(' ');
693     }
694 
695     line.push_back(' ');
696     line.push_back(hexValues[(p[i] >> 4) & 0xf]);
697     line.push_back(hexValues[p[i] & 0xf]);
698   }
699 
700   // 3 spaces for each byte we're not printing, one separating the halves
701   // if necessary
702   line.append(3 * (16 - n) + (n <= 8), ' ');
703   line.append("  |");
704 
705   for (size_t i = 0; i < n; i++) {
706     char c = (p[i] >= 32 && p[i] <= 126 ? static_cast<char>(p[i]) : '.');
707     line.push_back(c);
708   }
709   line.append(16 - n, ' ');
710   line.push_back('|');
711   DCHECK_EQ(line.size(), 78u);
712 
713   return n;
714 }
715 
716 } // namespace detail
717 
stripLeftMargin(std::string s)718 std::string stripLeftMargin(std::string s) {
719   std::vector<StringPiece> pieces;
720   split("\n", s, pieces);
721   auto piecer = range(pieces);
722 
723   auto piece = (piecer.end() - 1);
724   auto needle = std::find_if(piece->begin(), piece->end(), [](char c) {
725     return c != ' ' && c != '\t';
726   });
727   if (needle == piece->end()) {
728     (piecer.end() - 1)->clear();
729   }
730   piece = piecer.begin();
731   needle = std::find_if(piece->begin(), piece->end(), [](char c) {
732     return c != ' ' && c != '\t';
733   });
734   if (needle == piece->end()) {
735     piecer.erase(piecer.begin(), piecer.begin() + 1);
736   }
737 
738   const auto sentinel = std::numeric_limits<size_t>::max();
739   auto indent = sentinel;
740   size_t max_length = 0;
741   for (piece = piecer.begin(); piece != piecer.end(); piece++) {
742     needle = std::find_if(piece->begin(), piece->end(), [](char c) {
743       return c != ' ' && c != '\t';
744     });
745     if (needle != piece->end()) {
746       indent = std::min<size_t>(indent, size_t(needle - piece->begin()));
747     } else {
748       max_length = std::max<size_t>(piece->size(), max_length);
749     }
750   }
751   indent = indent == sentinel ? max_length : indent;
752   for (piece = piecer.begin(); piece != piecer.end(); piece++) {
753     if (piece->size() < indent) {
754       piece->clear();
755     } else {
756       piece->erase(piece->begin(), piece->begin() + indent);
757     }
758   }
759   return join("\n", piecer);
760 }
761 
762 } // namespace folly
763 
764 #ifdef FOLLY_DEFINED_DMGL
765 #undef FOLLY_DEFINED_DMGL
766 #undef DMGL_NO_OPTS
767 #undef DMGL_PARAMS
768 #undef DMGL_ANSI
769 #undef DMGL_JAVA
770 #undef DMGL_VERBOSE
771 #undef DMGL_TYPES
772 #undef DMGL_RET_POSTFIX
773 #endif
774