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