Commit 587427e7 authored by Zejun Wu's avatar Zejun Wu Committed by Anton Likhtarov

Specialize string to identical string conversion

Summary:
Avoid copying underlying char array in to<string>(const string&) and
to<fbstring>(const fbstring&).

Test Plan: fbconfig -r $redteamisthebestteam/$nekomikoreimu && fbmake

Reviewed By: ldbrandy@fb.com

Subscribers: jonp, folly@lists

FB internal diff: D1368183

Tasks: 4263125
parent aed6ef6f
...@@ -526,24 +526,56 @@ toAppendDelim(const Delimiter& delim, const T& v, const Ts&... vs) { ...@@ -526,24 +526,56 @@ toAppendDelim(const Delimiter& delim, const T& v, const Ts&... vs) {
toAppendDelim(delim, vs...); toAppendDelim(delim, vs...);
} }
/**
* to<SomeString>(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 <class Tgt, class Src>
typename std::enable_if<
IsSomeString<Tgt>::value && std::is_same<Tgt, Src>::value,
Tgt>::type
to(const Src & value) {
return value;
}
/** /**
* to<SomeString>(v1, v2, ...) uses toAppend() (see below) as back-end * to<SomeString>(v1, v2, ...) uses toAppend() (see below) as back-end
* for all types. * for all types.
*/ */
template <class Tgt, class... Ts> template <class Tgt, class... Ts>
typename std::enable_if<IsSomeString<Tgt>::value, Tgt>::type typename std::enable_if<
IsSomeString<Tgt>::value && (
sizeof...(Ts) != 1 ||
!std::is_same<Tgt, typename detail::last_element<Ts...>::type>::value),
Tgt>::type
to(const Ts&... vs) { to(const Ts&... vs) {
Tgt result; Tgt result;
toAppend(vs..., &result); toAppend(vs..., &result);
return result; return result;
} }
/**
* toDelim<SomeString>(SomeString str) returns itself.
*/
template <class Tgt, class Delim, class Src>
typename std::enable_if<
IsSomeString<Tgt>::value && std::is_same<Tgt, Src>::value,
Tgt>::type
toDelim(const Delim& delim, const Src & value) {
return value;
}
/** /**
* toDelim<SomeString>(delim, v1, v2, ...) uses toAppendDelim() as * toDelim<SomeString>(delim, v1, v2, ...) uses toAppendDelim() as
* back-end for all types. * back-end for all types.
*/ */
template <class Tgt, class Delim, class... Ts> template <class Tgt, class Delim, class... Ts>
typename std::enable_if<IsSomeString<Tgt>::value, Tgt>::type typename std::enable_if<
IsSomeString<Tgt>::value && (
sizeof...(Ts) != 1 ||
!std::is_same<Tgt, typename detail::last_element<Ts...>::type>::value),
Tgt>::type
toDelim(const Delim& delim, const Ts&... vs) { toDelim(const Delim& delim, const Ts&... vs) {
Tgt result; Tgt result;
toAppendDelim(delim, vs..., &result); toAppendDelim(delim, vs..., &result);
......
...@@ -389,6 +389,14 @@ TEST(Conv, BadStringToIntegral) { ...@@ -389,6 +389,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> template <class String>
void testVariadicTo() { void testVariadicTo() {
String s; String s;
...@@ -403,6 +411,17 @@ void testVariadicTo() { ...@@ -403,6 +411,17 @@ void testVariadicTo() {
EXPECT_EQ(s, "Lorem ipsum 1234 dolor amet 567.89."); 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> template <class String>
void testVariadicToDelim() { void testVariadicToDelim() {
String s; String s;
...@@ -427,11 +446,15 @@ TEST(Conv, NullString) { ...@@ -427,11 +446,15 @@ TEST(Conv, NullString) {
} }
TEST(Conv, VariadicTo) { TEST(Conv, VariadicTo) {
testIdenticalTo<string>();
testIdenticalTo<fbstring>();
testVariadicTo<string>(); testVariadicTo<string>();
testVariadicTo<fbstring>(); testVariadicTo<fbstring>();
} }
TEST(Conv, VariadicToDelim) { TEST(Conv, VariadicToDelim) {
testIdenticalToDelim<string>();
testIdenticalToDelim<fbstring>();
testVariadicToDelim<string>(); testVariadicToDelim<string>();
testVariadicToDelim<fbstring>(); testVariadicToDelim<fbstring>();
} }
...@@ -911,6 +934,35 @@ void u2aAppendFollyBM(unsigned int n, uint64_t value) { ...@@ -911,6 +934,35 @@ void u2aAppendFollyBM(unsigned int n, uint64_t value) {
} }
} }
template <class String>
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<String>(s);
doNotOptimizeAway(result.size());
}
}
};
template <class String>
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<String>(s, nullptr);
doNotOptimizeAway(result.size());
}
}
};
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) \ #define DEFINE_BENCHMARK_GROUP(n) \
BENCHMARK_PARAM(u64ToAsciiClassicBM, n); \ BENCHMARK_PARAM(u64ToAsciiClassicBM, n); \
BENCHMARK_RELATIVE_PARAM(u64ToAsciiTableBM, n); \ BENCHMARK_RELATIVE_PARAM(u64ToAsciiTableBM, n); \
...@@ -969,6 +1021,20 @@ DEFINE_BENCHMARK_GROUP(19); ...@@ -969,6 +1021,20 @@ DEFINE_BENCHMARK_GROUP(19);
#undef DEFINE_BENCHMARK_GROUP #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) { int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);
google::ParseCommandLineFlags(&argc, &argv, true); google::ParseCommandLineFlags(&argc, &argv, true);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment