implement ThreadCachedArena::totalSize()
[folly.git] / folly / test / ConvTest.cpp
index bb31bd5315f7557524273ab393940ec7a1d5eca4..189c96bd0b5811199205fc747f086fddb86cc223 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012 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.
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#include "folly/Benchmark.h"
-#include "folly/Conv.h"
-#include "folly/Foreach.h"
+#include <folly/Benchmark.h>
+#include <folly/Conv.h>
+#include <folly/Foreach.h>
 #include <boost/lexical_cast.hpp>
 #include <gtest/gtest.h>
 #include <limits>
@@ -34,6 +34,90 @@ static uint32_t u32;
 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;
+  EXPECT_EQ(to<int>(intV), 42);
+
+  float floatV = 4.2;
+  EXPECT_EQ(to<float>(floatV), 4.2f);
+
+  double doubleV = 0.42;
+  EXPECT_EQ(to<double>(doubleV), 0.42);
+
+  std::string stringV = "StdString";
+  EXPECT_EQ(to<std::string>(stringV), "StdString");
+
+  folly::fbstring fbStrV = "FBString";
+  EXPECT_EQ(to<folly::fbstring>(fbStrV), "FBString");
+
+  folly::StringPiece spV("StringPiece");
+  EXPECT_EQ(to<folly::StringPiece>(spV), "StringPiece");
+
+  // Rvalues
+  EXPECT_EQ(to<int>(42), 42);
+  EXPECT_EQ(to<float>(4.2f), 4.2f);
+  EXPECT_EQ(to<double>(.42), .42);
+  EXPECT_EQ(to<std::string>(std::string("Hello")), "Hello");
+  EXPECT_EQ(to<folly::fbstring>(folly::fbstring("hello")), "hello");
+  EXPECT_EQ(to<folly::StringPiece>(folly::StringPiece("Forty Two")),
+            "Forty Two");
+}
+
 TEST(Conv, Integral2Integral) {
   // Same size, different signs
   s64 = numeric_limits<uint8_t>::max();
@@ -389,6 +473,14 @@ TEST(Conv, BadStringToIntegral) {
   }
 }
 
