X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2Ftest%2FConvTest.cpp;h=189c96bd0b5811199205fc747f086fddb86cc223;hb=9642ca2dee51e2f4d04628a6fde613eb8101ef75;hp=bb31bd5315f7557524273ab393940ec7a1d5eca4;hpb=785dd995feb46487804ff8ceb67a5f3371ceeb7d;p=folly.git diff --git a/folly/test/ConvTest.cpp b/folly/test/ConvTest.cpp index bb31bd53..189c96bd 100644 --- a/folly/test/ConvTest.cpp +++ b/folly/test/ConvTest.cpp @@ -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 +#include +#include #include #include #include @@ -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) +TEST(Conv, Type2Type) { + int intV = 42; + EXPECT_EQ(to(intV), 42); + + float floatV = 4.2; + EXPECT_EQ(to(floatV), 4.2f); + + double doubleV = 0.42; + EXPECT_EQ(to(doubleV), 0.42); + + std::string stringV = "StdString"; + EXPECT_EQ(to(stringV), "StdString"); + + folly::fbstring fbStrV = "FBString"; + EXPECT_EQ(to(fbStrV), "FBString"); + + folly::StringPiece spV("StringPiece"); + EXPECT_EQ(to(spV), "StringPiece"); + + // Rvalues + EXPECT_EQ(to(42), 42); + EXPECT_EQ(to(4.2f), 4.2f); + EXPECT_EQ(to(.42), .42); + EXPECT_EQ(to(std::string("Hello")), "Hello"); + EXPECT_EQ(to(folly::fbstring("hello")), "hello"); + EXPECT_EQ(to(folly::StringPiece("Forty Two")), + "Forty Two"); +} + TEST(Conv, Integral2Integral) { // Same size, different signs s64 = numeric_limits::max(); @@ -389,6 +473,14 @@ TEST(Conv, BadStringToIntegral) { } } +template +void testIdenticalTo() { + String s("Yukkuri shiteitte ne!!!"); + + String result = to(s); + EXPECT_EQ(result, s); +} + template void testVariadicTo() { String s; @@ -403,18 +495,54 @@ void testVariadicTo() { EXPECT_EQ(s, "Lorem ipsum 1234 dolor amet 567.89."); } +template +void testIdenticalToDelim() { + String s("Yukkuri shiteitte ne!!!"); + + String charDelim = toDelim('$', s); + EXPECT_EQ(charDelim, s); + + String strDelim = toDelim(String(">_<"), s); + EXPECT_EQ(strDelim, s); +} + +template +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(':'); + EXPECT_TRUE(s.empty()); + + s = toDelim( + ":", "Lorem ipsum ", nullptr, 1234, " dolor amet ", 567.89, '.'); + EXPECT_EQ(s, "Lorem ipsum ::1234: dolor amet :567.89:."); +} + TEST(Conv, NullString) { - string s1 = to((char *) NULL); + string s1 = to((char *) nullptr); EXPECT_TRUE(s1.empty()); - fbstring s2 = to((char *) NULL); + fbstring s2 = to((char *) nullptr); EXPECT_TRUE(s2.empty()); } TEST(Conv, VariadicTo) { + testIdenticalTo(); + testIdenticalTo(); testVariadicTo(); testVariadicTo(); } +TEST(Conv, VariadicToDelim) { + testIdenticalToDelim(); + testIdenticalToDelim(); + testVariadicToDelim(); + testVariadicToDelim(); +} + template void testDoubleToString() { EXPECT_EQ(to(0.0), "0"); @@ -571,9 +699,6 @@ TEST(Conv, UnsignedEnum) { } } -#if defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) -// to and to(enum class) only supported in gcc 4.7 onwards - TEST(Conv, UnsignedEnumClass) { enum class E : uint32_t { x = 3000000000U }; auto u = to(E::x); @@ -600,8 +725,6 @@ TEST(Conv, EnumClassToString) { EXPECT_EQ("foo.65", to("foo.", A::z)); } -#endif // gcc 4.7 onwards - template void testStr2Bool() { EXPECT_FALSE(to(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(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(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 +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(s); + doNotOptimizeAway(result.size()); + } + } +}; + +template +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(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(bigInt, someString, stdString, otherString); + auto val3 = to(reallyShort, smallInt); + auto val2 = to(bigInt, stdString); + auto val4 = to(bigInt, stdString, dValue, otherString); + auto val5 = to(bigInt, someString, reallyShort); + } +} + +BENCHMARK(preallocateTestFloat, n) { + for (size_t i = 0; i < n; ++i) { + auto val1 = to(stdString, ',', fValue, dValue); + auto val2 = to(stdString, ',', dValue); + } +} +BENCHMARK_DRAW_LINE(); + +static const StringIdenticalToBM stringIdenticalToBM; +static const StringVariadicToBM stringVariadicToBM; +static const StringIdenticalToBM fbstringIdenticalToBM; +static const StringVariadicToBM 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();