folly::FunctionScheduler: Adding support for uniform interval distribution
[folly.git] / folly / Conv.h
index 31902c73d8008ed4dced18c224aee4c2e45f7e20..113a14954ae27ad56d60f3de46ecbf41f4016268 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2015 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #define FOLLY_RANGE_CHECK_STRINGIZE(x) #x
 #define FOLLY_RANGE_CHECK_STRINGIZE2(x) FOLLY_RANGE_CHECK_STRINGIZE(x)
 
+// Android doesn't support std::to_string so just use a placeholder there.
+#ifdef __ANDROID__
+#define FOLLY_RANGE_CHECK_TO_STRING(x) std::string("N/A")
+#else
+#define FOLLY_RANGE_CHECK_TO_STRING(x) std::to_string(x)
+#endif
+
 #define FOLLY_RANGE_CHECK(condition, message, src)                          \
   ((condition) ? (void)0 : throw std::range_error(                          \
     (std::string(__FILE__ "(" FOLLY_RANGE_CHECK_STRINGIZE2(__LINE__) "): ") \
@@ -95,15 +102,15 @@ to(const Src & value) {
                    < std::numeric_limits<Src>::max()) {
     FOLLY_RANGE_CHECK(
       (!greater_than<Tgt, std::numeric_limits<Tgt>::max()>(value)),
-      "Overflow", std::to_string(value)
-    );
+      "Overflow",
+      FOLLY_RANGE_CHECK_TO_STRING(value));
   }
   /* static */ if (std::is_signed<Src>::value &&
                    (!std::is_signed<Tgt>::value || sizeof(Src) > sizeof(Tgt))) {
     FOLLY_RANGE_CHECK(
       (!less_than<Tgt, std::numeric_limits<Tgt>::min()>(value)),
-      "Negative overflow", std::to_string(value)
-    );
+      "Negative overflow",
+      FOLLY_RANGE_CHECK_TO_STRING(value));
   }
   return static_cast<Tgt>(value);
 }
@@ -122,9 +129,11 @@ to(const Src & value) {
   /* static */ if (std::numeric_limits<Tgt>::max() <
                    std::numeric_limits<Src>::max()) {
     FOLLY_RANGE_CHECK(value <= std::numeric_limits<Tgt>::max(),
-                      "Overflow", std::to_string(value));
+                      "Overflow",
+                      FOLLY_RANGE_CHECK_TO_STRING(value));
     FOLLY_RANGE_CHECK(value >= -std::numeric_limits<Tgt>::max(),
-                      "Negative overflow", std::to_string(value));
+                      "Negative overflow",
+                      FOLLY_RANGE_CHECK_TO_STRING(value));
   }
   return boost::implicit_cast<Tgt>(value);
 }
@@ -144,7 +153,7 @@ template <class T, class... Ts>
 typename std::tuple_element<
   sizeof...(Ts),
   std::tuple<T, Ts...> >::type const&
-  getLastElement(const T& v, const Ts&... vs) {
+  getLastElement(const T&, const Ts&... vs) {
   return getLastElement(vs...);
 }
 
@@ -219,6 +228,42 @@ unsafeTelescope128(char * buffer, size_t room, unsigned __int128 x) {
  */
 
 inline uint32_t digits10(uint64_t v) {
+#ifdef __x86_64__
+
+  // For this arch we can get a little help from specialized CPU instructions
+  // which can count leading zeroes; 64 minus that is appx. log (base 2).
+  // Use that to approximate base-10 digits (log_10) and then adjust if needed.
+
+  // 10^i, defined for i 0 through 19.
+  // This is 20 * 8 == 160 bytes, which fits neatly into 5 cache lines
+  // (assuming a cache line size of 64).
+  static const uint64_t powersOf10[20] FOLLY_ALIGNED(64) = {
+    1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000,
+    10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000,
+    1000000000000000, 10000000000000000, 100000000000000000,
+    1000000000000000000, 10000000000000000000UL
+  };
+
+  // "count leading zeroes" operation not valid; for 0; special case this.
+  if UNLIKELY (! v) {
+    return 1;
+  }
+
+  // bits is in the ballpark of log_2(v).
+  const uint8_t leadingZeroes = __builtin_clzll(v);
+  const auto bits = 63 - leadingZeroes;
+
+  // approximate log_10(v) == log_10(2) * bits.
+  // Integer magic below: 77/256 is appx. 0.3010 (log_10(2)).
+  // The +1 is to make this the ceiling of the log_10 estimate.
+  const uint32_t minLength = 1 + ((bits * 77) >> 8);
+
+  // return that log_10 lower bound, plus adjust if input >= 10^(that bound)
+  // in case there's a small error and we misjudged length.
+  return minLength + (uint32_t) (UNLIKELY (v >= powersOf10[minLength]));
+
+#else
+
   uint32_t result = 1;
   for (;;) {
     if (LIKELY(v < 10)) return result;
@@ -229,6 +274,8 @@ inline uint32_t digits10(uint64_t v) {
     v /= 10000U;
     result += 4;
   }
+
+#endif
 }
 
 /**
@@ -500,9 +547,6 @@ estimateSpaceNeeded(Src value) {
   return estimateSpaceNeeded(static_cast<Intermediate>(value));
 }
 
-#if defined(__clang__) || __GNUC_PREREQ(4, 7)
-// std::underlying_type became available by gcc 4.7.0
-
 /**
  * Enumerated values get appended as integers.
  */
@@ -522,51 +566,6 @@ estimateSpaceNeeded(Src value) {
       static_cast<typename std::underlying_type<Src>::type>(value));
 }
 
-#else
-
-/**
- * Enumerated values get appended as integers.
- */
-template <class Tgt, class Src>
-typename std::enable_if<
-  std::is_enum<Src>::value && IsSomeString<Tgt>::value>::type
-toAppend(Src value, Tgt * result) {
-  /* static */ if (Src(-1) < 0) {
-    /* static */ if (sizeof(Src) <= sizeof(int)) {
-      toAppend(static_cast<int>(value), result);
-    } else {
-      toAppend(static_cast<long>(value), result);
-    }
-  } else {
-    /* static */ if (sizeof(Src) <= sizeof(int)) {
-      toAppend(static_cast<unsigned int>(value), result);
-    } else {
-      toAppend(static_cast<unsigned long>(value), result);
-    }
-  }
-}
-
-template <class Src>
-typename std::enable_if<
-  std::is_enum<Src>::value, size_t>::type
-estimateSpaceNeeded(Src value) {
-  /* static */ if (Src(-1) < 0) {
-    /* static */ if (sizeof(Src) <= sizeof(int)) {
-      return estimateSpaceNeeded(static_cast<int>(value));
-    } else {
-      return estimateSpaceNeeded(static_cast<long>(value));
-    }
-  } else {
-    /* static */ if (sizeof(Src) <= sizeof(int)) {
-      return estimateSpaceNeeded(static_cast<unsigned int>(value));
-    } else {
-      return estimateSpaceNeeded(static_cast<unsigned long>(value));
-    }
-  }
-}
-
-#endif // gcc 4.7 onwards
-
 /*******************************************************************************
  * Conversions from floating-point types to string types.
  ******************************************************************************/
@@ -589,7 +588,7 @@ toAppend(
   using namespace double_conversion;
   DoubleToStringConverter
     conv(DoubleToStringConverter::NO_FLAGS,
-         "infinity", "NaN", 'E',
+         "Infinity", "NaN", 'E',
          detail::kConvMaxDecimalInShortestLow,
          detail::kConvMaxDecimalInShortestHigh,
          6,   // max leading padding zeros
@@ -768,7 +767,7 @@ typename std::enable_if<sizeof...(Ts) >= 3
     typename detail::last_element<Ts...>::type
   >::type>::value>::type
 toAppend(const Ts&... vs) {
-  detail::toAppendStrImpl(vs...);
+  ::folly::detail::toAppendStrImpl(vs...);
 }
 
 /**
@@ -787,7 +786,7 @@ typename std::enable_if<
     typename detail::last_element<Ts...>::type
   >::type>::value>::type
 toAppendFit(const Ts&... vs) {
-  detail::reserveInTarget(vs...);
+  ::folly::detail::reserveInTarget(vs...);
   toAppend(vs...);
 }
 
@@ -939,7 +938,7 @@ namespace detail {
 // still not overflow uint16_t.
 constexpr int32_t OOR = 10000;
 
-__attribute__((__aligned__(16))) constexpr uint16_t shift1[] = {
+FOLLY_ALIGNED(16) constexpr uint16_t shift1[] = {
   OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR,  // 0-9
   OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR,  //  10
   OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR,  //  20
@@ -968,7 +967,7 @@ __attribute__((__aligned__(16))) constexpr uint16_t shift1[] = {
   OOR, OOR, OOR, OOR, OOR, OOR                       // 250
 };
 
-__attribute__((__aligned__(16))) constexpr uint16_t shift10[] = {
+FOLLY_ALIGNED(16) constexpr uint16_t shift10[] = {
   OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR,  // 0-9
   OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR,  //  10
   OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR,  //  20
@@ -997,7 +996,7 @@ __attribute__((__aligned__(16))) constexpr uint16_t shift10[] = {
   OOR, OOR, OOR, OOR, OOR, OOR                       // 250
 };
 
-__attribute__((__aligned__(16))) constexpr uint16_t shift100[] = {
+FOLLY_ALIGNED(16) constexpr uint16_t shift100[] = {
   OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR,  // 0-9
   OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR,  //  10
   OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR,  //  20
@@ -1026,7 +1025,7 @@ __attribute__((__aligned__(16))) constexpr uint16_t shift100[] = {
   OOR, OOR, OOR, OOR, OOR, OOR                       // 250
 };
 
-__attribute__((__aligned__(16))) constexpr uint16_t shift1000[] = {
+FOLLY_ALIGNED(16) constexpr uint16_t shift1000[] = {
   OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR,  // 0-9
   OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR,  //  10
   OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR,  //  20
@@ -1416,7 +1415,12 @@ to(const Src & value) {
   if (value != witness) {
     throw std::range_error(
       to<std::string>("to<>: loss of precision when converting ", value,
-                      " to type ", typeid(Tgt).name()).c_str());
+#ifdef FOLLY_HAS_RTTI
+                      " to type ", typeid(Tgt).name()
+#else
+                      " to other type"
+#endif
+                      ).c_str());
   }
   return result;
 }
@@ -1425,9 +1429,6 @@ to(const Src & value) {
  * Enum to anything and back
  ******************************************************************************/
 
-#if defined(__clang__) || __GNUC_PREREQ(4, 7)
-// std::underlying_type became available by gcc 4.7.0
-
 template <class Tgt, class Src>
 typename std::enable_if<
   std::is_enum<Src>::value && !std::is_same<Src, Tgt>::value, Tgt>::type
@@ -1442,48 +1443,6 @@ to(const Src & value) {
   return static_cast<Tgt>(to<typename std::underlying_type<Tgt>::type>(value));
 }
 
-#else
-
-template <class Tgt, class Src>
-typename std::enable_if<
-  std::is_enum<Src>::value && !std::is_same<Src, Tgt>::value, Tgt>::type
-to(const Src & value) {
-  /* static */ if (Src(-1) < 0) {
-    /* static */ if (sizeof(Src) <= sizeof(int)) {
-      return to<Tgt>(static_cast<int>(value));
-    } else {
-      return to<Tgt>(static_cast<long>(value));
-    }
-  } else {
-    /* static */ if (sizeof(Src) <= sizeof(int)) {
-      return to<Tgt>(static_cast<unsigned int>(value));
-    } else {
-      return to<Tgt>(static_cast<unsigned long>(value));
-    }
-  }
-}
-
-template <class Tgt, class Src>
-typename std::enable_if<
-  std::is_enum<Tgt>::value && !std::is_same<Src, Tgt>::value, Tgt>::type
-to(const Src & value) {
-  /* static */ if (Tgt(-1) < 0) {
-    /* static */ if (sizeof(Tgt) <= sizeof(int)) {
-      return static_cast<Tgt>(to<int>(value));
-    } else {
-      return static_cast<Tgt>(to<long>(value));
-    }
-  } else {
-    /* static */ if (sizeof(Tgt) <= sizeof(int)) {
-      return static_cast<Tgt>(to<unsigned int>(value));
-    } else {
-      return static_cast<Tgt>(to<unsigned long>(value));
-    }
-  }
-}
-
-#endif // gcc 4.7 onwards
-
 } // namespace folly
 
 // FOLLY_CONV_INTERNAL is defined by Conv.cpp.  Keep the FOLLY_RANGE_CHECK