Enabling format("{}", format(...))
authorTom Jackson <tjackson@fb.com>
Thu, 8 Nov 2012 22:59:20 +0000 (14:59 -0800)
committerJordan DeLong <jdelong@fb.com>
Sun, 16 Dec 2012 22:43:24 +0000 (14:43 -0800)
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
folly/test/FormatBenchmark.cpp
folly/test/FormatTest.cpp

index 3e5cf2128361c65f160a37ae16d883d39da8a9b8..25bc7ba77c065634a007347e963dcff496b08a25 100644 (file)
@@ -1063,6 +1063,21 @@ class FormatValue<std::tuple<Args...>> {
   const Tuple& val_;
 };
 
+// Partial specialization of FormatValue for nested Formatters
+template <bool containerMode, class... Args>
+class FormatValue<Formatter<containerMode, Args...>, void> {
+  typedef Formatter<containerMode, Args...> FormatterValue;
+ public:
+  explicit FormatValue(const FormatterValue& f) : f_(f) { }
+
+  template <class FormatCallback>
+  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.
index 6d4b76a4b021b5cd83b9fcfcf8ea51c0c754213b..79b124b4818d017fe9bfe79696a6c7d372eb180a 100644 (file)
@@ -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)
 //
 // ============================================================================
index e50ce3a2cd4c52594c9c43f77e2b4058f7b86f8a..ed42d7c461ab6f328337ac3be6ce6ce78d0f291a 100644 (file)
@@ -281,6 +281,14 @@ TEST(Format, Custom) {
   EXPECT_EQ("XX<key=hello, value=42>", 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);