1 /* 2 MIT License 3 4 Copyright (c) 2020 Oleg Fatkhiev 5 6 Permission is hereby granted, free of charge, to any person obtaining a copy 7 of this software and associated documentation files (the "Software"), to deal 8 in the Software without restriction, including without limitation the rights 9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 copies of the Software, and to permit persons to whom the Software is 11 furnished to do so, subject to the following conditions: 12 13 The above copyright notice and this permission notice shall be included in all 14 copies or substantial portions of the Software. 15 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 SOFTWARE. 23 */ 24 25 /* Sources fetched from https://github.com/ofats/any_invocable on 2021-02-19. */ 26 27 #ifndef _ANY_INVOKABLE_H_ 28 #define _ANY_INVOKABLE_H_ 29 30 #include <functional> 31 #include <memory> 32 #include <type_traits> 33 34 // clang-format off 35 /* 36 namespace std { 37 template<class Sig> class any_invocable; // never defined 38 39 template<class R, class... ArgTypes> 40 class any_invocable<R(ArgTypes...) cv ref noexcept(noex)> { 41 public: 42 using result_type = R; 43 44 // SECTION.3, construct/copy/destroy 45 any_invocable() noexcept; 46 any_invocable(nullptr_t) noexcept; 47 any_invocable(any_invocable&&) noexcept; 48 template<class F> any_invocable(F&&); 49 50 template<class T, class... Args> 51 explicit any_invocable(in_place_type_t<T>, Args&&...); 52 template<class T, class U, class... Args> 53 explicit any_invocable(in_place_type_t<T>, initializer_list<U>, Args&&...); 54 55 any_invocable& operator=(any_invocable&&) noexcept; 56 any_invocable& operator=(nullptr_t) noexcept; 57 template<class F> any_invocable& operator=(F&&); 58 template<class F> any_invocable& operator=(reference_wrapper<F>) noexcept; 59 60 ~any_invocable(); 61 62 // SECTION.4, any_invocable modifiers 63 void swap(any_invocable&) noexcept; 64 65 // SECTION.5, any_invocable capacity 66 explicit operator bool() const noexcept; 67 68 // SECTION.6, any_invocable invocation 69 R operator()(ArgTypes...) cv ref noexcept(noex); 70 71 // SECTION.7, null pointer comparisons 72 friend bool operator==(const any_invocable&, nullptr_t) noexcept; 73 74 // SECTION.8, specialized algorithms 75 friend void swap(any_invocable&, any_invocable&) noexcept; 76 }; 77 } 78 */ 79 // clang-format on 80 81 namespace ofats { 82 83 namespace any_detail { 84 85 using buffer = std::aligned_storage_t<sizeof(void*) * 2, alignof(void*)>; 86 87 template <class T> 88 inline constexpr bool is_small_object_v = 89 sizeof(T) <= sizeof(buffer) && alignof(buffer) % alignof(T) == 0 && 90 std::is_nothrow_move_constructible_v<T>; 91 92 union storage { 93 void* ptr_ = nullptr; 94 buffer buf_; 95 }; 96 97 enum class action { destroy, move }; 98 99 template <class R, class... ArgTypes> 100 struct handler_traits { 101 template <class Derived> 102 struct handler_base { 103 static void handle(action act, storage* current, storage* other = nullptr) { 104 switch (act) { 105 case (action::destroy): 106 Derived::destroy(*current); 107 break; 108 case (action::move): 109 Derived::move(*current, *other); 110 break; 111 } 112 } 113 }; 114 115 template <class T> 116 struct small_handler : handler_base<small_handler<T>> { 117 template <class... Args> createhandler_traits::small_handler118 static void create(storage& s, Args&&... args) { 119 new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...); 120 } 121 destroyhandler_traits::small_handler122 static void destroy(storage& s) noexcept { 123 T& value = *static_cast<T*>(static_cast<void*>(&s.buf_)); 124 value.~T(); 125 } 126 movehandler_traits::small_handler127 static void move(storage& dst, storage& src) noexcept { 128 create(dst, std::move(*static_cast<T*>(static_cast<void*>(&src.buf_)))); 129 destroy(src); 130 } 131 callhandler_traits::small_handler132 static R call(storage& s, ArgTypes... args) { 133 return std::invoke(*static_cast<T*>(static_cast<void*>(&s.buf_)), 134 std::forward<ArgTypes>(args)...); 135 } 136 }; 137 138 template <class T> 139 struct large_handler : handler_base<large_handler<T>> { 140 template <class... Args> createhandler_traits::large_handler141 static void create(storage& s, Args&&... args) { 142 s.ptr_ = new T(std::forward<Args>(args)...); 143 } 144 destroyhandler_traits::large_handler145 static void destroy(storage& s) noexcept { delete static_cast<T*>(s.ptr_); } 146 movehandler_traits::large_handler147 static void move(storage& dst, storage& src) noexcept { 148 dst.ptr_ = src.ptr_; 149 } 150 callhandler_traits::large_handler151 static R call(storage& s, ArgTypes... args) { 152 return std::invoke(*static_cast<T*>(s.ptr_), 153 std::forward<ArgTypes>(args)...); 154 } 155 }; 156 157 template <class T> 158 using handler = std::conditional_t<is_small_object_v<T>, small_handler<T>, 159 large_handler<T>>; 160 }; 161 162 template <class T> 163 struct is_in_place_type : std::false_type {}; 164 165 template <class T> 166 struct is_in_place_type<std::in_place_type_t<T>> : std::true_type {}; 167 168 template <class T> 169 inline constexpr auto is_in_place_type_v = is_in_place_type<T>::value; 170 171 template <class R, bool is_noexcept, class... ArgTypes> 172 class any_invocable_impl { 173 template <class T> 174 using handler = 175 typename any_detail::handler_traits<R, ArgTypes...>::template handler<T>; 176 177 using storage = any_detail::storage; 178 using action = any_detail::action; 179 using handle_func = void (*)(any_detail::action, any_detail::storage*, 180 any_detail::storage*); 181 using call_func = R (*)(any_detail::storage&, ArgTypes...); 182 183 public: 184 using result_type = R; 185 186 any_invocable_impl() noexcept = default; 187 any_invocable_impl(std::nullptr_t) noexcept {} 188 any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189 if (rhs.handle_) { 190 handle_ = rhs.handle_; 191 handle_(action::move, &storage_, &rhs.storage_); 192 call_ = rhs.call_; 193 rhs.handle_ = nullptr; 194 } 195 } 196 197 any_invocable_impl& operator=(any_invocable_impl&& rhs) noexcept { 198 any_invocable_impl{std::move(rhs)}.swap(*this); 199 return *this; 200 } 201 any_invocable_impl& operator=(std::nullptr_t) noexcept { 202 destroy(); 203 return *this; 204 } 205 206 ~any_invocable_impl() { destroy(); } 207 208 void swap(any_invocable_impl& rhs) noexcept { 209 if (handle_) { 210 if (rhs.handle_) { 211 storage tmp; 212 handle_(action::move, &tmp, &storage_); 213 rhs.handle_(action::move, &storage_, &rhs.storage_); 214 handle_(action::move, &rhs.storage_, &tmp); 215 std::swap(handle_, rhs.handle_); 216 std::swap(call_, rhs.call_); 217 } else { 218 rhs.swap(*this); 219 } 220 } else if (rhs.handle_) { 221 rhs.handle_(action::move, &storage_, &rhs.storage_); 222 handle_ = rhs.handle_; 223 call_ = rhs.call_; 224 rhs.handle_ = nullptr; 225 } 226 } 227 228 explicit operator bool() const noexcept { return handle_ != nullptr; } 229 230 protected: 231 template <class F, class... Args> 232 void create(Args&&... args) { 233 using hdl = handler<F>; 234 hdl::create(storage_, std::forward<Args>(args)...); 235 handle_ = &hdl::handle; 236 call_ = &hdl::call; 237 } 238 239 void destroy() noexcept { 240 if (handle_) { 241 handle_(action::destroy, &storage_, nullptr); 242 handle_ = nullptr; 243 } 244 } 245 246 R call(ArgTypes... args) noexcept(is_noexcept) { 247 return call_(storage_, std::forward<ArgTypes>(args)...); 248 } 249 250 friend bool operator==(const any_invocable_impl& f, std::nullptr_t) noexcept { 251 return !f; 252 } 253 friend bool operator==(std::nullptr_t, const any_invocable_impl& f) noexcept { 254 return !f; 255 } 256 friend bool operator!=(const any_invocable_impl& f, std::nullptr_t) noexcept { 257 return static_cast<bool>(f); 258 } 259 friend bool operator!=(std::nullptr_t, const any_invocable_impl& f) noexcept { 260 return static_cast<bool>(f); 261 } 262 263 friend void swap(any_invocable_impl& lhs, any_invocable_impl& rhs) noexcept { 264 lhs.swap(rhs); 265 } 266 267 private: 268 storage storage_; 269 handle_func handle_ = nullptr; 270 call_func call_; 271 }; 272 273 template <class T> 274 using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>; 275 276 template <class AI, class F, bool noex, class R, class FCall, class... ArgTypes> 277 using can_convert = std::conjunction< 278 std::negation<std::is_same<remove_cvref_t<F>, AI>>, 279 std::negation<any_detail::is_in_place_type<remove_cvref_t<F>>>, 280 std::is_invocable_r<R, FCall, ArgTypes...>, 281 std::bool_constant<(!noex || 282 std::is_nothrow_invocable_r_v<R, FCall, ArgTypes...>)>, 283 std::is_constructible<std::decay_t<F>, F>>; 284 285 } // namespace any_detail 286 287 template <class Signature> 288 class any_invocable; 289 290 #define __OFATS_ANY_INVOCABLE(cv, ref, noex, inv_quals) \ 291 template <class R, class... ArgTypes> \ 292 class any_invocable<R(ArgTypes...) cv ref noexcept(noex)> \ 293 : public any_detail::any_invocable_impl<R, noex, ArgTypes...> { \ 294 using base_type = any_detail::any_invocable_impl<R, noex, ArgTypes...>; \ 295 \ 296 public: \ 297 using base_type::base_type; \ 298 \ 299 template < \ 300 class F, \ 301 class = std::enable_if_t<any_detail::can_convert< \ 302 any_invocable, F, noex, R, F inv_quals, ArgTypes...>::value>> \ 303 any_invocable(F&& f) { \ 304 base_type::template create<std::decay_t<F>>(std::forward<F>(f)); \ 305 } \ 306 \ 307 template <class T, class... Args, class VT = std::decay_t<T>, \ 308 class = std::enable_if_t< \ 309 std::is_move_constructible_v<VT> && \ 310 std::is_constructible_v<VT, Args...> && \ 311 std::is_invocable_r_v<R, VT inv_quals, ArgTypes...> && \ 312 (!noex || std::is_nothrow_invocable_r_v<R, VT inv_quals, \ 313 ArgTypes...>)>> \ 314 explicit any_invocable(std::in_place_type_t<T>, Args&&... args) { \ 315 base_type::template create<VT>(std::forward<Args>(args)...); \ 316 } \ 317 \ 318 template < \ 319 class T, class U, class... Args, class VT = std::decay_t<T>, \ 320 class = std::enable_if_t< \ 321 std::is_move_constructible_v<VT> && \ 322 std::is_constructible_v<VT, std::initializer_list<U>&, Args...> && \ 323 std::is_invocable_r_v<R, VT inv_quals, ArgTypes...> && \ 324 (!noex || \ 325 std::is_nothrow_invocable_r_v<R, VT inv_quals, ArgTypes...>)>> \ 326 explicit any_invocable(std::in_place_type_t<T>, \ 327 std::initializer_list<U> il, Args&&... args) { \ 328 base_type::template create<VT>(il, std::forward<Args>(args)...); \ 329 } \ 330 \ 331 template <class F, class FDec = std::decay_t<F>> \ 332 std::enable_if_t<!std::is_same_v<FDec, any_invocable> && \ 333 std::is_move_constructible_v<FDec>, \ 334 any_invocable&> \ 335 operator=(F&& f) { \ 336 any_invocable{std::forward<F>(f)}.swap(*this); \ 337 return *this; \ 338 } \ 339 template <class F> \ 340 any_invocable& operator=(std::reference_wrapper<F> f) { \ 341 any_invocable{f}.swap(*this); \ 342 return *this; \ 343 } \ 344 \ 345 R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346 return base_type::call(std::forward<ArgTypes>(args)...); \ 347 } \ 348 }; 349 350 // cv -> {`empty`, const} 351 // ref -> {`empty`, &, &&} 352 // noex -> {true, false} 353 // inv_quals -> (is_empty(ref) ? & : ref) 354 __OFATS_ANY_INVOCABLE(, , false, &) // 000 355 __OFATS_ANY_INVOCABLE(, , true, &) // 001 356 __OFATS_ANY_INVOCABLE(, &, false, &) // 010 357 __OFATS_ANY_INVOCABLE(, &, true, &) // 011 358 __OFATS_ANY_INVOCABLE(, &&, false, &&) // 020 359 __OFATS_ANY_INVOCABLE(, &&, true, &&) // 021 360 __OFATS_ANY_INVOCABLE(const, , false, const&) // 100 361 __OFATS_ANY_INVOCABLE(const, , true, const&) // 101 362 __OFATS_ANY_INVOCABLE(const, &, false, const&) // 110 363 __OFATS_ANY_INVOCABLE(const, &, true, const&) // 111 364 __OFATS_ANY_INVOCABLE(const, &&, false, const&&) // 120 365 __OFATS_ANY_INVOCABLE(const, &&, true, const&&) // 121 366 367 #undef __OFATS_ANY_INVOCABLE 368 369 } // namespace ofats 370 371 /* We, uWebSockets define our own type */ 372 namespace uWS { 373 template <class T> 374 using MoveOnlyFunction = ofats::any_invocable<T>; 375 } 376 377 #endif // _ANY_INVOKABLE_H_ 378