1 // Copyright (C) 2020-2023 Free Software Foundation, Inc.
2 //
3 // This file is part of the GNU ISO C++ Library. This library is free
4 // software; you can redistribute it and/or modify it under the
5 // terms of the GNU General Public License as published by the
6 // Free Software Foundation; either version 3, or (at your option)
7 // any later version.
8 //
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this library; see the file COPYING3. If not see
16 // <http://www.gnu.org/licenses/>.
17
18 #ifndef VC_TESTS_METAHELPERS_H_
19 #define VC_TESTS_METAHELPERS_H_
20
21 #include <functional>
22 #include <type_traits>
23 #include <utility>
24
25 namespace vir
26 {
27 namespace test
28 {
29 template <class A, class B, class Op>
30 constexpr bool
31 operator_is_substitution_failure_impl(float)
32 { return true; }
33
34 template <class A, class B, class Op>
35 constexpr typename std::conditional<true, bool, decltype(
36 Op()(std::declval<A>(), std::declval<B>()))>::type
37 operator_is_substitution_failure_impl(int)
38 { return false; }
39
40 template <class... Ts>
41 constexpr bool
42 operator_is_substitution_failure()
43 { return operator_is_substitution_failure_impl<Ts...>(int()); }
44
45 template <class... Args, class F>
46 constexpr auto
47 sfinae_is_callable_impl(int, F &&f) -> typename std::conditional<
48 true, std::true_type,
49 decltype(std::forward<F>(f)(std::declval<Args>()...))>::type;
50
51 template <class... Args, class F>
52 constexpr std::false_type
53 sfinae_is_callable_impl(float, const F &);
54
55 template <class... Args, class F>
56 constexpr bool
57 sfinae_is_callable(F &&)
58 {
59 return decltype(
60 sfinae_is_callable_impl<Args...>(int(), std::declval<F>()))::value;
61 }
62
63 template <class... Args, class F>
64 constexpr auto sfinae_is_callable_t(F &&f)
65 -> decltype(sfinae_is_callable_impl<Args...>(int(), std::declval<F>()));
66
67 template <class A, class B>
68 constexpr bool
69 has_less_bits()
70 { return std::__digits_v<A> < std::__digits_v<B>; }
71
72 } // namespace test
73 } // namespace vir
74
75 struct assignment
76 {
77 template <class A, class B>
78 constexpr decltype(std::declval<A>() = std::declval<B>())
79 operator()(A &&a, B &&b) const noexcept(noexcept(
80 std::forward<A>(a) = std::forward<B>(b)))
81 { return std::forward<A>(a) = std::forward<B>(b); }
82 };
83
84 struct bit_shift_left
85 {
86 template <class A, class B>
87 constexpr decltype(std::declval<A>() << std::declval<B>())
88 operator()(A &&a, B &&b) const noexcept(noexcept(
89 std::forward<A>(a) << std::forward<B>(b)))
90 { return std::forward<A>(a) << std::forward<B>(b); }
91 };
92
93 struct bit_shift_right
94 {
95 template <class A, class B>
96 constexpr decltype(std::declval<A>() >> std::declval<B>())
97 operator()(A &&a, B &&b) const noexcept(noexcept(
98 std::forward<A>(a) >> std::forward<B>(b)))
99 { return std::forward<A>(a) >> std::forward<B>(b); }
100 };
101
102 struct assign_modulus
103 {
104 template <class A, class B>
105 constexpr decltype(std::declval<A>() %= std::declval<B>())
106 operator()(A &&a, B &&b) const noexcept(noexcept(
107 std::forward<A>(a) %= std::forward<B>(b)))
108 { return std::forward<A>(a) %= std::forward<B>(b); }
109 };
110
111 struct assign_bit_and
112 {
113 template <class A, class B>
114 constexpr decltype(std::declval<A>() &= std::declval<B>())
115 operator()(A &&a, B &&b) const noexcept(noexcept(
116 std::forward<A>(a) &= std::forward<B>(b)))
117 { return std::forward<A>(a) &= std::forward<B>(b); }
118 };
119
120 struct assign_bit_or
121 {
122 template <class A, class B>
123 constexpr decltype(std::declval<A>() |= std::declval<B>())
124 operator()(A &&a, B &&b) const noexcept(noexcept(
125 std::forward<A>(a) |= std::forward<B>(b)))
126 { return std::forward<A>(a) |= std::forward<B>(b); }
127 };
128
129 struct assign_bit_xor
130 {
131 template <class A, class B>
132 constexpr decltype(std::declval<A>() ^= std::declval<B>())
133 operator()(A &&a, B &&b) const noexcept(noexcept(
134 std::forward<A>(a) ^= std::forward<B>(b)))
135 { return std::forward<A>(a) ^= std::forward<B>(b); }
136 };
137
138 struct assign_bit_shift_left
139 {
140 template <class A, class B>
141 constexpr decltype(std::declval<A>() <<= std::declval<B>())
142 operator()(A &&a, B &&b) const noexcept(noexcept(
143 std::forward<A>(a) <<= std::forward<B>(b)))
144 { return std::forward<A>(a) <<= std::forward<B>(b); }
145 };
146
147 struct assign_bit_shift_right
148 {
149 template <class A, class B>
150 constexpr decltype(std::declval<A>() >>= std::declval<B>())
151 operator()(A &&a, B &&b) const noexcept(noexcept(
152 std::forward<A>(a) >>= std::forward<B>(b)))
153 { return std::forward<A>(a) >>= std::forward<B>(b); }
154 };
155
156 template <class A, class B, class Op = std::plus<>>
157 constexpr bool is_substitution_failure
158 = vir::test::operator_is_substitution_failure<A, B, Op>();
159
160 using vir::test::sfinae_is_callable;
161
162 using vir::test::has_less_bits;
163
164 #endif // VC_TESTS_METAHELPERS_H_