Unreviewed, rolling out r234489.
[WebKit-https.git] / Source / WTF / wtf / ScopedLambda.h
1 /*
2  * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef ScopedLambda_h
27 #define ScopedLambda_h
28
29 #include <wtf/ForbidHeapAllocation.h>
30
31 namespace WTF {
32
33 // You can use ScopedLambda to efficiently pass lambdas without allocating memory or requiring
34 // template specialization of the callee. The callee should be declared as:
35 //
36 // void foo(const ScopedLambda<MyThings* (int, Stuff&)>&);
37 //
38 // The caller just does:
39 //
40 // void foo(scopedLambda<MyThings* (int, Stuff&)>([&] (int x, Stuff& y) -> MyThings* { blah }));
41 //
42 // Note that this relies on foo() not escaping the lambda. The lambda is only valid while foo() is
43 // on the stack - hence the name ScopedLambda.
44
45 template<typename FunctionType> class ScopedLambda;
46 template<typename ResultType, typename... ArgumentTypes>
47 class ScopedLambda<ResultType (ArgumentTypes...)> {
48     WTF_FORBID_HEAP_ALLOCATION;
49 public:
50     ScopedLambda(ResultType (*impl)(void* arg, ArgumentTypes...) = nullptr, void* arg = nullptr)
51         : m_impl(impl)
52         , m_arg(arg)
53     {
54     }
55
56     template<typename... PassedArgumentTypes>
57     ResultType operator()(PassedArgumentTypes&&... arguments) const
58     {
59         return m_impl(m_arg, std::forward<PassedArgumentTypes>(arguments)...);
60     }
61
62 private:
63     ResultType (*m_impl)(void* arg, ArgumentTypes...);
64     void *m_arg;
65 };
66
67 template<typename FunctionType, typename Functor> class ScopedLambdaFunctor;
68 template<typename ResultType, typename... ArgumentTypes, typename Functor>
69 class ScopedLambdaFunctor<ResultType (ArgumentTypes...), Functor> : public ScopedLambda<ResultType (ArgumentTypes...)> {
70 public:
71     template<typename PassedFunctor>
72     ScopedLambdaFunctor(PassedFunctor&& functor)
73         : ScopedLambda<ResultType (ArgumentTypes...)>(implFunction, this)
74         , m_functor(std::forward<PassedFunctor>(functor))
75     {
76     }
77     
78     // We need to make sure that copying and moving ScopedLambdaFunctor results in a ScopedLambdaFunctor
79     // whose ScopedLambda supertype still points to this rather than other.
80     ScopedLambdaFunctor(const ScopedLambdaFunctor& other)
81         : ScopedLambda<ResultType (ArgumentTypes...)>(implFunction, this)
82         , m_functor(other.m_functor)
83     {
84     }
85
86     ScopedLambdaFunctor(ScopedLambdaFunctor&& other)
87         : ScopedLambda<ResultType (ArgumentTypes...)>(implFunction, this)
88         , m_functor(WTFMove(other.m_functor))
89     {
90     }
91     
92     ScopedLambdaFunctor& operator=(const ScopedLambdaFunctor& other)
93     {
94         m_functor = other.m_functor;
95         return *this;
96     }
97     
98     ScopedLambdaFunctor& operator=(ScopedLambdaFunctor&& other)
99     {
100         m_functor = WTFMove(other.m_functor);
101         return *this;
102     }
103
104 private:
105     static ResultType implFunction(void* argument, ArgumentTypes... arguments)
106     {
107         return static_cast<ScopedLambdaFunctor*>(argument)->m_functor(arguments...);
108     }
109
110     Functor m_functor;
111 };
112
113 // Can't simply rely on perfect forwarding because then the ScopedLambdaFunctor would point to the functor
114 // by const reference. This would be surprising in situations like:
115 //
116 // auto scopedLambda = scopedLambda<Foo(Bar)>([&] (Bar) -> Foo { ... });
117 //
118 // We expected scopedLambda to be valid for its entire lifetime, but if it computed the lambda by reference
119 // then it would be immediately invalid.
120 template<typename FunctionType, typename Functor>
121 ScopedLambdaFunctor<FunctionType, Functor> scopedLambda(const Functor& functor)
122 {
123     return ScopedLambdaFunctor<FunctionType, Functor>(functor);
124 }
125
126 template<typename FunctionType, typename Functor>
127 ScopedLambdaFunctor<FunctionType, Functor> scopedLambda(Functor&& functor)
128 {
129     return ScopedLambdaFunctor<FunctionType, Functor>(WTFMove(functor));
130 }
131
132 template<typename FunctionType, typename Functor> class ScopedLambdaRefFunctor;
133 template<typename ResultType, typename... ArgumentTypes, typename Functor>
134 class ScopedLambdaRefFunctor<ResultType (ArgumentTypes...), Functor> : public ScopedLambda<ResultType (ArgumentTypes...)> {
135 public:
136     ScopedLambdaRefFunctor(const Functor& functor)
137         : ScopedLambda<ResultType (ArgumentTypes...)>(implFunction, this)
138         , m_functor(&functor)
139     {
140     }
141     
142     // We need to make sure that copying and moving ScopedLambdaRefFunctor results in a
143     // ScopedLambdaRefFunctor whose ScopedLambda supertype still points to this rather than
144     // other.
145     ScopedLambdaRefFunctor(const ScopedLambdaRefFunctor& other)
146         : ScopedLambda<ResultType (ArgumentTypes...)>(implFunction, this)
147         , m_functor(other.m_functor)
148     {
149     }
150
151     ScopedLambdaRefFunctor(ScopedLambdaRefFunctor&& other)
152         : ScopedLambda<ResultType (ArgumentTypes...)>(implFunction, this)
153         , m_functor(other.m_functor)
154     {
155     }
156     
157     ScopedLambdaRefFunctor& operator=(const ScopedLambdaRefFunctor& other)
158     {
159         m_functor = other.m_functor;
160         return *this;
161     }
162     
163     ScopedLambdaRefFunctor& operator=(ScopedLambdaRefFunctor&& other)
164     {
165         m_functor = other.m_functor;
166         return *this;
167     }
168
169 private:
170     static ResultType implFunction(void* argument, ArgumentTypes... arguments)
171     {
172         return (*static_cast<ScopedLambdaRefFunctor*>(argument)->m_functor)(arguments...);
173     }
174
175     const Functor* m_functor;
176 };
177
178 // This is for when you already refer to a functor by reference, and you know its lifetime is
179 // good. This just creates a ScopedLambda that points to your functor.
180 //
181 // Note that this is always wrong:
182 //
183 // auto ref = scopedLambdaRef([...] (...) {...});
184 //
185 // Because the scopedLambdaRef will refer to the lambda by reference, and the lambda will die after the
186 // semicolon. Use scopedLambda() in that case.
187 template<typename FunctionType, typename Functor>
188 ScopedLambdaRefFunctor<FunctionType, Functor> scopedLambdaRef(const Functor& functor)
189 {
190     return ScopedLambdaRefFunctor<FunctionType, Functor>(functor);
191 }
192
193 } // namespace WTF
194
195 using WTF::ScopedLambda;
196 using WTF::scopedLambda;
197 using WTF::scopedLambdaRef;
198
199 #endif // ScopedLambda_h
200