summaryrefslogtreecommitdiffstats
path: root/third_party/rlbox/include/rlbox_stdlib_polyfill.hpp
blob: cf9c0117d0c8bc68a712dcf4ac121bd132a2aef7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#pragma once

// This file is a polyfill for parts of the C++ standard library available only
// in newer compilers. Since these are only compile time requirements, we can
// just include these as part of the rlbox library in case the target compiler
// doesn't support these features. For instance clang-5 which rlbox supports
// does not support std::invocable and related functionality in <type_traits>
// and is polyfilled here.
//
// This code was borrowed from clang's standard library - libc++
//
// Link:
// https://github.com/llvm-mirror/libcxx/blob/master/include/type_traits
//
// libc++ is dual licensed under the MIT license and the UIUC License (a
// BSD-like license) and is therefore compatible with our code base

// std::invocable and friends

namespace rlbox::detail::polyfill {

struct __nat
{
  __nat() = delete;
  __nat(const __nat&) = delete;
  __nat& operator=(const __nat&) = delete;
  ~__nat() = delete;
};

template<bool _Val>
using _BoolConstant = std::integral_constant<bool, _Val>;

template<class _Tp, class _Up>
using _IsNotSame = _BoolConstant<!std::is_same<_Tp, _Up>::value>;

#define INVOKE_RETURN(...)                                                     \
  noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) { return __VA_ARGS__; }

template<class _Fp, class... _Args>
inline auto helper__invoke(_Fp&& __f, _Args&&... __args)
  INVOKE_RETURN(std::forward<_Fp>(__f)(std::forward<_Args>(__args)...))

    template<class _Fp, class... _Args>
    inline constexpr auto helper__invoke_constexpr(_Fp&& __f, _Args&&... __args)
      INVOKE_RETURN(std::forward<_Fp>(__f)(std::forward<_Args>(__args)...))

#undef INVOKE_RETURN

  // __invokable
  template<class _Ret, class _Fp, class... _Args>
  struct __invokable_r
{
  template<class _XFp, class... _XArgs>
  static auto __try_call(int)
    -> decltype(helper__invoke(std::declval<_XFp>(),
                               std::declval<_XArgs>()...));
  template<class _XFp, class... _XArgs>
  static __nat __try_call(...);

  // FIXME: Check that _Ret, _Fp, and _Args... are all complete types, cv void,
  // or incomplete array types as required by the standard.
  using _Result = decltype(__try_call<_Fp, _Args...>(0));

  using type = typename std::conditional<
    _IsNotSame<_Result, __nat>::value,
    typename std::conditional<std::is_void<_Ret>::value,
                              std::true_type,
                              std::is_convertible<_Result, _Ret>>::type,
    std::false_type>::type;
  static const bool value = type::value;
};
template<class _Fp, class... _Args>
using __invokable = __invokable_r<void, _Fp, _Args...>;

template<bool _IsInvokable,
         bool _IsCVVoid,
         class _Ret,
         class _Fp,
         class... _Args>
struct __nothrow_invokable_r_imp
{
  static const bool value = false;
};

template<class _Ret, class _Fp, class... _Args>
struct __nothrow_invokable_r_imp<true, false, _Ret, _Fp, _Args...>
{
  typedef __nothrow_invokable_r_imp _ThisT;

  template<class _Tp>
  static void __test_noexcept(_Tp) noexcept;

  static const bool value = noexcept(_ThisT::__test_noexcept<_Ret>(
    helper__invoke(std::declval<_Fp>(), std::declval<_Args>()...)));
};

template<class _Ret, class _Fp, class... _Args>
struct __nothrow_invokable_r_imp<true, true, _Ret, _Fp, _Args...>
{
  static const bool value =
    noexcept(helper__invoke(std::declval<_Fp>(), std::declval<_Args>()...));
};

template<class _Ret, class _Fp, class... _Args>
using __nothrow_invokable_r =
  __nothrow_invokable_r_imp<__invokable_r<_Ret, _Fp, _Args...>::value,
                            std::is_void<_Ret>::value,
                            _Ret,
                            _Fp,
                            _Args...>;

template<class _Fp, class... _Args>
using __nothrow_invokable =
  __nothrow_invokable_r_imp<__invokable<_Fp, _Args...>::value,
                            true,
                            void,
                            _Fp,
                            _Args...>;

template<class _Fp, class... _Args>
struct helper__invoke_of
  : public std::enable_if<__invokable<_Fp, _Args...>::value,
                          typename __invokable_r<void, _Fp, _Args...>::_Result>
{};

// invoke_result

template<class _Fn, class... _Args>
struct invoke_result : helper__invoke_of<_Fn, _Args...>
{};

template<class _Fn, class... _Args>
using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;

// is_invocable

template<class _Fn, class... _Args>
struct is_invocable
  : std::integral_constant<bool, __invokable<_Fn, _Args...>::value>
{};

template<class _Ret, class _Fn, class... _Args>
struct is_invocable_r
  : std::integral_constant<bool, __invokable_r<_Ret, _Fn, _Args...>::value>
{};

template<class _Fn, class... _Args>
inline constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value;

template<class _Ret, class _Fn, class... _Args>
inline constexpr bool is_invocable_r_v =
  is_invocable_r<_Ret, _Fn, _Args...>::value;

// is_nothrow_invocable

template<class _Fn, class... _Args>
struct is_nothrow_invocable
  : std::integral_constant<bool, __nothrow_invokable<_Fn, _Args...>::value>
{};

template<class _Ret, class _Fn, class... _Args>
struct is_nothrow_invocable_r
  : std::integral_constant<bool,
                           __nothrow_invokable_r<_Ret, _Fn, _Args...>::value>
{};

template<class _Fn, class... _Args>
inline constexpr bool is_nothrow_invocable_v =
  is_nothrow_invocable<_Fn, _Args...>::value;

template<class _Ret, class _Fn, class... _Args>
inline constexpr bool is_nothrow_invocable_r_v =
  is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value;

}