*/
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] __attribute__((__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 auto 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 +
+ (UNLIKELY (v >= powersOf10[minLength]));
+
+#else
+
uint32_t result = 1;
for (;;) {
if (LIKELY(v < 10)) return result;
v /= 10000U;
result += 4;
}
+
+#endif
}
/**
static int64_t s64;
static uint64_t u64;
+TEST(Conv, digits10Minimal) {
+ // Not much of a test (and it's included in the test below anyway).
+ // I just want to inspect the generated assembly for this function.
+ folly::doNotOptimizeAway(digits10(random() * random()));
+}
+
+TEST(Conv, digits10) {
+ char buffer[100];
+ uint64_t power;
+
+ // first, some basic sniff tests
+ EXPECT_EQ( 1, digits10(0));
+ EXPECT_EQ( 1, digits10(1));
+ EXPECT_EQ( 1, digits10(9));
+ EXPECT_EQ( 2, digits10(10));
+ EXPECT_EQ( 2, digits10(99));
+ EXPECT_EQ( 3, digits10(100));
+ EXPECT_EQ( 3, digits10(999));
+ EXPECT_EQ( 4, digits10(1000));
+ EXPECT_EQ( 4, digits10(9999));
+ EXPECT_EQ(20, digits10(18446744073709551615ULL));
+
+ // try the first X nonnegatives.
+ // Covers some more cases of 2^p, 10^p
+ for (uint64_t i = 0; i < 100000; i++) {
+ snprintf(buffer, sizeof(buffer), "%lu", i);
+ EXPECT_EQ(strlen(buffer), digits10(i));
+ }
+
+ // try powers of 2
+ power = 1;
+ for (int p = 0; p < 64; p++) {
+ snprintf(buffer, sizeof(buffer), "%lu", power);
+ EXPECT_EQ(strlen(buffer), digits10(power));
+ snprintf(buffer, sizeof(buffer), "%lu", power - 1);
+ EXPECT_EQ(strlen(buffer), digits10(power - 1));
+ snprintf(buffer, sizeof(buffer), "%lu", power + 1);
+ EXPECT_EQ(strlen(buffer), digits10(power + 1));
+ power *= 2;
+ }
+
+ // try powers of 10
+ power = 1;
+ for (int p = 0; p < 20; p++) {
+ snprintf(buffer, sizeof(buffer), "%lu", power);
+ EXPECT_EQ(strlen(buffer), digits10(power));
+ snprintf(buffer, sizeof(buffer), "%lu", power - 1);
+ EXPECT_EQ(strlen(buffer), digits10(power - 1));
+ snprintf(buffer, sizeof(buffer), "%lu", power + 1);
+ EXPECT_EQ(strlen(buffer), digits10(power + 1));
+ power *= 10;
+ }
+}
+
// Test to<T>(T)
TEST(Conv, Type2Type) {
int intV = 42;