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