Construct Later with exception_ptr
[folly.git] / folly / String.cpp
index f50d1de8534dce74eeed5ea0ea2eb21524e813d4..4314d960b4ad95392f1fd4c7dbc0090ef425044f 100644 (file)
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include "folly/String.h"
-#include "folly/Format.h"
+#include <folly/String.h>
+#include <folly/Format.h>
 
 #include <cerrno>
 #include <cstdarg>
@@ -203,7 +203,7 @@ const PrettySuffix kPrettySISuffixes[] = {
   { "z", 1e-21L },
   { "y", 1e-24L },
   { " ", 0 },
-  { 0, 0} 
+  { 0, 0}
 };
 
 const PrettySuffix* const kPrettySuffixes[PRETTY_NUM_TYPES] = {
@@ -247,7 +247,7 @@ std::string prettyPrint(double val, PrettyType type, bool addSpace) {
 
 //TODO:
 //1) Benchmark & optimize
-double prettyToDouble(folly::StringPiece *const prettyString, 
+double prettyToDouble(folly::StringPiece *const prettyString,
                       const PrettyType type) {
   double value = folly::to<double>(prettyString);
   while (prettyString->size() > 0 && std::isspace(prettyString->front())) {
@@ -278,13 +278,13 @@ double prettyToDouble(folly::StringPiece *const prettyString,
             prettyString->toString(), "\""));
   }
   prettyString->advance(longestPrefixLen);
-  return suffixes[bestPrefixId].val ? value * suffixes[bestPrefixId].val : 
+  return suffixes[bestPrefixId].val ? value * suffixes[bestPrefixId].val :
                                       value;
 }
 
 double prettyToDouble(folly::StringPiece prettyString, const PrettyType type){
   double result = prettyToDouble(&prettyString, type);
-  detail::enforceWhitespace(prettyString.data(), 
+  detail::enforceWhitespace(prettyString.data(),
                             prettyString.data() + prettyString.size());
   return result;
 }
@@ -308,7 +308,7 @@ fbstring errnoStr(int err) {
 
   // https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/strerror_r.3.html
   // http://www.kernel.org/doc/man-pages/online/pages/man3/strerror.3.html
-#if defined(__APPLE__) || defined(__FreeBSD__) || \
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__CYGWIN__) ||\
     ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE)
   // Using XSI-compatible strerror_r
   int r = strerror_r(err, buf, sizeof(buf));
@@ -329,6 +329,166 @@ fbstring errnoStr(int err) {
   return result;
 }
 
+StringPiece skipWhitespace(StringPiece sp) {
+  // Spaces other than ' ' characters are less common but should be
+  // checked.  This configuration where we loop on the ' '
+  // separately from oddspaces was empirically fastest.
+  auto oddspace = [] (char c) {
+    return c == '\n' || c == '\t' || c == '\r';
+  };
+
+loop:
+  for (; !sp.empty() && sp.front() == ' '; sp.pop_front()) {
+  }
+  if (!sp.empty() && oddspace(sp.front())) {
+    sp.pop_front();
+    goto loop;
+  }
+
+  return sp;
+}
+
+namespace {
+
+void toLowerAscii8(char& c) {
+  // Branchless tolower, based on the input-rotating trick described
+  // at http://www.azillionmonkeys.com/qed/asmexample.html
+  //
+  // This algorithm depends on an observation: each uppercase
+  // ASCII character can be converted to its lowercase equivalent
+  // by adding 0x20.
+
+  // Step 1: Clear the high order bit. We'll deal with it in Step 5.
+  unsigned char rotated = c & 0x7f;
+  // Currently, the value of rotated, as a function of the original c is:
+  //   below 'A':   0- 64
+  //   'A'-'Z':    65- 90
+  //   above 'Z':  91-127
+
+  // Step 2: Add 0x25 (37)
+  rotated += 0x25;
+  // Now the value of rotated, as a function of the original c is:
+  //   below 'A':   37-101
+  //   'A'-'Z':    102-127
+  //   above 'Z':  128-164
+
+  // Step 3: clear the high order bit
+  rotated &= 0x7f;
+  //   below 'A':   37-101
+  //   'A'-'Z':    102-127
+  //   above 'Z':    0- 36
+
+  // Step 4: Add 0x1a (26)
+  rotated += 0x1a;
+  //   below 'A':   63-127
+  //   'A'-'Z':    128-153
+  //   above 'Z':   25- 62
+
+  // At this point, note that only the uppercase letters have been
+  // transformed into values with the high order bit set (128 and above).
+
+  // Step 5: Shift the high order bit 2 spaces to the right: the spot
+  // where the only 1 bit in 0x20 is.  But first, how we ignored the
+  // high order bit of the original c in step 1?  If that bit was set,
+  // we may have just gotten a false match on a value in the range
+  // 128+'A' to 128+'Z'.  To correct this, need to clear the high order
+  // bit of rotated if the high order bit of c is set.  Since we don't
+  // care about the other bits in rotated, the easiest thing to do
+  // is invert all the bits in c and bitwise-and them with rotated.
+  rotated &= ~c;
+  rotated >>= 2;
+
+  // Step 6: Apply a mask to clear everything except the 0x20 bit
+  // in rotated.
+  rotated &= 0x20;
+
+  // At this point, rotated is 0x20 if c is 'A'-'Z' and 0x00 otherwise
+
+  // Step 7: Add rotated to c
+  c += rotated;
+}
+
+void toLowerAscii32(uint32_t& c) {
+  // Besides being branchless, the algorithm in toLowerAscii8() has another
+  // interesting property: None of the addition operations will cause
+  // an overflow in the 8-bit value.  So we can pack four 8-bit values
+  // into a uint32_t and run each operation on all four values in parallel
+  // without having to use any CPU-specific SIMD instructions.
+  uint32_t rotated = c & uint32_t(0x7f7f7f7fL);
+  rotated += uint32_t(0x25252525L);
+  rotated &= uint32_t(0x7f7f7f7fL);
+  rotated += uint32_t(0x1a1a1a1aL);
+
+  // Step 5 involves a shift, so some bits will spill over from each
+  // 8-bit value into the next.  But that's okay, because they're bits
+  // that will be cleared by the mask in step 6 anyway.
+  rotated &= ~c;
+  rotated >>= 2;
+  rotated &= uint32_t(0x20202020L);
+  c += rotated;
+}
+
+void toLowerAscii64(uint64_t& c) {
+  // 64-bit version of toLower32
+  uint64_t rotated = c & uint64_t(0x7f7f7f7f7f7f7f7fL);
+  rotated += uint64_t(0x2525252525252525L);
+  rotated &= uint64_t(0x7f7f7f7f7f7f7f7fL);
+  rotated += uint64_t(0x1a1a1a1a1a1a1a1aL);
+  rotated &= ~c;
+  rotated >>= 2;
+  rotated &= uint64_t(0x2020202020202020L);
+  c += rotated;
+}
+
+} // anon namespace
+
+void toLowerAscii(char* str, size_t length) {
+  static const size_t kAlignMask64 = 7;
+  static const size_t kAlignMask32 = 3;
+
+  // Convert a character at a time until we reach an address that
+  // is at least 32-bit aligned
+  size_t n = (size_t)str;
+  n &= kAlignMask32;
+  n = std::min(n, length);
+  size_t offset = 0;
+  if (n != 0) {
+    n = std::min(4 - n, length);
+    do {
+      toLowerAscii8(str[offset]);
+      offset++;
+    } while (offset < n);
+  }
+
+  n = (size_t)(str + offset);
+  n &= kAlignMask64;
+  if ((n != 0) && (offset + 4 <= length)) {
+    // The next address is 32-bit aligned but not 64-bit aligned.
+    // Convert the next 4 bytes in order to get to the 64-bit aligned
+    // part of the input.
+    toLowerAscii32(*(uint32_t*)(str + offset));
+    offset += 4;
+  }
+
+  // Convert 8 characters at a time
+  while (offset + 8 <= length) {
+    toLowerAscii64(*(uint64_t*)(str + offset));
+    offset += 8;
+  }
+
+  // Convert 4 characters at a time
+  while (offset + 4 <= length) {
+    toLowerAscii32(*(uint32_t*)(str + offset));
+    offset += 4;
+  }
+
+  // Convert any characters remaining after the last 4-byte aligned group
+  while (offset < length) {
+    toLowerAscii8(str[offset]);
+    offset++;
+  }
+}
+
 namespace detail {
 
 size_t hexDumpLine(const void* ptr, size_t offset, size_t size,
@@ -385,4 +545,3 @@ size_t hexDumpLine(const void* ptr, size_t offset, size_t size,
 # undef DMGL_TYPES
 # undef DMGL_RET_POSTFIX
 #endif
-