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