annotate 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
rev   line source
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