1 /*
2  *  Copyright (c) 2016, Facebook, Inc.
3  *  All rights reserved.
4  *
5  *  This source code is licensed under the BSD-style license found in the
6  *  LICENSE file in the root directory of this source tree. An additional grant
7  *  of patent rights can be found in the PATENTS file in the same directory.
8  */
9 
10 #ifndef FATAL_INCLUDE_fatal_type_call_traits_h
11 #define FATAL_INCLUDE_fatal_type_call_traits_h
12 
13 #include <fatal/preprocessor.h>
14 #include <fatal/type/apply.h>
15 #include <fatal/type/sequence.h>
16 
17 #include <utility>
18 
19 namespace fatal {
20 namespace detail {
21 namespace call_traits_impl {
22 
23 template <typename T> T arg();
24 
25 template <bool> struct call_if;
26 
27 } // namespace call_traits_impl {
28 } // namespace detail {
29 
30 /**
31  * TODO: DOCUMENT AND TEST
32  *
33  * @author: Marcelo Juchem <marcelo@fb.com>
34  */
35 struct ctor_call_traits {
36   template <typename T>
37   struct automatic {
38     using type = T;
39 
automaticctor_call_traits::automatic40     constexpr inline automatic() {}
41 
42     template <typename... UArgs>
constructctor_call_traits::automatic43     constexpr static inline T construct(UArgs &&...args) {
44       return T(std::forward<UArgs>(args)...);
45     }
46 
47     template <typename... UArgs>
operatorctor_call_traits::automatic48     constexpr T inline operator ()(UArgs &&...args) const {
49       return construct(std::forward<UArgs>(args)...);
50     }
51   };
52 
53   template <typename T>
54   struct dynamic {
55     using type = T;
56 
dynamicctor_call_traits::dynamic57     constexpr inline dynamic() {}
58 
59     template <typename... UArgs>
constructctor_call_traits::dynamic60     constexpr static inline T *construct(UArgs &&...args) {
61       return new T(std::forward<UArgs>(args)...);
62     }
63 
64     template <typename... UArgs>
operatorctor_call_traits::dynamic65     constexpr inline T *operator ()(UArgs &&...args) const {
66       return construct(std::forward<UArgs>(args)...);
67     }
68   };
69 
70   template <typename T>
71   struct placement {
72     using type = T;
73 
placementctor_call_traits::placement74     constexpr inline placement() {}
75 
76     template <typename... UArgs>
constructctor_call_traits::placement77     constexpr static T *construct(T *pointer, UArgs &&...args) {
78       return new (pointer) T(std::forward<UArgs>(args)...);
79     }
80 
81     template <typename... UArgs>
operatorctor_call_traits::placement82     constexpr inline T *operator ()(T *pointer, UArgs &&...args) const {
83       return construct(pointer, std::forward<UArgs>(args)...);
84     }
85   };
86 };
87 
88 /**
89  * TODO: DOCUMENT AND TEST
90  *
91  * @author: Marcelo Juchem <marcelo@fb.com>
92  */
93 class call_operator_traits {
94   template <typename... Args>
95   struct is_impl {
96     template <
97       typename T,
98       typename = decltype(
99         detail::call_traits_impl::arg<T>()(
100           detail::call_traits_impl::arg<Args>()...
101         )
102       )
103     >
104     static std::true_type sfinae(T *);
105 
106     template <typename...>
107     static std::false_type sfinae(...);
108   };
109 
110 public:
call_operator_traits()111   constexpr call_operator_traits() {}
112 
113   template <typename T, typename... UArgs>
114   static constexpr inline auto call(T &&subject, UArgs &&...args)
115     noexcept(noexcept(subject(std::forward<UArgs>(args)...)))
116     -> decltype(subject(std::forward<UArgs>(args)...))
117   { return subject(std::forward<UArgs>(args)...); }
118 
119   template <typename T, typename... UArgs>
120   constexpr inline auto operator ()(T &&subject, UArgs &&...args) const
121     noexcept(
122       noexcept(call(std::forward<T>(subject), std::forward<UArgs>(args)...))
123     )
124     -> decltype(call(std::forward<T>(subject), std::forward<UArgs>(args)...))
125   { return call(std::forward<T>(subject), std::forward<UArgs>(args)...); }
126 
127   /**
128    * TODO: DOCUMENT
129    *
130    * Example:
131    *
132    *  struct Foo {
133    *    void operator ()() {}
134    *    void operator ()(int i, std::string s) {}
135    *  };
136    *
137    *  auto const lambda_is = [](int, std::string) {};
138    *  using lambda = decltype(lambda_is);
139    *
140    *  cout << std::boolalpha
141    *    << call_operator_traits::supports<Foo>::value
142    *    << ' ' << std::boolalpha
143    *    << call_operator_traits::supports<Foo, int>::value
144    *    << ' ' << std::boolalpha
145    *    << call_operator_traits::supports<Foo, int, double>::value
146    *    << ' ' << std::boolalpha
147    *    << call_operator_traits::supports<Foo, int, std::string>::value
148    *    << std::endl
149    *    << ' ' << std::boolalpha
150    *    << call_operator_traits::supports<lambda>::value
151    *    << ' ' << std::boolalpha
152    *    << call_operator_traits::supports<lambda, int>::value
153    *    << ' ' << std::boolalpha
154    *    << call_operator_traits::supports<lambda, int, double>::value
155    *    << ' ' << std::boolalpha
156    *    << call_operator_traits::supports<lambda, int, std::string>::value;
157    *
158    * Outputs:
159    *  true false false true
160    *  false false false true
161    *
162    * @author: Marcelo Juchem <marcelo@fb.com>
163    */
164   template <typename T, typename... Args>
165   using supports = decltype(
166     is_impl<Args...>::template sfinae(static_cast<T *>(nullptr))
167   );
168 };
169 
170 /**
171  * TODO: DOCUMENT AND TEST
172  *
173  * @author: Marcelo Juchem <marcelo@fb.com>
174  */
175 #define FATAL_CALL_TRAITS(Name, ...) \
176   FATAL_IMPL_CALL_TRAITS( \
177     Name, \
178     FATAL_UID(FATAL_CAT(Name, _call_traits_impl)), \
179     __VA_ARGS__ \
180   )
181 #define FATAL_IMPL_CALL_TRAITS(Name, Impl, ...) \
182   class Impl { \
183     template <typename... UArgs> \
184     struct member_fn_supports_impl { \
185       template < \
186         typename U, \
187         typename = decltype( \
188           ::fatal::detail::call_traits_impl::arg<U>().__VA_ARGS__( \
189             ::fatal::detail::call_traits_impl::arg<UArgs>()... \
190           ) \
191         ) \
192       > \
193       static ::std::true_type sfinae(U *); \
194       \
195       template <typename...> \
196       static ::std::false_type sfinae(...); \
197     }; \
198     \
199     template <typename... UArgs> \
200     struct static_member_supports_impl { \
201       template < \
202         typename U, \
203         typename = decltype( \
204           U::__VA_ARGS__( \
205             ::fatal::detail::call_traits_impl::arg<UArgs>()... \
206           ) \
207         ) \
208       > \
209       static ::std::true_type sfinae(U *); \
210       \
211       template <typename...> \
212       static ::std::false_type sfinae(...); \
213     }; \
214     \
215     FATAL_S(name_str, FATAL_TO_STR(__VA_ARGS__)); \
216     \
217   public: \
218     using name = name_str; \
219     \
220     struct member_function { \
221       using name = name_str; \
222       \
223       constexpr member_function() {} \
224       \
225       template <typename U> \
226       struct bind { \
227         template <typename... UArgs> \
228         using supports = decltype( \
229           member_fn_supports_impl<UArgs...>::template sfinae( \
230             static_cast<typename ::std::remove_reference<U>::type *>(nullptr) \
231           ) \
232         ); \
233       }; \
234       \
235       template <typename U, typename... UArgs> \
236       using supports = typename bind<U>::template supports<UArgs...>; \
237       \
238       template <typename U, typename... UArgs> \
239       using result = decltype( \
240         ::std::declval<U>().__VA_ARGS__(::std::declval<UArgs>()...) \
241       ); \
242       \
243       template <typename U, typename... UArgs> \
244       static constexpr inline auto call(U &&subject, UArgs &&...args) \
245         -> decltype( \
246           ::std::forward<U>(subject).__VA_ARGS__( \
247             ::std::forward<UArgs>(args)... \
248           ) \
249         ) \
250       { \
251         return ::std::forward<U>(subject).__VA_ARGS__( \
252           ::std::forward<UArgs>(args)... \
253         ); \
254       } \
255       \
256       template <typename U, typename... UArgs> \
257       constexpr inline auto operator ()(U &&subject, UArgs &&...args) const \
258         -> decltype( \
259           call(::std::forward<U>(subject), ::std::forward<UArgs>(args)...) \
260         ) \
261       { \
262         return call( \
263           ::std::forward<U>(subject), \
264           ::std::forward<UArgs>(args)... \
265         ); \
266       } \
267     }; \
268     \
269     struct static_member { \
270       using name = name_str; \
271       \
272       template <typename U> \
273       class bind { \
274         template <typename V, typename... UArgs> \
275         static constexpr inline auto call_impl(UArgs &&...args) \
276           -> decltype(V::__VA_ARGS__(::std::forward<UArgs>(args)...)) \
277         { return V::__VA_ARGS__(::std::forward<UArgs>(args)...); } \
278         \
279       public: \
280         constexpr inline bind() {} \
281         \
282         using type = U; \
283         \
284         template <typename... UArgs> \
285         using supports = decltype( \
286           static_member_supports_impl<UArgs...>::sfinae( \
287             static_cast<U *>(nullptr) \
288           ) \
289         ); \
290         \
291         template <typename... UArgs> \
292         using result = decltype(call_impl<type>(::std::declval<UArgs>()...)); \
293         \
294         template <typename... UArgs> \
295         static constexpr inline auto call(UArgs &&...args) \
296           -> decltype(call_impl<type>(::std::forward<UArgs>(args)...)) \
297         { return call_impl<type>(::std::forward<UArgs>(args)...); } \
298         \
299         template <typename... UArgs> \
300         constexpr inline auto operator ()(UArgs &&...args) const \
301           -> decltype(call_impl<type>(::std::forward<UArgs>(args)...)) \
302         { return call_impl<type>(::std::forward<UArgs>(args)...); } \
303       }; \
304       \
305       template <typename U, typename... UArgs> \
306       static constexpr inline auto call(UArgs &&...args) \
307         -> decltype(bind<U>::call(::std::forward<UArgs>(args)...)) \
308       { return bind<U>::call(::std::forward<UArgs>(args)...); } \
309       \
310       template <typename U, typename... UArgs> \
311       using supports = typename bind<U>::template supports<UArgs...>; \
312       \
313       template <typename U, typename... UArgs> \
314       using result = typename bind<U>::template result<UArgs...>; \
315     }; \
316   }; \
317   \
318   using Name = Impl
319 
320 /**
321  * Some pre-instantiated call traits for common function names.
322  *
323  * @author: Marcelo Juchem <marcelo@fb.com>
324  */
325 struct call_traits {
326 # define FATAL_CALL_TRAITS_IMPL(Name) FATAL_CALL_TRAITS(Name, Name)
327 
328   FATAL_CALL_TRAITS_IMPL(abort);
329   FATAL_CALL_TRAITS_IMPL(absolute);
330   FATAL_CALL_TRAITS_IMPL(add);
331   FATAL_CALL_TRAITS_IMPL(advance);
332   FATAL_CALL_TRAITS_IMPL(append);
333   FATAL_CALL_TRAITS_IMPL(append_to);
334   FATAL_CALL_TRAITS_IMPL(apply);
335   FATAL_CALL_TRAITS_IMPL(args);
336   FATAL_CALL_TRAITS_IMPL(argument);
337   FATAL_CALL_TRAITS_IMPL(arguments);
338   FATAL_CALL_TRAITS_IMPL(assign);
339   FATAL_CALL_TRAITS_IMPL(at);
340   FATAL_CALL_TRAITS_IMPL(back);
341   FATAL_CALL_TRAITS_IMPL(begin);
342   FATAL_CALL_TRAITS_IMPL(binary_search);
343   FATAL_CALL_TRAITS_IMPL(bind);
344   FATAL_CALL_TRAITS_IMPL(bootstrap);
345   FATAL_CALL_TRAITS_IMPL(byte);
346   FATAL_CALL_TRAITS_IMPL(bytes);
347   FATAL_CALL_TRAITS_IMPL(c_str);
348   FATAL_CALL_TRAITS_IMPL(call);
349   FATAL_CALL_TRAITS_IMPL(cancel);
350   FATAL_CALL_TRAITS_IMPL(capacity);
351   FATAL_CALL_TRAITS_IMPL(cbegin);
352   FATAL_CALL_TRAITS_IMPL(cend);
353   FATAL_CALL_TRAITS_IMPL(center);
354   FATAL_CALL_TRAITS_IMPL(check);
355   FATAL_CALL_TRAITS_IMPL(child);
356   FATAL_CALL_TRAITS_IMPL(children);
357   FATAL_CALL_TRAITS_IMPL(clean);
358   FATAL_CALL_TRAITS_IMPL(clean_up);
359   FATAL_CALL_TRAITS_IMPL(cleanup);
360   FATAL_CALL_TRAITS_IMPL(clear);
361   FATAL_CALL_TRAITS_IMPL(clone);
362   FATAL_CALL_TRAITS_IMPL(compare);
363   FATAL_CALL_TRAITS_IMPL(compress);
364   FATAL_CALL_TRAITS_IMPL(concat);
365   FATAL_CALL_TRAITS_IMPL(concatenate);
366   FATAL_CALL_TRAITS_IMPL(condition);
367   FATAL_CALL_TRAITS_IMPL(config);
368   FATAL_CALL_TRAITS_IMPL(configuration);
369   FATAL_CALL_TRAITS_IMPL(configure);
370   FATAL_CALL_TRAITS_IMPL(construct);
371   FATAL_CALL_TRAITS_IMPL(contains);
372   FATAL_CALL_TRAITS_IMPL(convert);
373   FATAL_CALL_TRAITS_IMPL(copy);
374   FATAL_CALL_TRAITS_IMPL(count);
375   FATAL_CALL_TRAITS_IMPL(cptr);
376   FATAL_CALL_TRAITS_IMPL(crbegin);
377   FATAL_CALL_TRAITS_IMPL(cref);
378   FATAL_CALL_TRAITS_IMPL(crend);
379   FATAL_CALL_TRAITS_IMPL(data);
380   FATAL_CALL_TRAITS_IMPL(decode);
381   FATAL_CALL_TRAITS_IMPL(dequeue);
382   FATAL_CALL_TRAITS_IMPL(descriptor);
383   FATAL_CALL_TRAITS_IMPL(deserialize);
384   FATAL_CALL_TRAITS_IMPL(destroy);
385   FATAL_CALL_TRAITS_IMPL(emplace);
386   FATAL_CALL_TRAITS_IMPL(emplace_back);
387   FATAL_CALL_TRAITS_IMPL(emplace_front);
388   FATAL_CALL_TRAITS_IMPL(empty);
389   FATAL_CALL_TRAITS_IMPL(encode);
390   FATAL_CALL_TRAITS_IMPL(end);
391   FATAL_CALL_TRAITS_IMPL(enqueue);
392   FATAL_CALL_TRAITS_IMPL(equal);
393   FATAL_CALL_TRAITS_IMPL(equal_range);
394   FATAL_CALL_TRAITS_IMPL(erase);
395   FATAL_CALL_TRAITS_IMPL(exact);
396   FATAL_CALL_TRAITS_IMPL(exception);
397   FATAL_CALL_TRAITS_IMPL(exit);
398   FATAL_CALL_TRAITS_IMPL(extension);
399   FATAL_CALL_TRAITS_IMPL(find);
400   FATAL_CALL_TRAITS_IMPL(find_first_not_of);
401   FATAL_CALL_TRAITS_IMPL(find_first_of);
402   FATAL_CALL_TRAITS_IMPL(find_last_not_of);
403   FATAL_CALL_TRAITS_IMPL(find_last_of);
404   FATAL_CALL_TRAITS_IMPL(finish);
405   FATAL_CALL_TRAITS_IMPL(finished);
406   FATAL_CALL_TRAITS_IMPL(first);
407   FATAL_CALL_TRAITS_IMPL(for_each);
408   FATAL_CALL_TRAITS_IMPL(foreach);
409   FATAL_CALL_TRAITS_IMPL(foreach_if);
410   FATAL_CALL_TRAITS_IMPL(fork);
411   FATAL_CALL_TRAITS_IMPL(forward);
412   FATAL_CALL_TRAITS_IMPL(fourth);
413   FATAL_CALL_TRAITS_IMPL(freeze);
414   FATAL_CALL_TRAITS_IMPL(from);
415   FATAL_CALL_TRAITS_IMPL(front);
416   FATAL_CALL_TRAITS_IMPL(get);
417   FATAL_CALL_TRAITS_IMPL(get_pointer);
418   FATAL_CALL_TRAITS_IMPL(get_reference);
419   FATAL_CALL_TRAITS_IMPL(getline);
420   FATAL_CALL_TRAITS_IMPL(go);
421   FATAL_CALL_TRAITS_IMPL(halt);
422   FATAL_CALL_TRAITS_IMPL(hash);
423   FATAL_CALL_TRAITS_IMPL(id);
424   FATAL_CALL_TRAITS_IMPL(index);
425   FATAL_CALL_TRAITS_IMPL(index_of);
426   FATAL_CALL_TRAITS_IMPL(info);
427   FATAL_CALL_TRAITS_IMPL(init);
428   FATAL_CALL_TRAITS_IMPL(initialize);
429   FATAL_CALL_TRAITS_IMPL(inject);
430   FATAL_CALL_TRAITS_IMPL(inner);
431   FATAL_CALL_TRAITS_IMPL(insert);
432   FATAL_CALL_TRAITS_IMPL(join);
433   FATAL_CALL_TRAITS_IMPL(joinable);
434   FATAL_CALL_TRAITS_IMPL(kind);
435   FATAL_CALL_TRAITS_IMPL(last);
436   FATAL_CALL_TRAITS_IMPL(left);
437   FATAL_CALL_TRAITS_IMPL(length);
438   FATAL_CALL_TRAITS_IMPL(lift);
439   FATAL_CALL_TRAITS_IMPL(limit);
440   FATAL_CALL_TRAITS_IMPL(list);
441   FATAL_CALL_TRAITS_IMPL(lock);
442   FATAL_CALL_TRAITS_IMPL(longest);
443   FATAL_CALL_TRAITS_IMPL(loop);
444   FATAL_CALL_TRAITS_IMPL(lower_bound);
445   FATAL_CALL_TRAITS_IMPL(map);
446   FATAL_CALL_TRAITS_IMPL(match);
447   FATAL_CALL_TRAITS_IMPL(max);
448   FATAL_CALL_TRAITS_IMPL(max_size);
449   FATAL_CALL_TRAITS_IMPL(mean);
450   FATAL_CALL_TRAITS_IMPL(median);
451   FATAL_CALL_TRAITS_IMPL(merge);
452   FATAL_CALL_TRAITS_IMPL(mid);
453   FATAL_CALL_TRAITS_IMPL(middle);
454   FATAL_CALL_TRAITS_IMPL(mimic);
455   FATAL_CALL_TRAITS_IMPL(min);
456   FATAL_CALL_TRAITS_IMPL(move);
457   FATAL_CALL_TRAITS_IMPL(multi_append);
458   FATAL_CALL_TRAITS_IMPL(name);
459   FATAL_CALL_TRAITS_IMPL(next);
460   FATAL_CALL_TRAITS_IMPL(next_as);
461   FATAL_CALL_TRAITS_IMPL(nth_element);
462   FATAL_CALL_TRAITS_IMPL(observe);
463   FATAL_CALL_TRAITS_IMPL(off);
464   FATAL_CALL_TRAITS_IMPL(offset);
465   FATAL_CALL_TRAITS_IMPL(on);
466   FATAL_CALL_TRAITS_IMPL(outer);
467   FATAL_CALL_TRAITS_IMPL(owner);
468   FATAL_CALL_TRAITS_IMPL(parameter);
469   FATAL_CALL_TRAITS_IMPL(parameters);
470   FATAL_CALL_TRAITS_IMPL(partial);
471   FATAL_CALL_TRAITS_IMPL(partial_sort);
472   FATAL_CALL_TRAITS_IMPL(partition);
473   FATAL_CALL_TRAITS_IMPL(pause);
474   FATAL_CALL_TRAITS_IMPL(payload);
475   FATAL_CALL_TRAITS_IMPL(pending);
476   FATAL_CALL_TRAITS_IMPL(piece);
477   FATAL_CALL_TRAITS_IMPL(pieces);
478   FATAL_CALL_TRAITS_IMPL(pinpoint);
479   FATAL_CALL_TRAITS_IMPL(pointer);
480   FATAL_CALL_TRAITS_IMPL(poll);
481   FATAL_CALL_TRAITS_IMPL(pop);
482   FATAL_CALL_TRAITS_IMPL(pop_back);
483   FATAL_CALL_TRAITS_IMPL(pop_front);
484   FATAL_CALL_TRAITS_IMPL(predicate);
485   FATAL_CALL_TRAITS_IMPL(prefix);
486   FATAL_CALL_TRAITS_IMPL(prefixes);
487   FATAL_CALL_TRAITS_IMPL(prev);
488   FATAL_CALL_TRAITS_IMPL(previous);
489   FATAL_CALL_TRAITS_IMPL(properties);
490   FATAL_CALL_TRAITS_IMPL(property);
491   FATAL_CALL_TRAITS_IMPL(ptr);
492   FATAL_CALL_TRAITS_IMPL(push);
493   FATAL_CALL_TRAITS_IMPL(push_back);
494   FATAL_CALL_TRAITS_IMPL(push_front);
495   FATAL_CALL_TRAITS_IMPL(put);
496   FATAL_CALL_TRAITS_IMPL(queue);
497   FATAL_CALL_TRAITS_IMPL(quit);
498   FATAL_CALL_TRAITS_IMPL(rbegin);
499   FATAL_CALL_TRAITS_IMPL(read);
500   FATAL_CALL_TRAITS_IMPL(ref);
501   FATAL_CALL_TRAITS_IMPL(reference);
502   FATAL_CALL_TRAITS_IMPL(rehash);
503   FATAL_CALL_TRAITS_IMPL(relative);
504   FATAL_CALL_TRAITS_IMPL(release);
505   FATAL_CALL_TRAITS_IMPL(remove);
506   FATAL_CALL_TRAITS_IMPL(rend);
507   FATAL_CALL_TRAITS_IMPL(replace);
508   FATAL_CALL_TRAITS_IMPL(reserve);
509   FATAL_CALL_TRAITS_IMPL(reset);
510   FATAL_CALL_TRAITS_IMPL(resize);
511   FATAL_CALL_TRAITS_IMPL(resume);
512   FATAL_CALL_TRAITS_IMPL(reverse);
513   FATAL_CALL_TRAITS_IMPL(rfind);
514   FATAL_CALL_TRAITS_IMPL(right);
515   FATAL_CALL_TRAITS_IMPL(rng);
516   FATAL_CALL_TRAITS_IMPL(rotate);
517   FATAL_CALL_TRAITS_IMPL(run);
518   FATAL_CALL_TRAITS_IMPL(search);
519   FATAL_CALL_TRAITS_IMPL(second);
520   FATAL_CALL_TRAITS_IMPL(seek);
521   FATAL_CALL_TRAITS_IMPL(select);
522   FATAL_CALL_TRAITS_IMPL(serialize);
523   FATAL_CALL_TRAITS_IMPL(set);
524   FATAL_CALL_TRAITS_IMPL(setup);
525   FATAL_CALL_TRAITS_IMPL(shortest);
526   FATAL_CALL_TRAITS_IMPL(shrink_to_fit);
527   FATAL_CALL_TRAITS_IMPL(shuffle);
528   FATAL_CALL_TRAITS_IMPL(shutdown);
529   FATAL_CALL_TRAITS_IMPL(signature);
530   FATAL_CALL_TRAITS_IMPL(size);
531   FATAL_CALL_TRAITS_IMPL(slice);
532   FATAL_CALL_TRAITS_IMPL(sort);
533   FATAL_CALL_TRAITS_IMPL(source);
534   FATAL_CALL_TRAITS_IMPL(spawn);
535   FATAL_CALL_TRAITS_IMPL(split);
536   FATAL_CALL_TRAITS_IMPL(split_step);
537   FATAL_CALL_TRAITS_IMPL(stable_sort);
538   FATAL_CALL_TRAITS_IMPL(stack);
539   FATAL_CALL_TRAITS_IMPL(standard_deviation);
540   FATAL_CALL_TRAITS_IMPL(start);
541   FATAL_CALL_TRAITS_IMPL(stddev);
542   FATAL_CALL_TRAITS_IMPL(steal);
543   FATAL_CALL_TRAITS_IMPL(stop);
544   FATAL_CALL_TRAITS_IMPL(str);
545   FATAL_CALL_TRAITS_IMPL(string);
546   FATAL_CALL_TRAITS_IMPL(substr);
547   FATAL_CALL_TRAITS_IMPL(suspend);
548   FATAL_CALL_TRAITS_IMPL(swap);
549   FATAL_CALL_TRAITS_IMPL(thaw);
550   FATAL_CALL_TRAITS_IMPL(third);
551   FATAL_CALL_TRAITS_IMPL(to);
552   FATAL_CALL_TRAITS_IMPL(to_str);
553   FATAL_CALL_TRAITS_IMPL(to_string);
554   FATAL_CALL_TRAITS_IMPL(to_wstring);
555   FATAL_CALL_TRAITS_IMPL(transcode);
556   FATAL_CALL_TRAITS_IMPL(transform);
557   FATAL_CALL_TRAITS_IMPL(try_emplace);
558   FATAL_CALL_TRAITS_IMPL(try_get);
559   FATAL_CALL_TRAITS_IMPL(try_lock);
560   FATAL_CALL_TRAITS_IMPL(try_set);
561   FATAL_CALL_TRAITS_IMPL(try_to);
562   FATAL_CALL_TRAITS_IMPL(turn);
563   FATAL_CALL_TRAITS_IMPL(type);
564   FATAL_CALL_TRAITS_IMPL(unique);
565   FATAL_CALL_TRAITS_IMPL(unlock);
566   FATAL_CALL_TRAITS_IMPL(update);
567   FATAL_CALL_TRAITS_IMPL(upper_bound);
568   FATAL_CALL_TRAITS_IMPL(value);
569   FATAL_CALL_TRAITS_IMPL(variance);
570   FATAL_CALL_TRAITS_IMPL(visit);
571   FATAL_CALL_TRAITS_IMPL(visit_if);
572   FATAL_CALL_TRAITS_IMPL(which);
573   FATAL_CALL_TRAITS_IMPL(with);
574   FATAL_CALL_TRAITS_IMPL(write);
575 
576 # undef FATAL_CALL_TRAITS_IMPL
577 };
578 
579 /**
580  * TODO: DOCUMENT
581  *
582  * @author: Marcelo Juchem <marcelo@fb.com>
583  */
584 #define FATAL_FREE_FUNCTION_CALL_TRAITS(Name, ...) \
585   FATAL_IMPL_FREE_FUNCTION_CALL_TRAITS( \
586     Name, \
587     FATAL_UID(FATAL_CAT(Name, _free_fn_call_traits_impl)), \
588     __VA_ARGS__ \
589   )
590 
591 #define FATAL_IMPL_FREE_FUNCTION_CALL_TRAITS(Name, Impl, ...) \
592   struct Impl { \
593     FATAL_S(name, FATAL_TO_STR(__VA_ARGS__)); \
594     \
595     constexpr inline Impl() {} \
596     \
597     template <typename... UArgs> \
598     static constexpr inline auto call(UArgs &&...args) \
599       -> decltype(__VA_ARGS__(::std::forward<UArgs>(args)...)) \
600     { return __VA_ARGS__(::std::forward<UArgs>(args)...); } \
601     \
602     template <typename... UArgs> \
603     constexpr inline auto operator ()(UArgs &&...args) const \
604       -> decltype(call(::std::forward<UArgs>(args)...)) \
605     { return call(::std::forward<UArgs>(args)...); } \
606   }; \
607   \
608   using Name = Impl
609 
610 /**
611  * Conditionally calls a function according to the given predicate.
612  *
613  * The provided call traits is used to decide which function to call, perfectly
614  * forwarding the given parameters to it.
615  *
616  * When the predicate evaluates to false, `Fallback` is instantiated and its
617  * call operator is called, perfectly forwarding the parameters to it.
618  *
619  * An optional list of template parameters `Args` can also be passed to the
620  * function.
621  *
622  * The predicate is a type template. It receives the optional list of template
623  * parameters and the types of the arguments given to `call_if`, and must
624  * evaluate to a type similar to `std::integral_constant` of type `bool`.
625  * In other words, `Predicate<Args..., UArgs...>::value` is used to decide
626  * whether to call the function, through the call traits, or the fallback.
627  *
628  * Default predicate calls the function if it exists and supported the given
629  * parameters, otherwise it calls the fallback.
630  *
631  * Example:
632  *
633  *  struct fallback {
634  *    template <typename... Args>
635  *    int operator ()(Args &&...) { return 98765; }
636  *  };
637  *
638  *  struct foo {
639  *    template <typename T>
640  *    T bar() { return T(12345); }
641  *
642  *    double bar(char const *, bool) { return 5.6; }
643  *
644  *    std::string baz(std::size_t n = 1) { return std::string(n, 'x'); }
645  *
646  *    template <typename... Args>
647  *    std::size_t baz(char const *s) {
648  *      return std::strlen(s) + sizeof...(Args);
649  *    }
650  *  };
651  *
652  *  FATAL_CALL_TRAITS(bar_traits, bar);
653  *  using member_fn = bar_traits::member_function;
654  *
655  *  template <typename T, typename... Args>
656  *  using member_pred = member_fn::supports<T, Args...>;
657  *
658  *  foo f;
659  *
660  *  // yields `12345` as an `int`
661  *  auto result1 = call_if<member_fn, fallback, member_pred>(f);
662  *
663  *  // yields `12345` as a `double`
664  *  auto result2 = call_if<member_fn, fallback, member_pred, double>(f);
665  *
666  *  // yields `98765`
667  *  auto result3 = call_if<member_fn, fallback, member_pred>(
668  *    f, "hello", "world", 143
669  *  );
670  *
671  *  // yields `5.6`
672  *  auto result4 = call_if<member_fn, fallback, member_pred>(f, "test", true);
673  *
674  *  // yields `98765`
675  *  auto result5 = call_if<member_fn, fallback, member_pred>(f, 10);
676  *
677  *  FATAL_CALL_TRAITS(baz_traits, baz);
678  *  using static_fn = baz_traits::static_member::bind<foo>;
679  *
680  *  template <typename... Args>
681  *  using static_pred = static_fn::supports<Args...>;
682  *
683  *  // yields `"xxxxx"`
684  *  auto result6 = call_if<static_fn, fallback, static_pred>(5);
685  *
686  *  // yields `"x"`
687  *  auto result7 = call_if<static_fn, fallback, static_pred>();
688  *
689  *  // yields `98765`
690  *  auto result8 = call_if<static_fn, fallback, static_pred>("hello", "world");
691  *
692  *  // yields `4`
693  *  auto result9 = call_if<static_fn, fallback, static_pred>("test");
694  *
695  *  // yields `6`
696  *  auto result10 = call_if<static_fn, fallback, static_pred, void, bool>(
697  *    "test"
698  *  );
699  *
700  * @author: Marcelo Juchem <marcelo@fb.com>
701  */
702 template <
703   typename CallTraits,
704   typename Fallback,
705   template <typename...> class Predicate,
706   typename... Args,
707   typename... UArgs
708 >
709 constexpr inline auto call_if(UArgs &&...args)
710   -> decltype(
711     detail::call_traits_impl::call_if<
712       apply_args<Predicate, Args..., UArgs...>::value
713     >::template call<CallTraits, Fallback, Args...>(
714       std::forward<UArgs>(args)...
715     )
716   )
717 {
718   return detail::call_traits_impl::call_if<
719     apply_args<Predicate, Args..., UArgs...>::value
720   >::template call<CallTraits, Fallback, Args...>(
721     std::forward<UArgs>(args)...
722   );
723 }
724 
725 /**
726  * Convenient specialization of `call_if` that calls a function if it exists
727  * and the desired overload is supported, or calls the fallback otherwise.
728  *
729  * The provided call traits is used to decide which function to call, perfectly
730  * forwarding the given parameters to it.
731  *
732  * An optional list of template parameters `Args` can also be passed to the
733  * function.
734  *
735  * Example:
736  *
737  *  struct fallback {
738  *    template <typename... Args>
739  *    int operator ()(Args &&...) { return 98765; }
740  *  };
741  *
742  *  struct foo {
743  *    template <typename T>
744  *    T bar() { return T(12345); }
745  *
746  *    double bar(char const *, bool) { return 5.6; }
747  *
748  *    std::string baz(std::size_t n = 1) { return std::string(n, 'x'); }
749  *
750  *    template <typename... Args>
751  *    std::size_t baz(char const *s) {
752  *      return std::strlen(s) + sizeof...(Args);
753  *    }
754  *  };
755  *
756  *  FATAL_CALL_TRAITS(bar_traits, bar);
757  *  using member_fn = bar_traits::member_function;
758  *
759  *  foo f;
760  *
761  *  // yields `12345` as an `int`
762  *  auto result1 = call_if_supported<member_fn, fallback>(f);
763  *
764  *  // yields `12345` as a `double`
765  *  auto result2 = call_if_supported<member_fn, fallback, double>(f);
766  *
767  *  // yields `98765`
768  *  auto result3 = call_if_supported<member_fn, fallback>(
769  *    f, "hello", "world", 143
770  *  );
771  *
772  *  // yields `5.6`
773  *  auto result4 = call_if_supported<member_fn, fallback>(f, "test", true);
774  *
775  *  // yields `98765`
776  *  auto result5 = call_if_supported<member_fn, fallback>(f, 10);
777  *
778  *  FATAL_CALL_TRAITS(baz_traits, baz);
779  *  using static_fn = baz_traits::static_member::bind<foo>;
780  *
781  *  // yields `"xxxxx"`
782  *  auto result6 = call_if_supported<static_fn, fallback>(5);
783  *
784  *  // yields `"x"`
785  *  auto result7 = call_if_supported<static_fn, fallback>();
786  *
787  *  // yields `98765`
788  *  auto result8 = call_if_supported<static_fn, fallback>("hello", "world");
789  *
790  *  // yields `4`
791  *  auto result9 = call_if_supported<static_fn, fallback>("test");
792  *
793  *  // yields `6`
794  *  auto result10 = call_if_supported<static_fn, fallback, void, bool>("test");
795  *
796  * @author: Marcelo Juchem <marcelo@fb.com>
797  */
798 template <
799   typename CallTraits, typename Fallback, typename... Args, typename... UArgs
800 >
801 constexpr inline auto call_if_supported(UArgs &&...args)
802   -> decltype(
803     call_if<CallTraits, Fallback, CallTraits::template supports, Args...>(
804       std::forward<UArgs>(args)...
805     )
806   )
807 {
808   return call_if<CallTraits, Fallback, CallTraits::template supports, Args...>(
809     std::forward<UArgs>(args)...
810   );
811 }
812 
813 ////////////////////////////
814 // IMPLEMENTATION DETAILS //
815 ////////////////////////////
816 
817 namespace detail {
818 namespace call_traits_impl {
819 
820 template <bool>
821 struct call_if {
822   template <typename Traits, typename, typename... Args, typename... UArgs>
823   static constexpr inline auto call(UArgs &&...args)
824     -> decltype(Traits::template call<Args...>(std::forward<UArgs>(args)...))
825   {
826     return Traits::template call<Args...>(std::forward<UArgs>(args)...);
827   }
828 };
829 
830 template <>
831 struct call_if<false> {
832   template <typename, typename Fn, typename... Args, typename... UArgs>
833   static constexpr inline auto call(UArgs &&...args)
834     -> decltype(Fn()(std::forward<UArgs>(args)...))
835   {
836     return Fn()(std::forward<UArgs>(args)...);
837   }
838 };
839 
840 } // namespace call_traits_impl {
841 } // namespace detail {
842 } // namespace fatal {
843 
844 #endif // FATAL_INCLUDE_fatal_type_call_traits_h
845