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