+template <class String>
+void testIdenticalTo() {
+  String s("Yukkuri shiteitte ne!!!");
+
+  String result = to<String>(s);
+  EXPECT_EQ(result, s);
+}
+
 template <class String>
 void testVariadicTo() {
   String s;
@@ -403,18 +495,54 @@ void testVariadicTo() {
   EXPECT_EQ(s, "Lorem ipsum 1234 dolor amet 567.89.");
 }
 
+template <class String>
+void testIdenticalToDelim() {
+  String s("Yukkuri shiteitte ne!!!");
+
+  String charDelim = toDelim<String>('$', s);
+  EXPECT_EQ(charDelim, s);
+
+  String strDelim = toDelim<String>(String(">_<"), s);
+  EXPECT_EQ(strDelim, s);
+}
+
+template <class String>
+void testVariadicToDelim() {
+  String s;
+  toAppendDelim(":", &s);
+  toAppendDelim(
+      ":", "Lorem ipsum ", 1234, String(" dolor amet "), 567.89, '!', &s);
+  EXPECT_EQ(s, "Lorem ipsum :1234: dolor amet :567.89:!");
+
+  s = toDelim<String>(':');
+  EXPECT_TRUE(s.empty());
+
+  s = toDelim<String>(
+      ":", "Lorem ipsum ", nullptr, 1234, " dolor amet ", 567.89, '.');
+  EXPECT_EQ(s, "Lorem ipsum ::1234: dolor amet :567.89:.");
+}
+
 TEST(Conv, NullString) {
-  string s1 = to<string>((char *) NULL);
+  string s1 = to<string>((char *) nullptr);
   EXPECT_TRUE(s1.empty());
-  fbstring s2 = to<fbstring>((char *) NULL);
+  fbstring s2 = to<fbstring>((char *) nullptr);
   EXPECT_TRUE(s2.empty());
 }
 
 TEST(Conv, VariadicTo) {
+  testIdenticalTo<string>();
+  testIdenticalTo<fbstring>();
   testVariadicTo<string>();
   testVariadicTo<fbstring>();
 }
 
+TEST(Conv, VariadicToDelim) {
+  testIdenticalToDelim<string>();
+  testIdenticalToDelim<fbstring>();
+  testVariadicToDelim<string>();
+  testVariadicToDelim<fbstring>();
+}
+
 template <class String>
 void testDoubleToString() {
   EXPECT_EQ(to<string>(0.0), "0");
@@ -571,9 +699,6 @@ TEST(Conv, UnsignedEnum) {
   }
 }
 
-#if defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
-// to<enum class> and to(enum class) only supported in gcc 4.7 onwards
-
 TEST(Conv, UnsignedEnumClass) {
   enum class E : uint32_t { x = 3000000000U };
   auto u = to<uint32_t>(E::x);
@@ -600,8 +725,6 @@ TEST(Conv, EnumClassToString) {
   EXPECT_EQ("foo.65", to<string>("foo.", A::z));
 }
 
-#endif // gcc 4.7 onwards
-
 template<typename Src>
 void testStr2Bool() {
   EXPECT_FALSE(to<bool>(Src("0")));
@@ -704,6 +827,22 @@ TEST(Conv, NewUint64ToString) {
 #undef THE_GREAT_EXPECTATIONS
 }
 
+TEST(Conv, allocate_size) {
+  std::string str1 = "meh meh meh";
+  std::string str2 = "zdech zdech zdech";
+
+  auto res1 = folly::to<std::string>(str1, ".", str2);
+  EXPECT_EQ(res1, str1 + "." + str2);
+
+  std::string res2; //empty
+  toAppendFit(str1, str2, 1, &res2);
+  EXPECT_EQ(res2, str1 + str2 + "1");
+
+  std::string res3;
+  toAppendDelimFit(",", str1, str2, &res3);
+  EXPECT_EQ(res3, str1 + "," + str2);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Benchmarks for ASCII to int conversion
 ////////////////////////////////////////////////////////////////////////////////
@@ -747,21 +886,21 @@ static int64_t handwrittenAtoi(const char* start, const char* end) {
 
 static StringPiece pc1 = "1234567890123456789";
 
-void handwrittenAtoiMeasure(uint n, uint digits) {
+void handwrittenAtoiMeasure(unsigned int n, unsigned int digits) {
   auto p = pc1.subpiece(pc1.size() - digits, digits);
   FOR_EACH_RANGE (i, 0, n) {
     doNotOptimizeAway(handwrittenAtoi(p.begin(), p.end()));
   }
 }
 
-void follyAtoiMeasure(uint n, uint digits) {
+void follyAtoiMeasure(unsigned int n, unsigned int digits) {
   auto p = pc1.subpiece(pc1.size() - digits, digits);
   FOR_EACH_RANGE (i, 0, n) {
     doNotOptimizeAway(folly::to<int64_t>(p.begin(), p.end()));
   }
 }
 
-void clibAtoiMeasure(uint n, uint digits) {
+void clibAtoiMeasure(unsigned int n, unsigned int digits) {
   auto p = pc1.subpiece(pc1.size() - digits, digits);
   assert(*p.end() == 0);
   static_assert(sizeof(long) == 8, "64-bit long assumed");
@@ -770,7 +909,7 @@ void clibAtoiMeasure(uint n, uint digits) {
   }
 }
 
-void clibStrtoulMeasure(uint n, uint digits) {
+void clibStrtoulMeasure(unsigned int n, unsigned int digits) {
   auto p = pc1.subpiece(pc1.size() - digits, digits);
   assert(*p.end() == 0);
   char * endptr;
@@ -779,7 +918,7 @@ void clibStrtoulMeasure(uint n, uint digits) {
   }
 }
 
-void lexicalCastMeasure(uint n, uint digits) {
+void lexicalCastMeasure(unsigned int n, unsigned int digits) {
   auto p = pc1.subpiece(pc1.size() - digits, digits);
   assert(*p.end() == 0);
   FOR_EACH_RANGE (i, 0, n) {
@@ -822,7 +961,7 @@ unsigned u64ToAsciiTable(uint64_t value, char* dst) {
   return length;
 }
 
-void u64ToAsciiTableBM(uint n, uint64_t value) {
+void u64ToAsciiTableBM(unsigned int n, uint64_t value) {
   // This is too fast, need to do 10 times per iteration
   char buf[20];
   FOR_EACH_RANGE (i, 0, n) {
@@ -852,7 +991,7 @@ unsigned u64ToAsciiClassic(uint64_t value, char* dst) {
   return length;
 }
 
-void u64ToAsciiClassicBM(uint n, uint64_t value) {
+void u64ToAsciiClassicBM(unsigned int n, uint64_t value) {
   // This is too fast, need to do 10 times per iteration
   char buf[20];
   FOR_EACH_RANGE (i, 0, n) {
@@ -860,7 +999,7 @@ void u64ToAsciiClassicBM(uint n, uint64_t value) {
   }
 }
 
-void u64ToAsciiFollyBM(uint n, uint64_t value) {
+void u64ToAsciiFollyBM(unsigned int n, uint64_t value) {
   // This is too fast, need to do 10 times per iteration
   char buf[20];
   FOR_EACH_RANGE (i, 0, n) {
@@ -870,7 +1009,7 @@ void u64ToAsciiFollyBM(uint n, uint64_t value) {
 
 // Benchmark uitoa with string append
 
-void u2aAppendClassicBM(uint n, uint64_t value) {
+void u2aAppendClassicBM(unsigned int n, uint64_t value) {
   string s;
   FOR_EACH_RANGE (i, 0, n) {
     // auto buf = &s.back() + 1;
@@ -880,7 +1019,7 @@ void u2aAppendClassicBM(uint n, uint64_t value) {
   }
 }
 
-void u2aAppendFollyBM(uint n, uint64_t value) {
+void u2aAppendFollyBM(unsigned int n, uint64_t value) {
   string s;
   FOR_EACH_RANGE (i, 0, n) {
     // auto buf = &s.back() + 1;
@@ -890,6 +1029,64 @@ void u2aAppendFollyBM(uint n, uint64_t value) {
   }
 }
 
+template <class String>
+struct StringIdenticalToBM {
+  StringIdenticalToBM() {}
+  void operator()(unsigned int n, size_t len) const {
+    String s;
+    BENCHMARK_SUSPEND { s.append(len, '0'); }
+    FOR_EACH_RANGE (i, 0, n) {
+      String result = to<String>(s);
+      doNotOptimizeAway(result.size());
+    }
+  }
+};
+
+template <class String>
+struct StringVariadicToBM {
+  StringVariadicToBM() {}
+  void operator()(unsigned int n, size_t len) const {
+    String s;
+    BENCHMARK_SUSPEND { s.append(len, '0'); }
+    FOR_EACH_RANGE (i, 0, n) {
+      String result = to<String>(s, nullptr);
+      doNotOptimizeAway(result.size());
+    }
+  }
+};
+
+static size_t bigInt = 11424545345345;
+static size_t smallInt = 104;
+static char someString[] = "this is some nice string";
+static char otherString[] = "this is a long string, so it's not so nice";
+static char reallyShort[] = "meh";
+static std::string stdString = "std::strings are very nice";
+static float fValue = 1.2355;
+static double dValue = 345345345.435;
+
+BENCHMARK(preallocateTestNoFloat, n) {
+  for (size_t i = 0; i < n; ++i) {
+    auto val1 = to<std::string>(bigInt, someString, stdString, otherString);
+    auto val3 = to<std::string>(reallyShort, smallInt);
+    auto val2 = to<std::string>(bigInt, stdString);
+    auto val4 = to<std::string>(bigInt, stdString, dValue, otherString);
+    auto val5 = to<std::string>(bigInt, someString, reallyShort);
+  }
+}
+
+BENCHMARK(preallocateTestFloat, n) {
+  for (size_t i = 0; i < n; ++i) {
+    auto val1 = to<std::string>(stdString, ',', fValue, dValue);
+    auto val2 = to<std::string>(stdString, ',', dValue);
+  }
+}
+BENCHMARK_DRAW_LINE();
+
+static const StringIdenticalToBM<std::string> stringIdenticalToBM;
+static const StringVariadicToBM<std::string> stringVariadicToBM;
+static const StringIdenticalToBM<fbstring> fbstringIdenticalToBM;
+static const StringVariadicToBM<fbstring> fbstringVariadicToBM;
+
 #define DEFINE_BENCHMARK_GROUP(n)                       \
   BENCHMARK_PARAM(u64ToAsciiClassicBM, n);              \
   BENCHMARK_RELATIVE_PARAM(u64ToAsciiTableBM, n);       \
@@ -948,9 +1145,23 @@ DEFINE_BENCHMARK_GROUP(19);
 
 #undef DEFINE_BENCHMARK_GROUP
 
+#define DEFINE_BENCHMARK_GROUP(T, n)                    \
+  BENCHMARK_PARAM(T ## VariadicToBM, n);                \
+  BENCHMARK_RELATIVE_PARAM(T ## IdenticalToBM, n);      \
+  BENCHMARK_DRAW_LINE();
+
+DEFINE_BENCHMARK_GROUP(string, 32);
+DEFINE_BENCHMARK_GROUP(string, 1024);
+DEFINE_BENCHMARK_GROUP(string, 32768);
+DEFINE_BENCHMARK_GROUP(fbstring, 32);
+DEFINE_BENCHMARK_GROUP(fbstring, 1024);
+DEFINE_BENCHMARK_GROUP(fbstring, 32768);
+
+#undef DEFINE_BENCHMARK_GROUP
+
 int main(int argc, char** argv) {
   testing::InitGoogleTest(&argc, argv);
-  google::ParseCommandLineFlags(&argc, &argv, true);
+  gflags::ParseCommandLineFlags(&argc, &argv, true);
   auto ret = RUN_ALL_TESTS();
   if (!ret && FLAGS_benchmark) {
     folly::runBenchmarks();