From 8ff3329c0acab544de0c1752ce6356d78fbe9273 Mon Sep 17 00:00:00 2001 From: Tom Jackson Date: Thu, 8 Nov 2012 14:59:20 -0800 Subject: [PATCH] Enabling format("{}", format(...)) Summary: If your format string ends up being conditional, it's handy to be able to chain together formatters. Test Plan: Unit tests Reviewed By: tudorb@fb.com FB internal diff: D625502 --- folly/Format-inl.h | 15 ++++++++++++++ folly/test/FormatBenchmark.cpp | 38 ++++++++++++++++++++++++++++++++++ folly/test/FormatTest.cpp | 8 +++++++ 3 files changed, 61 insertions(+) diff --git a/folly/Format-inl.h b/folly/Format-inl.h index 3e5cf212..25bc7ba7 100644 --- a/folly/Format-inl.h +++ b/folly/Format-inl.h @@ -1063,6 +1063,21 @@ class FormatValue> { const Tuple& val_; }; +// Partial specialization of FormatValue for nested Formatters +template +class FormatValue, void> { + typedef Formatter FormatterValue; + public: + explicit FormatValue(const FormatterValue& f) : f_(f) { } + + template + void format(FormatArg& arg, FormatCallback& cb) const { + format_value::formatFormatter(f_, arg, cb); + } + private: + const FormatterValue& f_; +}; + /** * Formatter objects can be appended to strings, and therefore they're * compatible with folly::toAppend and folly::to. diff --git a/folly/test/FormatBenchmark.cpp b/folly/test/FormatBenchmark.cpp index 6d4b76a4..79b124b4 100644 --- a/folly/test/FormatBenchmark.cpp +++ b/folly/test/FormatBenchmark.cpp @@ -123,6 +123,44 @@ BENCHMARK_RELATIVE(bigFormat_format, iters) { } } +BENCHMARK_DRAW_LINE() + +BENCHMARK(format_nested_strings, iters) { + while (iters--) { + fbstring out; + for (int i = 0; i < 1000; ++i) { + out.clear(); + format(&out, "{} {}", + format("{} {}", i, i + 1).str(), + format("{} {}", -i, -i - 1).str()); + } + } +} + +BENCHMARK_RELATIVE(format_nested_fbstrings, iters) { + while (iters--) { + fbstring out; + for (int i = 0; i < 1000; ++i) { + out.clear(); + format(&out, "{} {}", + format("{} {}", i, i + 1).fbstr(), + format("{} {}", -i, -i - 1).fbstr()); + } + } +} + +BENCHMARK_RELATIVE(format_nested_direct, iters) { + while (iters--) { + fbstring out; + for (int i = 0; i < 1000; ++i) { + out.clear(); + format(&out, "{} {}", + format("{} {}", i, i + 1), + format("{} {}", -i, -i - 1)); + } + } +} + // Benchmark results on my dev server (dual-CPU Xeon L5520 @ 2.7GHz) // // ============================================================================ diff --git a/folly/test/FormatTest.cpp b/folly/test/FormatTest.cpp index e50ce3a2..ed42d7c4 100644 --- a/folly/test/FormatTest.cpp +++ b/folly/test/FormatTest.cpp @@ -281,6 +281,14 @@ TEST(Format, Custom) { EXPECT_EQ("XX", fstr("{:X>23}", kv)); } +TEST(Format, Nested) { + EXPECT_EQ("1 2 3 4", fstr("{} {} {}", 1, 2, format("{} {}", 3, 4))); + // + // not copyable, must hold temporary in scope instead. + auto&& saved = format("{} {}", 3, 4); + EXPECT_EQ("1 2 3 4", fstr("{} {} {}", 1, 2, saved)); +} + int main(int argc, char *argv[]) { testing::InitGoogleTest(&argc, argv); google::ParseCommandLineFlags(&argc, &argv, true); -- 2.34.1