1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef _LIBCPP___UTILITY_CONSTANT_WRAPPER_H
10#define _LIBCPP___UTILITY_CONSTANT_WRAPPER_H
11
12#include <__config>
13#include <__cstddef/size_t.h>
14#include <__functional/invoke.h>
15#include <__type_traits/invoke.h>
16#include <__type_traits/is_constructible.h>
17#include <__type_traits/is_same.h>
18#include <__type_traits/remove_cvref.h>
19#include <__utility/declval.h>
20#include <__utility/forward.h>
21#include <__utility/integer_sequence.h>
22
23#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
24# pragma GCC system_header
25#endif
26
27_LIBCPP_BEGIN_NAMESPACE_STD
28
29#if _LIBCPP_STD_VER >= 26
30
31template <auto _Xp, class = remove_cvref_t<decltype(_Xp)>>
32struct constant_wrapper;
33
34template <class _Tp>
35concept __constexpr_param = requires { typename constant_wrapper<_Tp::value>; };
36
37template <auto _Xp>
38constexpr auto cw = constant_wrapper<_Xp>{};
39
40struct __cw_operators {
41 // unary operators
42 template <__constexpr_param _Tp>
43 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator+(_Tp) noexcept -> constant_wrapper<(+_Tp::value)> {
44 return {};
45 }
46 template <__constexpr_param _Tp>
47 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator-(_Tp) noexcept -> constant_wrapper<(-_Tp::value)> {
48 return {};
49 }
50 template <__constexpr_param _Tp>
51 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator~(_Tp) noexcept -> constant_wrapper<(~_Tp::value)> {
52 return {};
53 }
54 template <__constexpr_param _Tp>
55 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator!(_Tp) noexcept -> constant_wrapper<(!_Tp::value)> {
56 return {};
57 }
58 template <__constexpr_param _Tp>
59 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator&(_Tp) noexcept -> constant_wrapper<(&_Tp::value)> {
60 return {};
61 }
62 template <__constexpr_param _Tp>
63 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator*(_Tp) noexcept -> constant_wrapper<(*_Tp::value)> {
64 return {};
65 }
66
67 // binary operators
68 template <__constexpr_param _Lp, __constexpr_param _Rp>
69 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator+(_Lp, _Rp) noexcept
70 -> constant_wrapper<(_Lp::value + _Rp::value)> {
71 return {};
72 }
73 template <__constexpr_param _Lp, __constexpr_param _Rp>
74 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator-(_Lp, _Rp) noexcept
75 -> constant_wrapper<(_Lp::value - _Rp::value)> {
76 return {};
77 }
78 template <__constexpr_param _Lp, __constexpr_param _Rp>
79 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator*(_Lp, _Rp) noexcept
80 -> constant_wrapper<(_Lp::value * _Rp::value)> {
81 return {};
82 }
83 template <__constexpr_param _Lp, __constexpr_param _Rp>
84 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator/(_Lp, _Rp) noexcept
85 -> constant_wrapper<(_Lp::value / _Rp::value)> {
86 return {};
87 }
88 template <__constexpr_param _Lp, __constexpr_param _Rp>
89 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator%(_Lp, _Rp) noexcept
90 -> constant_wrapper<(_Lp::value % _Rp::value)> {
91 return {};
92 }
93
94 template <__constexpr_param _Lp, __constexpr_param _Rp>
95 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<<(_Lp, _Rp) noexcept
96 -> constant_wrapper<(_Lp::value << _Rp::value)> {
97 return {};
98 }
99 template <__constexpr_param _Lp, __constexpr_param _Rp>
100 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator>>(_Lp, _Rp) noexcept
101 -> constant_wrapper<(_Lp::value >> _Rp::value)> {
102 return {};
103 }
104 template <__constexpr_param _Lp, __constexpr_param _Rp>
105 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator&(_Lp, _Rp) noexcept
106 -> constant_wrapper<(_Lp::value & _Rp::value)> {
107 return {};
108 }
109 template <__constexpr_param _Lp, __constexpr_param _Rp>
110 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator|(_Lp, _Rp) noexcept
111 -> constant_wrapper<(_Lp::value | _Rp::value)> {
112 return {};
113 }
114 template <__constexpr_param _Lp, __constexpr_param _Rp>
115 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator^(_Lp, _Rp) noexcept
116 -> constant_wrapper<(_Lp::value ^ _Rp::value)> {
117 return {};
118 }
119
120 template <__constexpr_param _Lp, __constexpr_param _Rp>
121 requires(!is_constructible_v<bool, decltype(_Lp::value)> || !is_constructible_v<bool, decltype(_Rp::value)>)
122 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator&&(_Lp, _Rp) noexcept
123 -> constant_wrapper<(_Lp::value && _Rp::value)> {
124 return {};
125 }
126 template <__constexpr_param _Lp, __constexpr_param _Rp>
127 requires(!is_constructible_v<bool, decltype(_Lp::value)> || !is_constructible_v<bool, decltype(_Rp::value)>)
128 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator||(_Lp, _Rp) noexcept
129 -> constant_wrapper<(_Lp::value || _Rp::value)> {
130 return {};
131 }
132
133 // comparisons
134 template <__constexpr_param _Lp, __constexpr_param _Rp>
135 _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(_Lp, _Rp) noexcept
136 -> constant_wrapper<(_Lp::value <=> _Rp::value)> {
137 return {};
138 }
139 template <__constexpr_param _Lp, __constexpr_param _Rp>
140 _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<(_Lp, _Rp) noexcept
141 -> constant_wrapper<(_Lp::value < _Rp::value)> {
142 return {};
143 }
144 template <__constexpr_param _Lp, __constexpr_param _Rp>
145 _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=(_Lp, _Rp) noexcept
146 -> constant_wrapper<(_Lp::value <= _Rp::value)> {
147 return {};
148 }
149 template <__constexpr_param _Lp, __constexpr_param _Rp>
150 _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator==(_Lp, _Rp) noexcept
151 -> constant_wrapper<(_Lp::value == _Rp::value)> {
152 return {};
153 }
154 template <__constexpr_param _Lp, __constexpr_param _Rp>
155 _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator!=(_Lp, _Rp) noexcept
156 -> constant_wrapper<(_Lp::value != _Rp::value)> {
157 return {};
158 }
159 template <__constexpr_param _Lp, __constexpr_param _Rp>
160 _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator>(_Lp, _Rp) noexcept
161 -> constant_wrapper<(_Lp::value > _Rp::value)> {
162 return {};
163 }
164 template <__constexpr_param _Lp, __constexpr_param _Rp>
165 _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator>=(_Lp, _Rp) noexcept
166 -> constant_wrapper<(_Lp::value >= _Rp::value)> {
167 return {};
168 }
169
170 template <__constexpr_param _Lp, __constexpr_param _Rp>
171 friend auto operator,(_Lp, _Rp) = delete;
172
173 template <__constexpr_param _Lp, __constexpr_param _Rp>
174 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator->*(_Lp, _Rp) noexcept
175 // TODO: Remove `auto` when all support versions of Clang have https://llvm.org/PR202693 fixed.
176 -> constant_wrapper<auto(_Lp::value->*_Rp::value)> {
177 return {};
178 }
179
180 // pseudo-mutators
181 template <__constexpr_param _Tp>
182 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator++(this _Tp) noexcept -> constant_wrapper<(++_Tp::value)> {
183 return {};
184 }
185 template <__constexpr_param _Tp>
186 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator++(this _Tp, int) noexcept
187 -> constant_wrapper<(_Tp::value++)> {
188 return {};
189 }
190 template <__constexpr_param _Tp>
191 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator--(this _Tp) noexcept -> constant_wrapper<(--_Tp::value)> {
192 return {};
193 }
194 template <__constexpr_param _Tp>
195 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator--(this _Tp, int) noexcept
196 -> constant_wrapper<(_Tp::value--)> {
197 return {};
198 }
199
200 template <__constexpr_param _Tp, __constexpr_param _Rp>
201 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator+=(this _Tp, _Rp) noexcept
202 // TODO: Remove `auto` when all support versions of Clang have https://llvm.org/PR202693 fixed.
203 -> constant_wrapper<auto(_Tp::value += _Rp::value)> {
204 return {};
205 }
206 template <__constexpr_param _Tp, __constexpr_param _Rp>
207 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator-=(this _Tp, _Rp) noexcept
208 // TODO: Remove `auto` when all support versions of Clang have https://llvm.org/PR202693 fixed.
209 -> constant_wrapper<auto(_Tp::value -= _Rp::value)> {
210 return {};
211 }
212 template <__constexpr_param _Tp, __constexpr_param _Rp>
213 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator*=(this _Tp, _Rp) noexcept
214 // TODO: Remove `auto` when all support versions of Clang have https://llvm.org/PR202693 fixed.
215 -> constant_wrapper<auto(_Tp::value *= _Rp::value)> {
216 return {};
217 }
218 template <__constexpr_param _Tp, __constexpr_param _Rp>
219 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator/=(this _Tp, _Rp) noexcept
220 // TODO: Remove `auto` when all support versions of Clang have https://llvm.org/PR202693 fixed.
221 -> constant_wrapper<auto(_Tp::value /= _Rp::value)> {
222 return {};
223 }
224 template <__constexpr_param _Tp, __constexpr_param _Rp>
225 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator%=(this _Tp, _Rp) noexcept
226 // TODO: Remove `auto` when all support versions of Clang have https://llvm.org/PR202693 fixed.
227 -> constant_wrapper<auto(_Tp::value %= _Rp::value)> {
228 return {};
229 }
230 template <__constexpr_param _Tp, __constexpr_param _Rp>
231 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator&=(this _Tp, _Rp) noexcept
232 // TODO: Remove `auto` when all support versions of Clang have https://llvm.org/PR202693 fixed.
233 -> constant_wrapper<auto(_Tp::value &= _Rp::value)> {
234 return {};
235 }
236 template <__constexpr_param _Tp, __constexpr_param _Rp>
237 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator|=(this _Tp, _Rp) noexcept
238 // TODO: Remove `auto` when all support versions of Clang have https://llvm.org/PR202693 fixed.
239 -> constant_wrapper<auto(_Tp::value |= _Rp::value)> {
240 return {};
241 }
242 template <__constexpr_param _Tp, __constexpr_param _Rp>
243 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator^=(this _Tp, _Rp) noexcept
244 // TODO: Remove `auto` when all support versions of Clang have https://llvm.org/PR202693 fixed.
245 -> constant_wrapper<auto(_Tp::value ^= _Rp::value)> {
246 return {};
247 }
248 template <__constexpr_param _Tp, __constexpr_param _Rp>
249 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator<<=(this _Tp, _Rp) noexcept
250 // TODO: Remove `auto` when all support versions of Clang have https://llvm.org/PR202693 fixed.
251 -> constant_wrapper<auto(_Tp::value <<= _Rp::value)> {
252 return {};
253 }
254 template <__constexpr_param _Tp, __constexpr_param _Rp>
255 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator>>=(this _Tp, _Rp) noexcept
256 // TODO: Remove `auto` when all support versions of Clang have https://llvm.org/PR202693 fixed.
257 -> constant_wrapper<auto(_Tp::value >>= _Rp::value)> {
258 return {};
259 }
260};
261
262template <const auto& _Callable, class... _Args>
263concept __constexpr_callable = (__constexpr_param<remove_cvref_t<_Args>> && ...) && requires {
264 typename constant_wrapper<std::invoke(_Callable, remove_cvref_t<_Args>::value...)>;
265};
266
267template <const auto& _Obj, class... _Args>
268concept __constexpr_indexable = (__constexpr_param<remove_cvref_t<_Args>> && ...) && requires {
269 typename constant_wrapper<auto(_Obj[remove_cvref_t<_Args>::value...])>;
270};
271
272template <auto _Xp, class _Tp>
273struct constant_wrapper : __cw_operators {
274 static constexpr decltype((_Xp)) value = (_Xp);
275
276 using type = constant_wrapper;
277 using value_type = decltype(_Xp);
278
279 static_assert(is_same_v<_Tp, value_type>,
280 "the second template parameter of std::constant_wrapper must be its value_type");
281
282 template <__constexpr_param _Rp>
283 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator=(_Rp) const noexcept
284 // TODO: Remove `auto` when all support versions of Clang have https://llvm.org/PR202693 fixed.
285 -> constant_wrapper<auto(value = _Rp::value)> {
286 return {};
287 }
288
289 _LIBCPP_HIDE_FROM_ABI constexpr operator decltype(value)() const noexcept { return value; }
290
291 template <class... _Args>
292 requires __constexpr_callable<value, _Args...>
293 [[nodiscard]]
294 _LIBCPP_HIDE_FROM_ABI static constexpr constant_wrapper<std::invoke(value, remove_cvref_t<_Args>::value...)>
295 operator()(_Args&&...) noexcept {
296 return {};
297 }
298
299 template <class... _Args>
300 requires(!__constexpr_callable<value, _Args...> && is_invocable_v<const value_type&, _Args && ...>)
301 _LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto)
302 operator()(_Args&&... __args) noexcept(noexcept(std::invoke(value, std::forward<_Args>(__args)...))) {
303 return std::invoke(value, std::forward<_Args>(__args)...);
304 }
305
306 template <class... _Args>
307 requires __constexpr_indexable<value, _Args...>
308 [[nodiscard]]
309 _LIBCPP_HIDE_FROM_ABI static constexpr constant_wrapper<auto(value[remove_cvref_t<_Args>::value...])>
310 operator[](_Args&&...) noexcept {
311 return {};
312 }
313
314 template <class... _Args>
315 requires(!__constexpr_indexable<value, _Args...> && requires { value[std::declval<_Args>()...]; })
316 _LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto)
317 operator[](_Args&&... __args) noexcept(noexcept(value[std::forward<_Args>(__args)...])) {
318 return value[std::forward<_Args>(__args)...];
319 }
320};
321
322#endif // _LIBCPP_STD_VER >= 26
323
324_LIBCPP_END_NAMESPACE_STD
325
326#endif // _LIBCPP___UTILITY_CONSTANT_WRAPPER_H
327