cannam@49: // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors cannam@49: // Licensed under the MIT License: cannam@49: // cannam@49: // Permission is hereby granted, free of charge, to any person obtaining a copy cannam@49: // of this software and associated documentation files (the "Software"), to deal cannam@49: // in the Software without restriction, including without limitation the rights cannam@49: // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell cannam@49: // copies of the Software, and to permit persons to whom the Software is cannam@49: // furnished to do so, subject to the following conditions: cannam@49: // cannam@49: // The above copyright notice and this permission notice shall be included in cannam@49: // all copies or substantial portions of the Software. cannam@49: // cannam@49: // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR cannam@49: // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, cannam@49: // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE cannam@49: // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER cannam@49: // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, cannam@49: // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN cannam@49: // THE SOFTWARE. cannam@49: cannam@49: #ifndef KJ_FUNCTION_H_ cannam@49: #define KJ_FUNCTION_H_ cannam@49: cannam@49: #if defined(__GNUC__) && !KJ_HEADER_WARNINGS cannam@49: #pragma GCC system_header cannam@49: #endif cannam@49: cannam@49: #include "memory.h" cannam@49: cannam@49: namespace kj { cannam@49: cannam@49: template cannam@49: class Function; cannam@49: // Function wrapper using virtual-based polymorphism. Use this when template polymorphism is cannam@49: // not possible. You can, for example, accept a Function as a parameter: cannam@49: // cannam@49: // void setFilter(Function filter); cannam@49: // cannam@49: // The caller of `setFilter()` may then pass any callable object as the parameter. The callable cannam@49: // object does not have to have the exact signature specified, just one that is "compatible" -- cannam@49: // i.e. the return type is covariant and the parameters are contravariant. cannam@49: // cannam@49: // Unlike `std::function`, `kj::Function`s are movable but not copyable, just like `kj::Own`. This cannam@49: // is to avoid unexpected heap allocation or slow atomic reference counting. cannam@49: // cannam@49: // When a `Function` is constructed from an lvalue, it captures only a reference to the value. cannam@49: // When constructed from an rvalue, it invokes the value's move constructor. So, for example: cannam@49: // cannam@49: // struct AddN { cannam@49: // int n; cannam@49: // int operator(int i) { return i + n; } cannam@49: // } cannam@49: // cannam@49: // Function f1 = AddN{2}; cannam@49: // // f1 owns an instance of AddN. It may safely be moved out cannam@49: // // of the local scope. cannam@49: // cannam@49: // AddN adder(2); cannam@49: // Function f2 = adder; cannam@49: // // f2 contains a reference to `adder`. Thus, it becomes invalid cannam@49: // // when `adder` goes out-of-scope. cannam@49: // cannam@49: // AddN adder2(2); cannam@49: // Function f3 = kj::mv(adder2); cannam@49: // // f3 owns an insatnce of AddN moved from `adder2`. f3 may safely cannam@49: // // be moved out of the local scope. cannam@49: // cannam@49: // Additionally, a Function may be bound to a class method using KJ_BIND_METHOD(object, methodName). cannam@49: // For example: cannam@49: // cannam@49: // class Printer { cannam@49: // public: cannam@49: // void print(int i); cannam@49: // void print(kj::StringPtr s); cannam@49: // }; cannam@49: // cannam@49: // Printer p; cannam@49: // cannam@49: // Function intPrinter = KJ_BIND_METHOD(p, print); cannam@49: // // Will call Printer::print(int). cannam@49: // cannam@49: // Function strPrinter = KJ_BIND_METHOD(p, print); cannam@49: // // Will call Printer::print(kj::StringPtr). cannam@49: // cannam@49: // Notice how KJ_BIND_METHOD is able to figure out which overload to use depending on the kind of cannam@49: // Function it is binding to. cannam@49: cannam@49: template cannam@49: class ConstFunction; cannam@49: // Like Function, but wraps a "const" (i.e. thread-safe) call. cannam@49: cannam@49: template cannam@49: class Function { cannam@49: public: cannam@49: template cannam@49: inline Function(F&& f): impl(heap>(kj::fwd(f))) {} cannam@49: Function() = default; cannam@49: cannam@49: // Make sure people don't accidentally end up wrapping a reference when they meant to return cannam@49: // a function. cannam@49: KJ_DISALLOW_COPY(Function); cannam@49: Function(Function&) = delete; cannam@49: Function& operator=(Function&) = delete; cannam@49: template Function(const Function&) = delete; cannam@49: template Function& operator=(const Function&) = delete; cannam@49: template Function(const ConstFunction&) = delete; cannam@49: template Function& operator=(const ConstFunction&) = delete; cannam@49: Function(Function&&) = default; cannam@49: Function& operator=(Function&&) = default; cannam@49: cannam@49: inline Return operator()(Params... params) { cannam@49: return (*impl)(kj::fwd(params)...); cannam@49: } cannam@49: cannam@49: Function reference() { cannam@49: // Forms a new Function of the same type that delegates to this Function by reference. cannam@49: // Therefore, this Function must outlive the returned Function, but otherwise they behave cannam@49: // exactly the same. cannam@49: cannam@49: return *impl; cannam@49: } cannam@49: cannam@49: private: cannam@49: class Iface { cannam@49: public: cannam@49: virtual Return operator()(Params... params) = 0; cannam@49: }; cannam@49: cannam@49: template cannam@49: class Impl final: public Iface { cannam@49: public: cannam@49: explicit Impl(F&& f): f(kj::fwd(f)) {} cannam@49: cannam@49: Return operator()(Params... params) override { cannam@49: return f(kj::fwd(params)...); cannam@49: } cannam@49: cannam@49: private: cannam@49: F f; cannam@49: }; cannam@49: cannam@49: Own impl; cannam@49: }; cannam@49: cannam@49: template cannam@49: class ConstFunction { cannam@49: public: cannam@49: template cannam@49: inline ConstFunction(F&& f): impl(heap>(kj::fwd(f))) {} cannam@49: ConstFunction() = default; cannam@49: cannam@49: // Make sure people don't accidentally end up wrapping a reference when they meant to return cannam@49: // a function. cannam@49: KJ_DISALLOW_COPY(ConstFunction); cannam@49: ConstFunction(ConstFunction&) = delete; cannam@49: ConstFunction& operator=(ConstFunction&) = delete; cannam@49: template ConstFunction(const ConstFunction&) = delete; cannam@49: template ConstFunction& operator=(const ConstFunction&) = delete; cannam@49: template ConstFunction(const Function&) = delete; cannam@49: template ConstFunction& operator=(const Function&) = delete; cannam@49: ConstFunction(ConstFunction&&) = default; cannam@49: ConstFunction& operator=(ConstFunction&&) = default; cannam@49: cannam@49: inline Return operator()(Params... params) const { cannam@49: return (*impl)(kj::fwd(params)...); cannam@49: } cannam@49: cannam@49: ConstFunction reference() const { cannam@49: // Forms a new ConstFunction of the same type that delegates to this ConstFunction by reference. cannam@49: // Therefore, this ConstFunction must outlive the returned ConstFunction, but otherwise they cannam@49: // behave exactly the same. cannam@49: cannam@49: return *impl; cannam@49: } cannam@49: cannam@49: private: cannam@49: class Iface { cannam@49: public: cannam@49: virtual Return operator()(Params... params) const = 0; cannam@49: }; cannam@49: cannam@49: template cannam@49: class Impl final: public Iface { cannam@49: public: cannam@49: explicit Impl(F&& f): f(kj::fwd(f)) {} cannam@49: cannam@49: Return operator()(Params... params) const override { cannam@49: return f(kj::fwd(params)...); cannam@49: } cannam@49: cannam@49: private: cannam@49: F f; cannam@49: }; cannam@49: cannam@49: Own impl; cannam@49: }; cannam@49: cannam@49: #if 1 cannam@49: cannam@49: namespace _ { // private cannam@49: cannam@49: template cannam@49: class BoundMethod; cannam@49: cannam@49: template ::*method)(Params...)> cannam@49: class BoundMethod::*)(Params...), method> { cannam@49: public: cannam@49: BoundMethod(T&& t): t(kj::fwd(t)) {} cannam@49: cannam@49: Return operator()(Params&&... params) { cannam@49: return (t.*method)(kj::fwd(params)...); cannam@49: } cannam@49: cannam@49: private: cannam@49: T t; cannam@49: }; cannam@49: cannam@49: template ::*method)(Params...) const> cannam@49: class BoundMethod::*)(Params...) const, method> { cannam@49: public: cannam@49: BoundMethod(T&& t): t(kj::fwd(t)) {} cannam@49: cannam@49: Return operator()(Params&&... params) const { cannam@49: return (t.*method)(kj::fwd(params)...); cannam@49: } cannam@49: cannam@49: private: cannam@49: T t; cannam@49: }; cannam@49: cannam@49: } // namespace _ (private) cannam@49: cannam@49: #define KJ_BIND_METHOD(obj, method) \ cannam@49: ::kj::_::BoundMethod::method), \ cannam@49: &::kj::Decay::method>(obj) cannam@49: // Macro that produces a functor object which forwards to the method `obj.name`. If `obj` is an cannam@49: // lvalue, the functor will hold a reference to it. If `obj` is an rvalue, the functor will cannam@49: // contain a copy (by move) of it. cannam@49: // cannam@49: // The current implementation requires that the method is not overloaded. cannam@49: // cannam@49: // TODO(someday): C++14's generic lambdas may be able to simplify this code considerably, and cannam@49: // probably make it work with overloaded methods. cannam@49: cannam@49: #else cannam@49: // Here's a better implementation of the above that doesn't work with GCC (but does with Clang) cannam@49: // because it uses a local class with a template method. Sigh. This implementation supports cannam@49: // overloaded methods. cannam@49: cannam@49: #define KJ_BIND_METHOD(obj, method) \ cannam@49: ({ \ cannam@49: typedef KJ_DECLTYPE_REF(obj) T; \ cannam@49: class F { \ cannam@49: public: \ cannam@49: inline F(T&& t): t(::kj::fwd(t)) {} \ cannam@49: template \ cannam@49: auto operator()(Params&&... params) \ cannam@49: -> decltype(::kj::instance().method(::kj::fwd(params)...)) { \ cannam@49: return t.method(::kj::fwd(params)...); \ cannam@49: } \ cannam@49: private: \ cannam@49: T t; \ cannam@49: }; \ cannam@49: (F(obj)); \ cannam@49: }) cannam@49: // Macro that produces a functor object which forwards to the method `obj.name`. If `obj` is an cannam@49: // lvalue, the functor will hold a reference to it. If `obj` is an rvalue, the functor will cannam@49: // contain a copy (by move) of it. cannam@49: cannam@49: #endif cannam@49: cannam@49: } // namespace kj cannam@49: cannam@49: #endif // KJ_FUNCTION_H_