From 587427e7a45a508caa2f6c78176c5add4df08c45 Mon Sep 17 00:00:00 2001 From: Zejun Wu Date: Mon, 9 Jun 2014 10:16:31 -0700 Subject: [PATCH] Specialize string to identical string conversion Summary: Avoid copying underlying char array in to(const string&) and to(const fbstring&). Test Plan: fbconfig -r $redteamisthebestteam/$nekomikoreimu && fbmake Reviewed By: ldbrandy@fb.com Subscribers: jonp, folly@lists FB internal diff: D1368183 Tasks: 4263125 --- folly/Conv.h | 36 ++++++++++++++++++++-- folly/test/ConvTest.cpp | 66 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/folly/Conv.h b/folly/Conv.h index 9ecc43c8..120eda96 100644 --- a/folly/Conv.h +++ b/folly/Conv.h @@ -526,24 +526,56 @@ toAppendDelim(const Delimiter& delim, const T& v, const Ts&... vs) { toAppendDelim(delim, vs...); } +/** + * to(SomeString str) returns itself. As both std::string and + * folly::fbstring use Copy-on-Write, it's much more efficient by + * avoiding copying the underlying char array. + */ +template +typename std::enable_if< + IsSomeString::value && std::is_same::value, + Tgt>::type +to(const Src & value) { + return value; +} + /** * to(v1, v2, ...) uses toAppend() (see below) as back-end * for all types. */ template -typename std::enable_if::value, Tgt>::type +typename std::enable_if< + IsSomeString::value && ( + sizeof...(Ts) != 1 || + !std::is_same::type>::value), + Tgt>::type to(const Ts&... vs) { Tgt result; toAppend(vs..., &result); return result; } +/** + * toDelim(SomeString str) returns itself. + */ +template +typename std::enable_if< + IsSomeString::value && std::is_same::value, + Tgt>::type +toDelim(const Delim& delim, const Src & value) { + return value; +} + /** * toDelim(delim, v1, v2, ...) uses toAppendDelim() as * back-end for all types. */ template -typename std::enable_if::value, Tgt>::type +typename std::enable_if< + IsSomeString::value && ( + sizeof...(Ts) != 1 || + !std::is_same::type>::value), + Tgt>::type toDelim(const Delim& delim, const Ts&... vs) { Tgt result; toAppendDelim(delim, vs..., &result); diff --git a/folly/test/ConvTest.cpp b/folly/test/ConvTest.cpp index 537b4f25..1b6214db 100644 --- a/folly/test/ConvTest.cpp +++ b/folly/test/ConvTest.cpp @@ -389,6 +389,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,6 +411,17 @@ 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; @@ -427,11 +446,15 @@ TEST(Conv, NullString) { } TEST(Conv, VariadicTo) { + testIdenticalTo(); + testIdenticalTo(); testVariadicTo(); testVariadicTo(); } TEST(Conv, VariadicToDelim) { + testIdenticalToDelim(); + testIdenticalToDelim(); testVariadicToDelim(); testVariadicToDelim(); } @@ -911,6 +934,35 @@ void u2aAppendFollyBM(unsigned int n, uint64_t value) { } } +template +struct 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 { + 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 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); \ @@ -969,6 +1021,20 @@ 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); -- 2.34.1