Adding support for printing arbitrary pointers
authorTom Jackson <tjackson@fb.com>
Thu, 8 Nov 2012 23:32:13 +0000 (15:32 -0800)
committerJordan DeLong <jdelong@fb.com>
Sun, 16 Dec 2012 22:43:29 +0000 (14:43 -0800)
Summary: We should be able to print ##Foo*##, even if we can't print ##Foo##.

Test Plan: Unit Tests.

Reviewed By: tudorb@fb.com

FB internal diff: D625977

folly/Format-inl.h
folly/test/FormatTest.cpp

index 25bc7ba77c065634a007347e963dcff496b08a25..944e2869ad68ccd0975a01c4a7b55e69e4a0ff9b 100644 (file)
@@ -787,6 +787,28 @@ class FormatValue<
   T* val_;
 };
 
+template <class T, class = void>
+class TryFormatValue {
+ public:
+  template <class FormatCallback>
+  static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
+    arg.error("No formatter available for this type");
+  }
+};
+
+template <class T>
+class TryFormatValue<
+  T,
+  typename std::enable_if<
+      0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type>
+  {
+ public:
+  template <class FormatCallback>
+  static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
+    FormatValue<typename std::decay<T>::type>(value).format(arg, cb);
+  }
+};
+
 // Partial specialization of FormatValue for other pointers
 template <class T>
 class FormatValue<
@@ -803,8 +825,7 @@ class FormatValue<
     if (arg.keyEmpty()) {
       FormatValue<void*>((void*)val_).format(arg, cb);
     } else {
-      FormatValue<typename std::decay<T>::type>(
-          val_[arg.splitIntKey()]).format(arg, cb);
+      TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb);
     }
   }
  private:
index ed42d7c461ab6f328337ac3be6ce6ce78d0f291a..c34fd49c0f8560196223b798efe095535625ad18 100644 (file)
@@ -131,6 +131,7 @@ TEST(Format, Simple) {
   EXPECT_EQ("0020", vstr("{1:04}", p));
   EXPECT_EQ("0020", fstr("{0[1]:04}", q));
   EXPECT_EQ("0020", vstr("{1:04}", q));
+  EXPECT_NE("", fstr("{}", q));
 
   EXPECT_EQ("0x", fstr("{}", p).substr(0, 2));
   EXPECT_EQ("10", vstr("{}", p));
@@ -279,6 +280,22 @@ TEST(Format, Custom) {
   EXPECT_EQ("<key=hello", fstr("{:.10}", kv));
   EXPECT_EQ("<key=hello, value=42>XX", fstr("{:X<23}", kv));
   EXPECT_EQ("XX<key=hello, value=42>", fstr("{:X>23}", kv));
+  EXPECT_EQ("<key=hello, value=42>", fstr("{0[0]}", &kv));
+  EXPECT_NE("", fstr("{}", &kv));
+}
+
+namespace {
+
+struct Opaque {
+  int k;
+};
+
+} // namespace
+
+TEST(Format, Unformatted) {
+  Opaque o;
+  EXPECT_NE("", fstr("{}", &o));
+  EXPECT_THROW(fstr("{0[0]}", &o), std::invalid_argument);
 }
 
 TEST(Format, Nested) {