RLBox
rlbox_stdlib_polyfill.hpp
1 #pragma once
2 
3 // This file is a polyfill for parts of the C++ standard library available only
4 // in newer compilers. Since these are only compile time requirements, we can
5 // just include these as part of the rlbox library in case the target compiler
6 // doesn't support these features. For instance clang-5 which rlbox supports
7 // does not support std::invocable and related functionality in <type_traits>
8 // and is polyfilled here.
9 //
10 // This code was borrowed from clang's standard library - libc++
11 //
12 // Link:
13 // https://github.com/llvm-mirror/libcxx/blob/master/include/type_traits
14 //
15 // libc++ is dual licensed under the MIT license and the UIUC License (a
16 // BSD-like license) and is therefore compatible with our code base
17 
18 // std::invocable and friends
19 
20 namespace rlbox::detail::polyfill {
21 
22 struct __nat
23 {
24  __nat() = delete;
25  __nat(const __nat&) = delete;
26  __nat& operator=(const __nat&) = delete;
27  ~__nat() = delete;
28 };
29 
30 template<bool _Val>
31 using _BoolConstant = std::integral_constant<bool, _Val>;
32 
33 template<class _Tp, class _Up>
34 using _IsNotSame = _BoolConstant<!std::is_same<_Tp, _Up>::value>;
35 
36 #define INVOKE_RETURN(...) \
37  noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) { return __VA_ARGS__; }
38 
39 template<class _Fp, class... _Args>
40 inline auto helper__invoke(_Fp&& __f, _Args&&... __args)
41  INVOKE_RETURN(std::forward<_Fp>(__f)(std::forward<_Args>(__args)...))
42 
43  template<class _Fp, class... _Args>
44  inline constexpr auto helper__invoke_constexpr(_Fp&& __f, _Args&&... __args)
45  INVOKE_RETURN(std::forward<_Fp>(__f)(std::forward<_Args>(__args)...))
46 
47 #undef INVOKE_RETURN
48 
49  // __invokable
50  template<class _Ret, class _Fp, class... _Args>
51  struct __invokable_r
52 {
53  template<class _XFp, class... _XArgs>
54  static auto __try_call(int)
55  -> decltype(helper__invoke(std::declval<_XFp>(),
56  std::declval<_XArgs>()...));
57  template<class _XFp, class... _XArgs>
58  static __nat __try_call(...);
59 
60  // FIXME: Check that _Ret, _Fp, and _Args... are all complete types, cv void,
61  // or incomplete array types as required by the standard.
62  using _Result = decltype(__try_call<_Fp, _Args...>(0));
63 
64  using type = typename std::conditional<
65  _IsNotSame<_Result, __nat>::value,
66  typename std::conditional<std::is_void<_Ret>::value,
67  std::true_type,
68  std::is_convertible<_Result, _Ret>>::type,
69  std::false_type>::type;
70  static const bool value = type::value;
71 };
72 template<class _Fp, class... _Args>
73 using __invokable = __invokable_r<void, _Fp, _Args...>;
74 
75 template<bool _IsInvokable,
76  bool _IsCVVoid,
77  class _Ret,
78  class _Fp,
79  class... _Args>
81 {
82  static const bool value = false;
83 };
84 
85 template<class _Ret, class _Fp, class... _Args>
86 struct __nothrow_invokable_r_imp<true, false, _Ret, _Fp, _Args...>
87 {
89 
90  template<class _Tp>
91  static void __test_noexcept(_Tp) noexcept;
92 
93  static const bool value = noexcept(_ThisT::__test_noexcept<_Ret>(
94  helper__invoke(std::declval<_Fp>(), std::declval<_Args>()...)));
95 };
96 
97 template<class _Ret, class _Fp, class... _Args>
98 struct __nothrow_invokable_r_imp<true, true, _Ret, _Fp, _Args...>
99 {
100  static const bool value =
101  noexcept(helper__invoke(std::declval<_Fp>(), std::declval<_Args>()...));
102 };
103 
104 template<class _Ret, class _Fp, class... _Args>
105 using __nothrow_invokable_r =
106  __nothrow_invokable_r_imp<__invokable_r<_Ret, _Fp, _Args...>::value,
107  std::is_void<_Ret>::value,
108  _Ret,
109  _Fp,
110  _Args...>;
111 
112 template<class _Fp, class... _Args>
113 using __nothrow_invokable =
114  __nothrow_invokable_r_imp<__invokable<_Fp, _Args...>::value,
115  true,
116  void,
117  _Fp,
118  _Args...>;
119 
120 template<class _Fp, class... _Args>
122  : public std::enable_if<__invokable<_Fp, _Args...>::value,
123  typename __invokable_r<void, _Fp, _Args...>::_Result>
124 {};
125 
126 // invoke_result
127 
128 template<class _Fn, class... _Args>
129 struct invoke_result : helper__invoke_of<_Fn, _Args...>
130 {};
131 
132 template<class _Fn, class... _Args>
133 using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
134 
135 // is_invocable
136 
137 template<class _Fn, class... _Args>
139  : std::integral_constant<bool, __invokable<_Fn, _Args...>::value>
140 {};
141 
142 template<class _Ret, class _Fn, class... _Args>
144  : std::integral_constant<bool, __invokable_r<_Ret, _Fn, _Args...>::value>
145 {};
146 
147 template<class _Fn, class... _Args>
148 inline constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value;
149 
150 template<class _Ret, class _Fn, class... _Args>
151 inline constexpr bool is_invocable_r_v =
152  is_invocable_r<_Ret, _Fn, _Args...>::value;
153 
154 // is_nothrow_invocable
155 
156 template<class _Fn, class... _Args>
158  : std::integral_constant<bool, __nothrow_invokable<_Fn, _Args...>::value>
159 {};
160 
161 template<class _Ret, class _Fn, class... _Args>
163  : std::integral_constant<bool,
164  __nothrow_invokable_r<_Ret, _Fn, _Args...>::value>
165 {};
166 
167 template<class _Fn, class... _Args>
168 inline constexpr bool is_nothrow_invocable_v =
169  is_nothrow_invocable<_Fn, _Args...>::value;
170 
171 template<class _Ret, class _Fn, class... _Args>
172 inline constexpr bool is_nothrow_invocable_r_v =
173  is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value;
174 
175 }
Definition: rlbox_stdlib_polyfill.hpp:23
Definition: rlbox_stdlib_polyfill.hpp:81
Definition: rlbox_stdlib_polyfill.hpp:124
Definition: rlbox_stdlib_polyfill.hpp:130
Definition: rlbox_stdlib_polyfill.hpp:145
Definition: rlbox_stdlib_polyfill.hpp:140
Definition: rlbox_stdlib_polyfill.hpp:165
Definition: rlbox_stdlib_polyfill.hpp:159