jpayne@69: // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors jpayne@69: // Licensed under the MIT License: jpayne@69: // jpayne@69: // Permission is hereby granted, free of charge, to any person obtaining a copy jpayne@69: // of this software and associated documentation files (the "Software"), to deal jpayne@69: // in the Software without restriction, including without limitation the rights jpayne@69: // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell jpayne@69: // copies of the Software, and to permit persons to whom the Software is jpayne@69: // furnished to do so, subject to the following conditions: jpayne@69: // jpayne@69: // The above copyright notice and this permission notice shall be included in jpayne@69: // all copies or substantial portions of the Software. jpayne@69: // jpayne@69: // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR jpayne@69: // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, jpayne@69: // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE jpayne@69: // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER jpayne@69: // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, jpayne@69: // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN jpayne@69: // THE SOFTWARE. jpayne@69: jpayne@69: #pragma once jpayne@69: jpayne@69: #include "memory.h" jpayne@69: jpayne@69: KJ_BEGIN_HEADER jpayne@69: jpayne@69: namespace kj { jpayne@69: jpayne@69: template jpayne@69: class Function; jpayne@69: // Function wrapper using virtual-based polymorphism. Use this when template polymorphism is jpayne@69: // not possible. You can, for example, accept a Function as a parameter: jpayne@69: // jpayne@69: // void setFilter(Function filter); jpayne@69: // jpayne@69: // The caller of `setFilter()` may then pass any callable object as the parameter. The callable jpayne@69: // object does not have to have the exact signature specified, just one that is "compatible" -- jpayne@69: // i.e. the return type is covariant and the parameters are contravariant. jpayne@69: // jpayne@69: // Unlike `std::function`, `kj::Function`s are movable but not copyable, just like `kj::Own`. This jpayne@69: // is to avoid unexpected heap allocation or slow atomic reference counting. jpayne@69: // jpayne@69: // When a `Function` is constructed from an lvalue, it captures only a reference to the value. jpayne@69: // When constructed from an rvalue, it invokes the value's move constructor. So, for example: jpayne@69: // jpayne@69: // struct AddN { jpayne@69: // int n; jpayne@69: // int operator(int i) { return i + n; } jpayne@69: // } jpayne@69: // jpayne@69: // Function f1 = AddN{2}; jpayne@69: // // f1 owns an instance of AddN. It may safely be moved out jpayne@69: // // of the local scope. jpayne@69: // jpayne@69: // AddN adder(2); jpayne@69: // Function f2 = adder; jpayne@69: // // f2 contains a reference to `adder`. Thus, it becomes invalid jpayne@69: // // when `adder` goes out-of-scope. jpayne@69: // jpayne@69: // AddN adder2(2); jpayne@69: // Function f3 = kj::mv(adder2); jpayne@69: // // f3 owns an insatnce of AddN moved from `adder2`. f3 may safely jpayne@69: // // be moved out of the local scope. jpayne@69: // jpayne@69: // Additionally, a Function may be bound to a class method using KJ_BIND_METHOD(object, methodName). jpayne@69: // For example: jpayne@69: // jpayne@69: // class Printer { jpayne@69: // public: jpayne@69: // void print(int i); jpayne@69: // void print(kj::StringPtr s); jpayne@69: // }; jpayne@69: // jpayne@69: // Printer p; jpayne@69: // jpayne@69: // Function intPrinter = KJ_BIND_METHOD(p, print); jpayne@69: // // Will call Printer::print(int). jpayne@69: // jpayne@69: // Function strPrinter = KJ_BIND_METHOD(p, print); jpayne@69: // // Will call Printer::print(kj::StringPtr). jpayne@69: // jpayne@69: // Notice how KJ_BIND_METHOD is able to figure out which overload to use depending on the kind of jpayne@69: // Function it is binding to. jpayne@69: jpayne@69: template jpayne@69: class ConstFunction; jpayne@69: // Like Function, but wraps a "const" (i.e. thread-safe) call. jpayne@69: jpayne@69: template jpayne@69: class FunctionParam; jpayne@69: // Like Function, but used specifically as a call parameter type. Does not do any heap allocation. jpayne@69: // jpayne@69: // This type MUST NOT be used for anything other than a parameter type to a function or method. jpayne@69: // This is because if FunctionParam binds to a temporary, it assumes that the temporary will jpayne@69: // outlive the FunctionParam instance. This is true when FunctionParam is used as a parameter type, jpayne@69: // but not if it is used as a local variable nor a class member variable. jpayne@69: jpayne@69: template jpayne@69: class Function { jpayne@69: public: jpayne@69: template jpayne@69: inline Function(F&& f): impl(heap>(kj::fwd(f))) {} jpayne@69: Function() = default; jpayne@69: jpayne@69: // Make sure people don't accidentally end up wrapping a reference when they meant to return jpayne@69: // a function. jpayne@69: KJ_DISALLOW_COPY(Function); jpayne@69: Function(Function&) = delete; jpayne@69: Function& operator=(Function&) = delete; jpayne@69: template Function(const Function&) = delete; jpayne@69: template Function& operator=(const Function&) = delete; jpayne@69: template Function(const ConstFunction&) = delete; jpayne@69: template Function& operator=(const ConstFunction&) = delete; jpayne@69: Function(Function&&) = default; jpayne@69: Function& operator=(Function&&) = default; jpayne@69: jpayne@69: inline Return operator()(Params... params) { jpayne@69: return (*impl)(kj::fwd(params)...); jpayne@69: } jpayne@69: jpayne@69: Function reference() { jpayne@69: // Forms a new Function of the same type that delegates to this Function by reference. jpayne@69: // Therefore, this Function must outlive the returned Function, but otherwise they behave jpayne@69: // exactly the same. jpayne@69: jpayne@69: return *impl; jpayne@69: } jpayne@69: jpayne@69: private: jpayne@69: class Iface { jpayne@69: public: jpayne@69: virtual Return operator()(Params... params) = 0; jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: class Impl final: public Iface { jpayne@69: public: jpayne@69: explicit Impl(F&& f): f(kj::fwd(f)) {} jpayne@69: jpayne@69: Return operator()(Params... params) override { jpayne@69: return f(kj::fwd(params)...); jpayne@69: } jpayne@69: jpayne@69: private: jpayne@69: F f; jpayne@69: }; jpayne@69: jpayne@69: Own impl; jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: class ConstFunction { jpayne@69: public: jpayne@69: template jpayne@69: inline ConstFunction(F&& f): impl(heap>(kj::fwd(f))) {} jpayne@69: ConstFunction() = default; jpayne@69: jpayne@69: // Make sure people don't accidentally end up wrapping a reference when they meant to return jpayne@69: // a function. jpayne@69: KJ_DISALLOW_COPY(ConstFunction); jpayne@69: ConstFunction(ConstFunction&) = delete; jpayne@69: ConstFunction& operator=(ConstFunction&) = delete; jpayne@69: template ConstFunction(const ConstFunction&) = delete; jpayne@69: template ConstFunction& operator=(const ConstFunction&) = delete; jpayne@69: template ConstFunction(const Function&) = delete; jpayne@69: template ConstFunction& operator=(const Function&) = delete; jpayne@69: ConstFunction(ConstFunction&&) = default; jpayne@69: ConstFunction& operator=(ConstFunction&&) = default; jpayne@69: jpayne@69: inline Return operator()(Params... params) const { jpayne@69: return (*impl)(kj::fwd(params)...); jpayne@69: } jpayne@69: jpayne@69: ConstFunction reference() const { jpayne@69: // Forms a new ConstFunction of the same type that delegates to this ConstFunction by reference. jpayne@69: // Therefore, this ConstFunction must outlive the returned ConstFunction, but otherwise they jpayne@69: // behave exactly the same. jpayne@69: jpayne@69: return *impl; jpayne@69: } jpayne@69: jpayne@69: private: jpayne@69: class Iface { jpayne@69: public: jpayne@69: virtual Return operator()(Params... params) const = 0; jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: class Impl final: public Iface { jpayne@69: public: jpayne@69: explicit Impl(F&& f): f(kj::fwd(f)) {} jpayne@69: jpayne@69: Return operator()(Params... params) const override { jpayne@69: return f(kj::fwd(params)...); jpayne@69: } jpayne@69: jpayne@69: private: jpayne@69: F f; jpayne@69: }; jpayne@69: jpayne@69: Own impl; jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: class FunctionParam { jpayne@69: public: jpayne@69: template jpayne@69: FunctionParam(Func&& func) { jpayne@69: typedef Wrapper> WrapperType; jpayne@69: jpayne@69: // All instances of Wrapper are two pointers in size: a vtable, and a Func&. So if we jpayne@69: // allocate space for two pointers, we can construct a Wrapper in it! jpayne@69: static_assert(sizeof(WrapperType) == sizeof(space), jpayne@69: "expected WrapperType to be two pointers"); jpayne@69: jpayne@69: // Even if `func` is an rvalue reference, it's OK to use it as an lvalue here, because jpayne@69: // FunctionParam is used strictly for parameters. If we captured a temporary, we know that jpayne@69: // temporary will not be destroyed until after the function call completes. jpayne@69: ctor(*reinterpret_cast(space), func); jpayne@69: } jpayne@69: jpayne@69: FunctionParam(const FunctionParam& other) = default; jpayne@69: FunctionParam(FunctionParam&& other) = default; jpayne@69: // Magically, a plain copy works. jpayne@69: jpayne@69: inline Return operator()(Params... params) { jpayne@69: return (*reinterpret_cast(space))(kj::fwd(params)...); jpayne@69: } jpayne@69: jpayne@69: private: jpayne@69: alignas(void*) char space[2 * sizeof(void*)]; jpayne@69: jpayne@69: class WrapperBase { jpayne@69: public: jpayne@69: virtual Return operator()(Params... params) = 0; jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: class Wrapper: public WrapperBase { jpayne@69: public: jpayne@69: Wrapper(Func& func): func(func) {} jpayne@69: jpayne@69: inline Return operator()(Params... params) override { jpayne@69: return func(kj::fwd(params)...); jpayne@69: } jpayne@69: jpayne@69: private: jpayne@69: Func& func; jpayne@69: }; jpayne@69: }; jpayne@69: jpayne@69: namespace _ { // private jpayne@69: jpayne@69: template jpayne@69: class BoundMethod { jpayne@69: public: jpayne@69: BoundMethod(T&& t, Func&& func, ConstFunc&& constFunc) jpayne@69: : t(kj::fwd(t)), func(kj::mv(func)), constFunc(kj::mv(constFunc)) {} jpayne@69: jpayne@69: template jpayne@69: auto operator()(Params&&... params) { jpayne@69: return func(t, kj::fwd(params)...); jpayne@69: } jpayne@69: template jpayne@69: auto operator()(Params&&... params) const { jpayne@69: return constFunc(t, kj::fwd(params)...); jpayne@69: } jpayne@69: jpayne@69: private: jpayne@69: T t; jpayne@69: Func func; jpayne@69: ConstFunc constFunc; jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: BoundMethod boundMethod(T&& t, Func&& func, ConstFunc&& constFunc) { jpayne@69: return { kj::fwd(t), kj::fwd(func), kj::fwd(constFunc) }; jpayne@69: } jpayne@69: jpayne@69: } // namespace _ (private) jpayne@69: jpayne@69: #define KJ_BIND_METHOD(obj, method) \ jpayne@69: ::kj::_::boundMethod(obj, \ jpayne@69: [](auto& s, auto&&... p) mutable { return s.method(kj::fwd(p)...); }, \ jpayne@69: [](auto& s, auto&&... p) { return s.method(kj::fwd(p)...); }) jpayne@69: // Macro that produces a functor object which forwards to the method `obj.name`. If `obj` is an jpayne@69: // lvalue, the functor will hold a reference to it. If `obj` is an rvalue, the functor will jpayne@69: // contain a copy (by move) of it. The method is allowed to be overloaded. jpayne@69: jpayne@69: } // namespace kj jpayne@69: jpayne@69: KJ_END_HEADER