annotate osx/include/kj/function.h @ 83:ae30d91d2ffe

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