#include <stdexcept>
#include <typeinfo>
+#include <limits.h>
+
#include "double-conversion.h" // V8 JavaScript implementation
#define FOLLY_RANGE_CHECK(condition, message) \
* 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
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];
testIntegral2String<String, Ints...>();
}
+#if FOLLY_HAVE_INT128_T
+template <class String>
+void test128Bit2String() {
+ typedef unsigned __int128 Uint;
+ typedef __int128 Sint;
+
+ EXPECT_EQ(detail::digitsEnough<unsigned __int128>(), 39);
+
+ Uint value = 123;
+ EXPECT_EQ(to<String>(value), "123");
+ Sint svalue = 123;
+ EXPECT_EQ(to<String>(svalue), "123");
+ svalue = -123;
+ EXPECT_EQ(to<String>(svalue), "-123");
+
+ value = __int128(1) << 64;
+ EXPECT_EQ(to<String>(value), "18446744073709551616");
+
+ svalue = -(__int128(1) << 64);
+ EXPECT_EQ(to<String>(svalue), "-18446744073709551616");
+
+ value = 0;
+ EXPECT_EQ(to<String>(value), "0");
+
+ svalue = 0;
+ EXPECT_EQ(to<String>(svalue), "0");
+
+ // TODO: the following do not compile to<__int128> ...
+
+#if 0
+ value = numeric_limits<Uint>::min();
+ EXPECT_EQ(to<Uint>(to<String>(value)), value);
+ value = numeric_limits<Uint>::max();
+ EXPECT_EQ(to<Uint>(to<String>(value)), value);
+
+ svalue = numeric_limits<Sint>::min();
+ EXPECT_EQ(to<Sint>(to<String>(svalue)), svalue);
+ value = numeric_limits<Sint>::max();
+ EXPECT_EQ(to<Sint>(to<String>(svalue)), svalue);
+#endif
+}
+
+#endif
+
TEST(Conv, Integral2String) {
testIntegral2String<std::string, char, short, int, long>();
testIntegral2String<fbstring, char, short, int, long>();
+
+#if FOLLY_HAVE_INT128_T
+ test128Bit2String<std::string>();
+ test128Bit2String<fbstring>();
+#endif
}
template <class String>