Introduce WTF_LAZY_INSTANTIATE
authorjfbastien@apple.com <jfbastien@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Mar 2018 17:36:20 +0000 (17:36 +0000)
committerjfbastien@apple.com <jfbastien@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Mar 2018 17:36:20 +0000 (17:36 +0000)
https://bugs.webkit.org/show_bug.cgi?id=184169
<rdar://problem/39023385>

Reviewed by Mark Lam.

As part of #184164 I'm adding some forwarding methods to
WTF::String. These need to forward RetainPtr and CString, and
usually that would require #include'ing RetainPtr.h and CString.h
to WTFString.h which isn't really something we should do.

Introduce WTF_LAZY_INSTANTIATE to forward-declare functions which
just pass parameters to another function, and return whatever that
other function returned, without having to include the return's /
parameters' type header.

Try it out here: godbolt.org/g/oV8G5Q

* wtf/Forward.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@230109 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WTF/ChangeLog
Source/WTF/wtf/Forward.h

index a2ebfde..6509966 100644 (file)
@@ -1,3 +1,25 @@
+2018-03-30  JF Bastien  <jfbastien@apple.com>
+
+        Introduce WTF_LAZY_INSTANTIATE
+        https://bugs.webkit.org/show_bug.cgi?id=184169
+        <rdar://problem/39023385>
+
+        Reviewed by Mark Lam.
+
+        As part of #184164 I'm adding some forwarding methods to
+        WTF::String. These need to forward RetainPtr and CString, and
+        usually that would require #include'ing RetainPtr.h and CString.h
+        to WTFString.h which isn't really something we should do.
+
+        Introduce WTF_LAZY_INSTANTIATE to forward-declare functions which
+        just pass parameters to another function, and return whatever that
+        other function returned, without having to include the return's /
+        parameters' type header.
+
+        Try it out here: godbolt.org/g/oV8G5Q
+
+        * wtf/Forward.h:
+
 2018-03-29  JF Bastien  <jfbastien@apple.com>
 
         Use Forward.h instead of forward-declaring WTF::String
index 3d9c3fe..1f43f90 100644 (file)
@@ -114,3 +114,51 @@ using WTF::Vector;
 
 template<class T, class E> using Expected = std::experimental::expected<T, E>;
 template<class E> using Unexpected = std::experimental::unexpected<E>;
+
+// Sometimes an inline method simply forwards to another one and does nothing else. If it were
+// just a forward declaration of that method then you would only need a forward declaration of
+// its return types and parameter types too, but because it's inline and it actually needs to
+// return / pass these types (even though it's just passing through whatever it called) you
+// now find yourself having to actually have a full declaration of these types. That might be
+// an include you'd rather avoid.
+//
+// No more. Enter template magic to lazily instantiate that method!
+//
+// This macro makes the method work as if you'd declared the return / parameter types as normal,
+// but forces lazy instantiation of the method at the call site, at which point the caller (not
+// the declaration) had better have a full declaration of the return / parameter types.
+//
+// Simply pass the forward-declared types to the macro, with an alias for each, and then define
+// your function as you otherwise would have but using the aliased name. Why the alias? So you
+// can be lazy on templated types! Sample usage:
+//
+// struct Foo; // No need to define Foo!
+// template<typename T>
+// struct A {
+//     Foo declared(Bar); // Forward declarations of Foo and Bar are sufficient here.
+//     // The below code would normally require a definition of Foo and Bar.
+//     WTF_LAZY_INSTANTIATE(Foo=Foo, Bar=Bar) Foo forwarder(Bar b) { return declared(b); }
+// };
+#define WTF_LAZY_JOIN_UNLAZE(A, B) A##B
+#define WTF_LAZY_JOIN(A, B) WTF_LAZY_JOIN_UNLAZE(A, B)
+#define WTF_LAZY_ARGUMENT_NUMBER(_1, _2, _3, _4, _5, _6, _7, N, ...) N
+#define WTF_LAZY_REVERSE_SEQUENCE() 7, 6, 5, 4, 3, 2, 1, 0
+#define WTF_LAZY_NUM_ARGS_(...) WTF_LAZY_ARGUMENT_NUMBER(__VA_ARGS__)
+#define WTF_LAZY_NUM_ARGS(...) WTF_LAZY_NUM_ARGS_(__VA_ARGS__, WTF_LAZY_REVERSE_SEQUENCE())
+#define WTF_LAZY_FOR_EACH_TERM(F, ...) \
+    WTF_LAZY_JOIN(WTF_LAZY_FOR_EACH_TERM_, WTF_LAZY_NUM_ARGS(__VA_ARGS__))(F, (__VA_ARGS__))
+#define WTF_LAZY_FIRST(_1, ...) _1
+#define WTF_LAZY_REST(_1, ...) (__VA_ARGS__)
+#define WTF_LAZY_FOR_EACH_TERM_0(...)
+#define WTF_LAZY_FOR_EACH_TERM_1(F, ARGS) F(WTF_LAZY_FIRST ARGS) WTF_LAZY_FOR_EACH_TERM_0(F, WTF_LAZY_REST ARGS)
+#define WTF_LAZY_FOR_EACH_TERM_2(F, ARGS) F(WTF_LAZY_FIRST ARGS) WTF_LAZY_FOR_EACH_TERM_1(F, WTF_LAZY_REST ARGS)
+#define WTF_LAZY_FOR_EACH_TERM_3(F, ARGS) F(WTF_LAZY_FIRST ARGS) WTF_LAZY_FOR_EACH_TERM_2(F, WTF_LAZY_REST ARGS)
+#define WTF_LAZY_FOR_EACH_TERM_4(F, ARGS) F(WTF_LAZY_FIRST ARGS) WTF_LAZY_FOR_EACH_TERM_3(F, WTF_LAZY_REST ARGS)
+#define WTF_LAZY_FOR_EACH_TERM_5(F, ARGS) F(WTF_LAZY_FIRST ARGS) WTF_LAZY_FOR_EACH_TERM_4(F, WTF_LAZY_REST ARGS)
+#define WTF_LAZY_FOR_EACH_TERM_6(F, ARGS) F(WTF_LAZY_FIRST ARGS) WTF_LAZY_FOR_EACH_TERM_5(F, WTF_LAZY_REST ARGS)
+#define WTF_LAZY_FOR_EACH_TERM_7(F, ARGS) F(WTF_LAZY_FIRST ARGS) WTF_LAZY_FOR_EACH_TERM_6(F, WTF_LAZY_REST ARGS)
+#define WTF_LAZY_DECLARE_ALIAS_AND_TYPE(ALIAS_AND_TYPE) typename ALIAS_AND_TYPE,
+#define WTF_LAZY_INSTANTIATE(...)                                        \
+    template<                                                            \
+    WTF_LAZY_FOR_EACH_TERM(WTF_LAZY_DECLARE_ALIAS_AND_TYPE, __VA_ARGS__) \
+    typename = void>