/*
- * Copyright 2013 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.
* 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>
using namespace std;
using namespace folly;
-static int8_t s8;
-static uint8_t u8;
-static int16_t s16;
-static uint16_t u16;
-static int32_t s32;
-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) {
+ bool boolV = true;
+ EXPECT_EQ(to<bool>(boolV), true);
+
+ 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<bool>(true), true);
+ 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();
+ int64_t s64 = numeric_limits<uint8_t>::max();
EXPECT_EQ(to<uint8_t>(s64), s64);
s64 = numeric_limits<int8_t>::max();
}
}
+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;
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");
EXPECT_EQ(i, 42);
try {
auto i = to<int>(42.1);
+ LOG(ERROR) << "to<int> returned " << i << " instead of throwing";
EXPECT_TRUE(false);
} catch (std::range_error& e) {
//LOG(INFO) << e.what();
EXPECT_EQ(j, 42);
try {
auto i = to<char>(y);
- LOG(ERROR) << static_cast<unsigned int>(i);
+ LOG(ERROR) << "to<char> returned "
+ << static_cast<unsigned int>(i)
+ << " instead of throwing";
EXPECT_TRUE(false);
} catch (std::range_error& e) {
//LOG(INFO) << e.what();
EXPECT_EQ(j, 100);
try {
auto i = to<A>(5000000000L);
+ LOG(ERROR) << "to<A> returned "
+ << static_cast<unsigned int>(i)
+ << " instead of throwing";
EXPECT_TRUE(false);
} catch (std::range_error& e) {
//LOG(INFO) << e.what();
EXPECT_EQ(e, x);
try {
auto i = to<int32_t>(x);
- LOG(ERROR) << to<uint32_t>(x);
+ LOG(ERROR) << "to<int32_t> returned " << i << " instead of throwing";
EXPECT_TRUE(false);
} catch (std::range_error& e) {
}
}
-#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);
EXPECT_EQ(e, E::x);
try {
auto i = to<int32_t>(E::x);
- LOG(ERROR) << to<uint32_t>(E::x);
+ LOG(ERROR) << "to<int32_t> returned " << i << " instead of throwing";
EXPECT_TRUE(false);
} catch (std::range_error& e) {
}
EXPECT_EQ("foo.65", to<string>("foo.", A::z));
}
-#endif // gcc 4.7 onwards
+TEST(Conv, IntegralToBool) {
+ EXPECT_FALSE(to<bool>(0));
+ EXPECT_FALSE(to<bool>(0ul));
+
+ EXPECT_TRUE(to<bool>(1));
+ EXPECT_TRUE(to<bool>(1ul));
+
+ EXPECT_TRUE(to<bool>(-42));
+ EXPECT_TRUE(to<bool>(42ul));
+}
template<typename Src>
void testStr2Bool() {
#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
////////////////////////////////////////////////////////////////////////////////
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");
}
}
-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;
}
}
-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) {
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) {
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) {
}
}
-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) {
// 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;
}
}
-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;
}
}
+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); \
#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();