jpayne@69
|
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
jpayne@69
|
2 // Licensed under the MIT License:
|
jpayne@69
|
3 //
|
jpayne@69
|
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
|
jpayne@69
|
5 // of this software and associated documentation files (the "Software"), to deal
|
jpayne@69
|
6 // in the Software without restriction, including without limitation the rights
|
jpayne@69
|
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
jpayne@69
|
8 // copies of the Software, and to permit persons to whom the Software is
|
jpayne@69
|
9 // furnished to do so, subject to the following conditions:
|
jpayne@69
|
10 //
|
jpayne@69
|
11 // The above copyright notice and this permission notice shall be included in
|
jpayne@69
|
12 // all copies or substantial portions of the Software.
|
jpayne@69
|
13 //
|
jpayne@69
|
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
jpayne@69
|
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
jpayne@69
|
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
jpayne@69
|
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
jpayne@69
|
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
jpayne@69
|
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
jpayne@69
|
20 // THE SOFTWARE.
|
jpayne@69
|
21
|
jpayne@69
|
22 #pragma once
|
jpayne@69
|
23
|
jpayne@69
|
24 #include "memory.h"
|
jpayne@69
|
25
|
jpayne@69
|
26 KJ_BEGIN_HEADER
|
jpayne@69
|
27
|
jpayne@69
|
28 namespace kj {
|
jpayne@69
|
29
|
jpayne@69
|
30 template <typename Signature>
|
jpayne@69
|
31 class Function;
|
jpayne@69
|
32 // Function wrapper using virtual-based polymorphism. Use this when template polymorphism is
|
jpayne@69
|
33 // not possible. You can, for example, accept a Function as a parameter:
|
jpayne@69
|
34 //
|
jpayne@69
|
35 // void setFilter(Function<bool(const Widget&)> filter);
|
jpayne@69
|
36 //
|
jpayne@69
|
37 // The caller of `setFilter()` may then pass any callable object as the parameter. The callable
|
jpayne@69
|
38 // object does not have to have the exact signature specified, just one that is "compatible" --
|
jpayne@69
|
39 // i.e. the return type is covariant and the parameters are contravariant.
|
jpayne@69
|
40 //
|
jpayne@69
|
41 // Unlike `std::function`, `kj::Function`s are movable but not copyable, just like `kj::Own`. This
|
jpayne@69
|
42 // is to avoid unexpected heap allocation or slow atomic reference counting.
|
jpayne@69
|
43 //
|
jpayne@69
|
44 // When a `Function` is constructed from an lvalue, it captures only a reference to the value.
|
jpayne@69
|
45 // When constructed from an rvalue, it invokes the value's move constructor. So, for example:
|
jpayne@69
|
46 //
|
jpayne@69
|
47 // struct AddN {
|
jpayne@69
|
48 // int n;
|
jpayne@69
|
49 // int operator(int i) { return i + n; }
|
jpayne@69
|
50 // }
|
jpayne@69
|
51 //
|
jpayne@69
|
52 // Function<int(int, int)> f1 = AddN{2};
|
jpayne@69
|
53 // // f1 owns an instance of AddN. It may safely be moved out
|
jpayne@69
|
54 // // of the local scope.
|
jpayne@69
|
55 //
|
jpayne@69
|
56 // AddN adder(2);
|
jpayne@69
|
57 // Function<int(int, int)> f2 = adder;
|
jpayne@69
|
58 // // f2 contains a reference to `adder`. Thus, it becomes invalid
|
jpayne@69
|
59 // // when `adder` goes out-of-scope.
|
jpayne@69
|
60 //
|
jpayne@69
|
61 // AddN adder2(2);
|
jpayne@69
|
62 // Function<int(int, int)> f3 = kj::mv(adder2);
|
jpayne@69
|
63 // // f3 owns an insatnce of AddN moved from `adder2`. f3 may safely
|
jpayne@69
|
64 // // be moved out of the local scope.
|
jpayne@69
|
65 //
|
jpayne@69
|
66 // Additionally, a Function may be bound to a class method using KJ_BIND_METHOD(object, methodName).
|
jpayne@69
|
67 // For example:
|
jpayne@69
|
68 //
|
jpayne@69
|
69 // class Printer {
|
jpayne@69
|
70 // public:
|
jpayne@69
|
71 // void print(int i);
|
jpayne@69
|
72 // void print(kj::StringPtr s);
|
jpayne@69
|
73 // };
|
jpayne@69
|
74 //
|
jpayne@69
|
75 // Printer p;
|
jpayne@69
|
76 //
|
jpayne@69
|
77 // Function<void(uint)> intPrinter = KJ_BIND_METHOD(p, print);
|
jpayne@69
|
78 // // Will call Printer::print(int).
|
jpayne@69
|
79 //
|
jpayne@69
|
80 // Function<void(const char*)> strPrinter = KJ_BIND_METHOD(p, print);
|
jpayne@69
|
81 // // Will call Printer::print(kj::StringPtr).
|
jpayne@69
|
82 //
|
jpayne@69
|
83 // Notice how KJ_BIND_METHOD is able to figure out which overload to use depending on the kind of
|
jpayne@69
|
84 // Function it is binding to.
|
jpayne@69
|
85
|
jpayne@69
|
86 template <typename Signature>
|
jpayne@69
|
87 class ConstFunction;
|
jpayne@69
|
88 // Like Function, but wraps a "const" (i.e. thread-safe) call.
|
jpayne@69
|
89
|
jpayne@69
|
90 template <typename Signature>
|
jpayne@69
|
91 class FunctionParam;
|
jpayne@69
|
92 // Like Function, but used specifically as a call parameter type. Does not do any heap allocation.
|
jpayne@69
|
93 //
|
jpayne@69
|
94 // This type MUST NOT be used for anything other than a parameter type to a function or method.
|
jpayne@69
|
95 // This is because if FunctionParam binds to a temporary, it assumes that the temporary will
|
jpayne@69
|
96 // outlive the FunctionParam instance. This is true when FunctionParam is used as a parameter type,
|
jpayne@69
|
97 // but not if it is used as a local variable nor a class member variable.
|
jpayne@69
|
98
|
jpayne@69
|
99 template <typename Return, typename... Params>
|
jpayne@69
|
100 class Function<Return(Params...)> {
|
jpayne@69
|
101 public:
|
jpayne@69
|
102 template <typename F>
|
jpayne@69
|
103 inline Function(F&& f): impl(heap<Impl<F>>(kj::fwd<F>(f))) {}
|
jpayne@69
|
104 Function() = default;
|
jpayne@69
|
105
|
jpayne@69
|
106 // Make sure people don't accidentally end up wrapping a reference when they meant to return
|
jpayne@69
|
107 // a function.
|
jpayne@69
|
108 KJ_DISALLOW_COPY(Function);
|
jpayne@69
|
109 Function(Function&) = delete;
|
jpayne@69
|
110 Function& operator=(Function&) = delete;
|
jpayne@69
|
111 template <typename T> Function(const Function<T>&) = delete;
|
jpayne@69
|
112 template <typename T> Function& operator=(const Function<T>&) = delete;
|
jpayne@69
|
113 template <typename T> Function(const ConstFunction<T>&) = delete;
|
jpayne@69
|
114 template <typename T> Function& operator=(const ConstFunction<T>&) = delete;
|
jpayne@69
|
115 Function(Function&&) = default;
|
jpayne@69
|
116 Function& operator=(Function&&) = default;
|
jpayne@69
|
117
|
jpayne@69
|
118 inline Return operator()(Params... params) {
|
jpayne@69
|
119 return (*impl)(kj::fwd<Params>(params)...);
|
jpayne@69
|
120 }
|
jpayne@69
|
121
|
jpayne@69
|
122 Function reference() {
|
jpayne@69
|
123 // Forms a new Function of the same type that delegates to this Function by reference.
|
jpayne@69
|
124 // Therefore, this Function must outlive the returned Function, but otherwise they behave
|
jpayne@69
|
125 // exactly the same.
|
jpayne@69
|
126
|
jpayne@69
|
127 return *impl;
|
jpayne@69
|
128 }
|
jpayne@69
|
129
|
jpayne@69
|
130 private:
|
jpayne@69
|
131 class Iface {
|
jpayne@69
|
132 public:
|
jpayne@69
|
133 virtual Return operator()(Params... params) = 0;
|
jpayne@69
|
134 };
|
jpayne@69
|
135
|
jpayne@69
|
136 template <typename F>
|
jpayne@69
|
137 class Impl final: public Iface {
|
jpayne@69
|
138 public:
|
jpayne@69
|
139 explicit Impl(F&& f): f(kj::fwd<F>(f)) {}
|
jpayne@69
|
140
|
jpayne@69
|
141 Return operator()(Params... params) override {
|
jpayne@69
|
142 return f(kj::fwd<Params>(params)...);
|
jpayne@69
|
143 }
|
jpayne@69
|
144
|
jpayne@69
|
145 private:
|
jpayne@69
|
146 F f;
|
jpayne@69
|
147 };
|
jpayne@69
|
148
|
jpayne@69
|
149 Own<Iface> impl;
|
jpayne@69
|
150 };
|
jpayne@69
|
151
|
jpayne@69
|
152 template <typename Return, typename... Params>
|
jpayne@69
|
153 class ConstFunction<Return(Params...)> {
|
jpayne@69
|
154 public:
|
jpayne@69
|
155 template <typename F>
|
jpayne@69
|
156 inline ConstFunction(F&& f): impl(heap<Impl<F>>(kj::fwd<F>(f))) {}
|
jpayne@69
|
157 ConstFunction() = default;
|
jpayne@69
|
158
|
jpayne@69
|
159 // Make sure people don't accidentally end up wrapping a reference when they meant to return
|
jpayne@69
|
160 // a function.
|
jpayne@69
|
161 KJ_DISALLOW_COPY(ConstFunction);
|
jpayne@69
|
162 ConstFunction(ConstFunction&) = delete;
|
jpayne@69
|
163 ConstFunction& operator=(ConstFunction&) = delete;
|
jpayne@69
|
164 template <typename T> ConstFunction(const ConstFunction<T>&) = delete;
|
jpayne@69
|
165 template <typename T> ConstFunction& operator=(const ConstFunction<T>&) = delete;
|
jpayne@69
|
166 template <typename T> ConstFunction(const Function<T>&) = delete;
|
jpayne@69
|
167 template <typename T> ConstFunction& operator=(const Function<T>&) = delete;
|
jpayne@69
|
168 ConstFunction(ConstFunction&&) = default;
|
jpayne@69
|
169 ConstFunction& operator=(ConstFunction&&) = default;
|
jpayne@69
|
170
|
jpayne@69
|
171 inline Return operator()(Params... params) const {
|
jpayne@69
|
172 return (*impl)(kj::fwd<Params>(params)...);
|
jpayne@69
|
173 }
|
jpayne@69
|
174
|
jpayne@69
|
175 ConstFunction reference() const {
|
jpayne@69
|
176 // Forms a new ConstFunction of the same type that delegates to this ConstFunction by reference.
|
jpayne@69
|
177 // Therefore, this ConstFunction must outlive the returned ConstFunction, but otherwise they
|
jpayne@69
|
178 // behave exactly the same.
|
jpayne@69
|
179
|
jpayne@69
|
180 return *impl;
|
jpayne@69
|
181 }
|
jpayne@69
|
182
|
jpayne@69
|
183 private:
|
jpayne@69
|
184 class Iface {
|
jpayne@69
|
185 public:
|
jpayne@69
|
186 virtual Return operator()(Params... params) const = 0;
|
jpayne@69
|
187 };
|
jpayne@69
|
188
|
jpayne@69
|
189 template <typename F>
|
jpayne@69
|
190 class Impl final: public Iface {
|
jpayne@69
|
191 public:
|
jpayne@69
|
192 explicit Impl(F&& f): f(kj::fwd<F>(f)) {}
|
jpayne@69
|
193
|
jpayne@69
|
194 Return operator()(Params... params) const override {
|
jpayne@69
|
195 return f(kj::fwd<Params>(params)...);
|
jpayne@69
|
196 }
|
jpayne@69
|
197
|
jpayne@69
|
198 private:
|
jpayne@69
|
199 F f;
|
jpayne@69
|
200 };
|
jpayne@69
|
201
|
jpayne@69
|
202 Own<Iface> impl;
|
jpayne@69
|
203 };
|
jpayne@69
|
204
|
jpayne@69
|
205 template <typename Return, typename... Params>
|
jpayne@69
|
206 class FunctionParam<Return(Params...)> {
|
jpayne@69
|
207 public:
|
jpayne@69
|
208 template <typename Func>
|
jpayne@69
|
209 FunctionParam(Func&& func) {
|
jpayne@69
|
210 typedef Wrapper<Decay<Func>> WrapperType;
|
jpayne@69
|
211
|
jpayne@69
|
212 // All instances of Wrapper<Func> are two pointers in size: a vtable, and a Func&. So if we
|
jpayne@69
|
213 // allocate space for two pointers, we can construct a Wrapper<Func> in it!
|
jpayne@69
|
214 static_assert(sizeof(WrapperType) == sizeof(space),
|
jpayne@69
|
215 "expected WrapperType to be two pointers");
|
jpayne@69
|
216
|
jpayne@69
|
217 // Even if `func` is an rvalue reference, it's OK to use it as an lvalue here, because
|
jpayne@69
|
218 // FunctionParam is used strictly for parameters. If we captured a temporary, we know that
|
jpayne@69
|
219 // temporary will not be destroyed until after the function call completes.
|
jpayne@69
|
220 ctor(*reinterpret_cast<WrapperType*>(space), func);
|
jpayne@69
|
221 }
|
jpayne@69
|
222
|
jpayne@69
|
223 FunctionParam(const FunctionParam& other) = default;
|
jpayne@69
|
224 FunctionParam(FunctionParam&& other) = default;
|
jpayne@69
|
225 // Magically, a plain copy works.
|
jpayne@69
|
226
|
jpayne@69
|
227 inline Return operator()(Params... params) {
|
jpayne@69
|
228 return (*reinterpret_cast<WrapperBase*>(space))(kj::fwd<Params>(params)...);
|
jpayne@69
|
229 }
|
jpayne@69
|
230
|
jpayne@69
|
231 private:
|
jpayne@69
|
232 alignas(void*) char space[2 * sizeof(void*)];
|
jpayne@69
|
233
|
jpayne@69
|
234 class WrapperBase {
|
jpayne@69
|
235 public:
|
jpayne@69
|
236 virtual Return operator()(Params... params) = 0;
|
jpayne@69
|
237 };
|
jpayne@69
|
238
|
jpayne@69
|
239 template <typename Func>
|
jpayne@69
|
240 class Wrapper: public WrapperBase {
|
jpayne@69
|
241 public:
|
jpayne@69
|
242 Wrapper(Func& func): func(func) {}
|
jpayne@69
|
243
|
jpayne@69
|
244 inline Return operator()(Params... params) override {
|
jpayne@69
|
245 return func(kj::fwd<Params>(params)...);
|
jpayne@69
|
246 }
|
jpayne@69
|
247
|
jpayne@69
|
248 private:
|
jpayne@69
|
249 Func& func;
|
jpayne@69
|
250 };
|
jpayne@69
|
251 };
|
jpayne@69
|
252
|
jpayne@69
|
253 namespace _ { // private
|
jpayne@69
|
254
|
jpayne@69
|
255 template <typename T, typename Func, typename ConstFunc>
|
jpayne@69
|
256 class BoundMethod {
|
jpayne@69
|
257 public:
|
jpayne@69
|
258 BoundMethod(T&& t, Func&& func, ConstFunc&& constFunc)
|
jpayne@69
|
259 : t(kj::fwd<T>(t)), func(kj::mv(func)), constFunc(kj::mv(constFunc)) {}
|
jpayne@69
|
260
|
jpayne@69
|
261 template <typename... Params>
|
jpayne@69
|
262 auto operator()(Params&&... params) {
|
jpayne@69
|
263 return func(t, kj::fwd<Params>(params)...);
|
jpayne@69
|
264 }
|
jpayne@69
|
265 template <typename... Params>
|
jpayne@69
|
266 auto operator()(Params&&... params) const {
|
jpayne@69
|
267 return constFunc(t, kj::fwd<Params>(params)...);
|
jpayne@69
|
268 }
|
jpayne@69
|
269
|
jpayne@69
|
270 private:
|
jpayne@69
|
271 T t;
|
jpayne@69
|
272 Func func;
|
jpayne@69
|
273 ConstFunc constFunc;
|
jpayne@69
|
274 };
|
jpayne@69
|
275
|
jpayne@69
|
276 template <typename T, typename Func, typename ConstFunc>
|
jpayne@69
|
277 BoundMethod<T, Func, ConstFunc> boundMethod(T&& t, Func&& func, ConstFunc&& constFunc) {
|
jpayne@69
|
278 return { kj::fwd<T>(t), kj::fwd<Func>(func), kj::fwd<ConstFunc>(constFunc) };
|
jpayne@69
|
279 }
|
jpayne@69
|
280
|
jpayne@69
|
281 } // namespace _ (private)
|
jpayne@69
|
282
|
jpayne@69
|
283 #define KJ_BIND_METHOD(obj, method) \
|
jpayne@69
|
284 ::kj::_::boundMethod(obj, \
|
jpayne@69
|
285 [](auto& s, auto&&... p) mutable { return s.method(kj::fwd<decltype(p)>(p)...); }, \
|
jpayne@69
|
286 [](auto& s, auto&&... p) { return s.method(kj::fwd<decltype(p)>(p)...); })
|
jpayne@69
|
287 // Macro that produces a functor object which forwards to the method `obj.name`. If `obj` is an
|
jpayne@69
|
288 // lvalue, the functor will hold a reference to it. If `obj` is an rvalue, the functor will
|
jpayne@69
|
289 // contain a copy (by move) of it. The method is allowed to be overloaded.
|
jpayne@69
|
290
|
jpayne@69
|
291 } // namespace kj
|
jpayne@69
|
292
|
jpayne@69
|
293 KJ_END_HEADER
|