Add samples to FBVector documentation
[folly.git] / folly / Conv.h
index 98ff2c01ea9733d4fd39509877028cc696519a44..1bf2a39f4aa85c457d35b42978e87126606edc02 100644 (file)
@@ -37,6 +37,8 @@
 #include <stdexcept>
 #include <typeinfo>
 
+#include <limits.h>
+
 #include "double-conversion.h"   // V8 JavaScript implementation
 
 #define FOLLY_RANGE_CHECK(condition, message)                           \
@@ -122,6 +124,46 @@ typename std::tuple_element<
  * Conversions from integral types to string types.
  ******************************************************************************/
 
+#if FOLLY_HAVE_INT128_T
+namespace detail {
+
+template <typename IntegerType>
+constexpr unsigned int
+digitsEnough() {
+  return ceil((double(sizeof(IntegerType) * CHAR_BIT) * M_LN2) / M_LN10);
+}
+
+inline unsigned int
+unsafeTelescope128(char * buffer, unsigned int room, unsigned __int128 x) {
+  typedef unsigned __int128 Usrc;
+  unsigned int p = room - 1;
+
+  while (x >= (Usrc(1) << 64)) { // Using 128-bit division while needed
+    const auto y = x / 10;
+    const auto digit = x % 10;
+
+    buffer[p--] = '0' + digit;
+    x = y;
+  }
+
+  uint64_t xx = x; // Moving to faster 64-bit division thereafter
+
+  while (xx >= 10) {
+    const auto y = xx / 10ULL;
+    const auto digit = xx % 10ULL;
+
+    buffer[p--] = '0' + digit;
+    xx = y;
+  }
+
+  buffer[p] = '0' + xx;
+
+  return p;
+}
+
+}
+#endif
+
 /**
  * Returns the number of digits in the base 10 representation of an
  * uint64_t. Useful for preallocating buffers and such. It's also used
@@ -229,19 +271,53 @@ toAppend(const fbstring& value, Tgt * result) {
   result->append(value.data(), value.size());
 }
 
+#if FOLLY_HAVE_INT128_T
+/**
+ * Special handling for 128 bit integers.
+ */
+
+template <class Tgt>
+void
+toAppend(__int128 value, Tgt * result) {
+  typedef unsigned __int128 Usrc;
+  char buffer[detail::digitsEnough<unsigned __int128>() + 1];
+  unsigned int p;
+
+  if (value < 0) {
+    p = detail::unsafeTelescope128(buffer, sizeof(buffer), Usrc(-value));
+    buffer[--p] = '-';
+  } else {
+    p = detail::unsafeTelescope128(buffer, sizeof(buffer), value);
+  }
+
+  result->append(buffer + p, buffer + sizeof(buffer));
+}
+
+template <class Tgt>
+void
+toAppend(unsigned __int128 value, Tgt * result) {
+  char buffer[detail::digitsEnough<unsigned __int128>()];
+  unsigned int p;
+
+  p = detail::unsafeTelescope128(buffer, sizeof(buffer), value);
+
+  result->append(buffer + p, buffer + sizeof(buffer));
+}
+
+#endif
+
 /**
  * int32_t and int64_t to string (by appending) go through here. The
  * result is APPENDED to a preexisting string passed as the second
- * parameter. For convenience, the function also returns a reference
- * to *result. This should be efficient with fbstring because fbstring
+ * parameter. This should be efficient with fbstring because fbstring
  * incurs no dynamic allocation below 23 bytes and no number has more
  * than 22 bytes in its textual representation (20 for digits, one for
  * sign, one for the terminating 0).
  */
 template <class Tgt, class Src>
 typename std::enable_if<
-  std::is_integral<Src>::value && std::is_signed<Src>::value
-  && detail::IsSomeString<Tgt>::value && sizeof(Src) >= 4>::type
+  std::is_integral<Src>::value && std::is_signed<Src>::value &&
+  detail::IsSomeString<Tgt>::value && sizeof(Src) >= 4>::type
 toAppend(Src value, Tgt * result) {
   typedef typename std::make_unsigned<Src>::type Usrc;
   char buffer[20];
@@ -280,6 +356,22 @@ toAppend(Src value, Tgt * result) {
   toAppend<Tgt>(static_cast<Intermediate>(value), result);
 }
 
+#if defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
+// std::underlying_type became available by gcc 4.7.0
+
+/**
+ * Enumerated values get appended as integers.
+ */
+template <class Tgt, class Src>
+typename std::enable_if<
+  std::is_enum<Src>::value && detail::IsSomeString<Tgt>::value>::type
+toAppend(Src value, Tgt * result) {
+  toAppend(
+      static_cast<typename std::underlying_type<Src>::type>(value), result);
+}
+
+#else
+
 /**
  * Enumerated values get appended as integers.
  */
@@ -302,6 +394,8 @@ toAppend(Src value, Tgt * result) {
   }
 }
 
+#endif // gcc 4.7 onwards
+
 /*******************************************************************************
  * Conversions from floating-point types to string types.
  ******************************************************************************/
@@ -912,12 +1006,26 @@ to(const Src & value) {
  * Enum to anything and back
  ******************************************************************************/
 
+#if defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 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, Tgt>::type
+to(const Src & value) {
+  return to<Tgt>(static_cast<typename std::underlying_type<Src>::type>(value));
+}
+
+template <class Tgt, class Src>
+typename std::enable_if<std::is_enum<Tgt>::value, Tgt>::type
+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, Tgt>::type
 to(const Src & value) {
-  // TODO: uncomment this when underlying_type is available
-  // return to<Tgt>(static_cast<typename std::underlying_type<Src>::type>(
-  //    value));
   /* static */ if (Src(-1) < 0) {
     /* static */ if (sizeof(Src) <= sizeof(int)) {
       return to<Tgt>(static_cast<int>(value));
@@ -936,9 +1044,6 @@ to(const Src & value) {
 template <class Tgt, class Src>
 typename std::enable_if<std::is_enum<Tgt>::value, Tgt>::type
 to(const Src & value) {
-  // TODO: uncomment this when underlying_type is available
-  // return static_cast<Tgt>(
-  //    to<typename std::underlying_type<Tgt>::type>(value));
   /* static */ if (Tgt(-1) < 0) {
     /* static */ if (sizeof(Tgt) <= sizeof(int)) {
       return static_cast<Tgt>(to<int>(value));
@@ -954,6 +1059,8 @@ to(const Src & value) {
   }
 }
 
+#endif // gcc 4.7 onwards
+
 } // namespace folly
 
 // FOLLY_CONV_INTERNAL is defined by Conv.cpp.  Keep the FOLLY_RANGE_CHECK