blob: 11dbe43eb257f36c2cda82fbc46357e1c2eef735 [file] [log] [blame]
Patrick Williams5b5d15b2022-08-23 09:35:15 -05001/*
2 * Copyright (c) 2021-2022 NVIDIA Corporation
3 *
4 * Licensed under the Apache License Version 2.0 with LLVM Exceptions
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * https://llvm.org/LICENSE.txt
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#pragma once
17
Patrick Williams5e7ef082023-01-05 11:08:53 -060018#if __cpp_concepts < 201907L
19#error This library requires support for C++20 concepts
20#endif
21
Patrick Williams5b5d15b2022-08-23 09:35:15 -050022#include <version>
23
Patrick Williams5e7ef082023-01-05 11:08:53 -060024// Perhaps the stdlib lacks support for concepts though:
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060025#if __has_include(<concepts>) && __cpp_lib_concepts >= 202002
26#define STDEXEC_HAS_STD_CONCEPTS_HEADER() 1
27#else
28#define STDEXEC_HAS_STD_CONCEPTS_HEADER() 0
29#endif
30
31#if STDEXEC_HAS_STD_CONCEPTS_HEADER()
Patrick Williams5b5d15b2022-08-23 09:35:15 -050032#include <concepts>
Patrick Williams5b5d15b2022-08-23 09:35:15 -050033#else
34#include <type_traits>
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060035#endif
Patrick Williams5b5d15b2022-08-23 09:35:15 -050036
Patrick Williamse61c6792023-03-29 10:28:22 -050037#include "__detail/__meta.hpp"
38
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060039namespace stdexec::__std_concepts
Patrick Williams5b5d15b2022-08-23 09:35:15 -050040{
Patrick Williams5b5d15b2022-08-23 09:35:15 -050041#if defined(__clang__)
Patrick Williamse61c6792023-03-29 10:28:22 -050042template <class _Ap, class _Bp>
43concept __same_as = __is_same(_Ap, _Bp);
Patrick Williams5b5d15b2022-08-23 09:35:15 -050044#elif defined(__GNUC__)
Patrick Williamse61c6792023-03-29 10:28:22 -050045template <class _Ap, class _Bp>
46concept __same_as = __is_same_as(_Ap, _Bp);
Patrick Williams5b5d15b2022-08-23 09:35:15 -050047#else
Patrick Williamse61c6792023-03-29 10:28:22 -050048template <class _Ap, class _Bp>
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060049inline constexpr bool __same_as = false;
Patrick Williamse61c6792023-03-29 10:28:22 -050050template <class _Ap>
51inline constexpr bool __same_as<_Ap, _Ap> = true;
Patrick Williams5b5d15b2022-08-23 09:35:15 -050052#endif
53
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060054// Make sure we're using a same_as concept that doesn't instantiate std::is_same
Patrick Williamse61c6792023-03-29 10:28:22 -050055template <class _Ap, class _Bp>
56concept same_as = __same_as<_Ap, _Bp> && __same_as<_Bp, _Ap>;
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060057
58#if STDEXEC_HAS_STD_CONCEPTS_HEADER()
59
60using std::convertible_to;
61using std::derived_from;
62using std::equality_comparable;
63using std::integral;
64
65#else
66
Patrick Williams5b5d15b2022-08-23 09:35:15 -050067template <class T>
68concept integral = std::is_integral_v<T>;
69
Patrick Williamse61c6792023-03-29 10:28:22 -050070template <class _Ap, class _Bp>
71concept derived_from = //
72 std::is_base_of_v<_Bp, _Ap> && //
73 std::is_convertible_v<const volatile _Ap*, const volatile _Bp*>;
Patrick Williams5b5d15b2022-08-23 09:35:15 -050074
75template <class _From, class _To>
Patrick Williamse61c6792023-03-29 10:28:22 -050076concept convertible_to = //
77 std::is_convertible_v<_From, _To> && //
Patrick Williams5b5d15b2022-08-23 09:35:15 -050078 requires(_From (&__fun)()) { static_cast<_To>(__fun()); };
79
Patrick Williamse61c6792023-03-29 10:28:22 -050080template <class _Ty>
81concept equality_comparable = //
82 requires(__cref_t<_Ty> __t) {
83 {
84 __t == __t
Patrick Williamsd2149042023-05-10 07:50:13 -050085 } -> convertible_to<bool>;
Patrick Williamse61c6792023-03-29 10:28:22 -050086 {
87 __t != __t
Patrick Williamsd2149042023-05-10 07:50:13 -050088 } -> convertible_to<bool>;
Patrick Williamse61c6792023-03-29 10:28:22 -050089 };
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060090#endif
91} // namespace stdexec::__std_concepts
Patrick Williams5b5d15b2022-08-23 09:35:15 -050092
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060093namespace stdexec
94{
95using namespace __std_concepts;
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060096
Patrick Williamse61c6792023-03-29 10:28:22 -050097#if __has_builtin(__decay)
98template <class _Ty>
99using __decay_t = __decay(_Ty);
100#elif STDEXEC_NVHPC()
101template <class _Ty>
102using __decay_t = std::decay_t<_Ty>;
103#else
104namespace __tt
105{
106struct __decay_object
107{
108 template <class _Ty>
109 static _Ty __g(const _Ty&);
110 template <class _Ty>
111 using __f = decltype(__g(__declval<_Ty>()));
112};
Patrick Williamsabbdd6a2023-01-20 10:12:50 -0600113
Patrick Williamse61c6792023-03-29 10:28:22 -0500114struct __decay_default
115{
116 template <class _Ty>
117 static _Ty __g(_Ty);
118 template <class _Ty>
119 using __f = decltype(__g(__declval<_Ty>()));
120};
Patrick Williamsabbdd6a2023-01-20 10:12:50 -0600121
Patrick Williamse61c6792023-03-29 10:28:22 -0500122struct __decay_abominable
123{
124 template <class _Ty>
125 using __f = _Ty;
126};
127
128struct __decay_void
129{
130 template <class _Ty>
131 using __f = void;
132};
133
134template <class _Ty>
135extern __decay_object __mdecay;
136
137template <class _Ty, class... Us>
138extern __decay_default __mdecay<_Ty(Us...)>;
139
140template <class _Ty, class... Us>
141extern __decay_default __mdecay<_Ty(Us...) noexcept>;
142
143template <class _Ty, class... Us>
144extern __decay_default __mdecay<_Ty (&)(Us...)>;
145
146template <class _Ty, class... Us>
147extern __decay_default __mdecay<_Ty (&)(Us...) noexcept>;
148
149template <class _Ty, class... Us>
150extern __decay_abominable __mdecay<_Ty(Us...) const>;
151
152template <class _Ty, class... Us>
153extern __decay_abominable __mdecay<_Ty(Us...) const noexcept>;
154
155template <class _Ty, class... Us>
156extern __decay_abominable __mdecay<_Ty(Us...) const&>;
157
158template <class _Ty, class... Us>
159extern __decay_abominable __mdecay<_Ty(Us...) const & noexcept>;
160
161template <class _Ty, class... Us>
162extern __decay_abominable __mdecay<_Ty(Us...) const&&>;
163
164template <class _Ty, class... Us>
165extern __decay_abominable __mdecay<_Ty(Us...) const && noexcept>;
166
167template <class _Ty>
168extern __decay_default __mdecay<_Ty[]>;
169
170template <class _Ty, std::size_t N>
171extern __decay_default __mdecay<_Ty[N]>;
172
173template <class _Ty, std::size_t N>
174extern __decay_default __mdecay<_Ty (&)[N]>;
175
176template <>
177inline __decay_void __mdecay<void>;
178
179template <>
180inline __decay_void __mdecay<const void>;
181} // namespace __tt
182
183template <class _Ty>
184using __decay_t = typename decltype(__tt::__mdecay<_Ty>)::template __f<_Ty>;
185#endif
Patrick Williamsabbdd6a2023-01-20 10:12:50 -0600186
187// C++20 concepts
Patrick Williamse61c6792023-03-29 10:28:22 -0500188template <class _Ty, class _Up>
189concept __decays_to = __same_as<__decay_t<_Ty>, _Up>;
190
191template <class _Ty, class _Up>
Patrick Williamsd2149042023-05-10 07:50:13 -0500192concept __not_decays_to = !__decays_to<_Ty, _Up>;
Patrick Williamse61c6792023-03-29 10:28:22 -0500193
194template <bool _TrueOrFalse>
195concept __satisfies = _TrueOrFalse;
Patrick Williamsabbdd6a2023-01-20 10:12:50 -0600196
197template <class...>
198concept __true = true;
199
Patrick Williamse61c6792023-03-29 10:28:22 -0500200template <class _Cp>
201concept __class = __true<int _Cp::*> && (!__same_as<const _Cp, _Cp>);
Patrick Williamsabbdd6a2023-01-20 10:12:50 -0600202
Patrick Williamse61c6792023-03-29 10:28:22 -0500203template <class _Ty, class... _As>
204concept __one_of = (__same_as<_Ty, _As> || ...);
Patrick Williamsabbdd6a2023-01-20 10:12:50 -0600205
Patrick Williamse61c6792023-03-29 10:28:22 -0500206template <class _Ty, class... _Us>
207concept __all_of = (__same_as<_Ty, _Us> && ...);
Patrick Williamsabbdd6a2023-01-20 10:12:50 -0600208
Patrick Williamse61c6792023-03-29 10:28:22 -0500209template <class _Ty, class... _Us>
Patrick Williamsd2149042023-05-10 07:50:13 -0500210concept __none_of = ((!__same_as<_Ty, _Us>)&&...);
Patrick Williamsabbdd6a2023-01-20 10:12:50 -0600211
212// Not exactly right, but close.
Patrick Williamse61c6792023-03-29 10:28:22 -0500213template <class _Ty>
214concept __boolean_testable_ = convertible_to<_Ty, bool>;
215
216template <class _Ty>
217inline constexpr bool __is_lvalue_reference_ = false;
218template <class _Ty>
219inline constexpr bool __is_lvalue_reference_<_Ty&> = true;
Patrick Williamsabbdd6a2023-01-20 10:12:50 -0600220
221// Avoid using libstdc++'s object concepts because they instantiate a
222// lot of templates.
223template <class _Ty>
Patrick Williamse61c6792023-03-29 10:28:22 -0500224inline constexpr bool __destructible_ = //
Patrick Williamsabbdd6a2023-01-20 10:12:50 -0600225 requires {
226 {
227 ((_Ty && (*)() noexcept) nullptr)().~_Ty()
228 } noexcept;
229 };
230template <class _Ty>
231inline constexpr bool __destructible_<_Ty&> = true;
232template <class _Ty>
233inline constexpr bool __destructible_<_Ty&&> = true;
Patrick Williamse61c6792023-03-29 10:28:22 -0500234template <class _Ty, std::size_t _Np>
235inline constexpr bool __destructible_<_Ty[_Np]> = __destructible_<_Ty>;
Patrick Williamsabbdd6a2023-01-20 10:12:50 -0600236
237template <class T>
238concept destructible = __destructible_<T>;
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500239
240#if __has_builtin(__is_constructible)
Patrick Williamse61c6792023-03-29 10:28:22 -0500241template <class _Ty, class... _As>
242concept constructible_from = //
243 destructible<_Ty> && //
244 __is_constructible(_Ty, _As...);
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500245#else
Patrick Williamse61c6792023-03-29 10:28:22 -0500246template <class _Ty, class... _As>
247concept constructible_from = //
248 destructible<_Ty> && //
249 is_constructible_v<_Ty, _As...>;
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500250#endif
251
Patrick Williamse61c6792023-03-29 10:28:22 -0500252template <class _Ty>
253concept default_initializable = //
254 constructible_from<_Ty> && //
255 requires { _Ty{}; } && //
256 requires { ::new _Ty; };
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500257
Patrick Williamse61c6792023-03-29 10:28:22 -0500258template <class _Ty>
259concept move_constructible = //
260 constructible_from<_Ty, _Ty>;
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500261
Patrick Williamse61c6792023-03-29 10:28:22 -0500262template <class _Ty>
263concept copy_constructible = //
264 move_constructible<_Ty> //
265 && constructible_from<_Ty, const _Ty&>;
266
267template <class _LHS, class _RHS>
268concept assignable_from = //
269 __is_lvalue_reference_<_LHS> && //
270 // std::common_reference_with<
271 // const std::remove_reference_t<_LHS>&,
272 // const std::remove_reference_t<_RHS>&> &&
273 requires(_LHS __lhs, _RHS&& __rhs) {
274 {
Patrick Williamsd2149042023-05-10 07:50:13 -0500275 __lhs = ((_RHS&&)__rhs)
276 } -> same_as<_LHS>;
Patrick Williamse61c6792023-03-29 10:28:22 -0500277 };
278
279namespace __swap
280{
281using std::swap;
282
283template <class _Ty, class _Uy>
284concept swappable_with = //
Patrick Williamsd2149042023-05-10 07:50:13 -0500285 requires(_Ty&& __t, _Uy&& __u) { swap((_Ty&&)__t, (_Uy&&)__u); };
Patrick Williamse61c6792023-03-29 10:28:22 -0500286
287inline constexpr const auto __fn = //
288 []<class _Ty, swappable_with<_Ty> _Uy>(_Ty&& __t, _Uy&& __u) noexcept(
Patrick Williamsd2149042023-05-10 07:50:13 -0500289 noexcept(swap((_Ty&&)__t, (_Uy&&)__u))) {
290 swap((_Ty&&)__t, (_Uy&&)__u);
291};
Patrick Williamse61c6792023-03-29 10:28:22 -0500292} // namespace __swap
293
294using __swap::swappable_with;
295inline constexpr const auto& swap = __swap::__fn;
296
297template <class _Ty>
298concept swappable = //
299 swappable_with<_Ty, _Ty>;
300
301template <class _Ty>
302concept movable = //
303 std::is_object_v<_Ty> && //
304 move_constructible<_Ty> && //
305 assignable_from<_Ty&, _Ty> && //
306 swappable<_Ty>;
307
308template <class _Ty>
309concept copyable = //
310 copy_constructible<_Ty> && //
311 movable<_Ty> && //
312 assignable_from<_Ty&, _Ty&> && //
313 assignable_from<_Ty&, const _Ty&> && //
314 assignable_from<_Ty&, const _Ty>;
315
316template <class _Ty>
317concept semiregular = //
318 copyable<_Ty> && //
319 default_initializable<_Ty>;
320
321template <class _Ty>
322concept regular = //
323 semiregular<_Ty> && //
324 equality_comparable<_Ty>;
325
326template <class T, class U>
327concept __partially_ordered_with = //
328 requires(__cref_t<T> t, __cref_t<U> u) {
329 {
330 t < u
Patrick Williamsd2149042023-05-10 07:50:13 -0500331 } -> __boolean_testable_;
Patrick Williamse61c6792023-03-29 10:28:22 -0500332 {
333 t > u
Patrick Williamsd2149042023-05-10 07:50:13 -0500334 } -> __boolean_testable_;
Patrick Williamse61c6792023-03-29 10:28:22 -0500335 {
336 t <= u
Patrick Williamsd2149042023-05-10 07:50:13 -0500337 } -> __boolean_testable_;
Patrick Williamse61c6792023-03-29 10:28:22 -0500338 {
339 t >= u
Patrick Williamsd2149042023-05-10 07:50:13 -0500340 } -> __boolean_testable_;
Patrick Williamse61c6792023-03-29 10:28:22 -0500341 {
342 u < t
Patrick Williamsd2149042023-05-10 07:50:13 -0500343 } -> __boolean_testable_;
Patrick Williamse61c6792023-03-29 10:28:22 -0500344 {
345 u > t
Patrick Williamsd2149042023-05-10 07:50:13 -0500346 } -> __boolean_testable_;
Patrick Williamse61c6792023-03-29 10:28:22 -0500347 {
348 u <= t
Patrick Williamsd2149042023-05-10 07:50:13 -0500349 } -> __boolean_testable_;
Patrick Williamse61c6792023-03-29 10:28:22 -0500350 {
351 u >= t
Patrick Williamsd2149042023-05-10 07:50:13 -0500352 } -> __boolean_testable_;
Patrick Williamse61c6792023-03-29 10:28:22 -0500353 };
354
355template <class _Ty>
356concept totally_ordered = //
357 equality_comparable<_Ty> && //
358 __partially_ordered_with<_Ty, _Ty>;
359
360template <class _Ty>
361concept __movable_value = //
362 move_constructible<__decay_t<_Ty>> && //
363 constructible_from<__decay_t<_Ty>, _Ty>;
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500364
365template <class _Trait>
366concept __is_true = _Trait::value;
367
368template <class, template <class...> class>
369constexpr bool __is_instance_of_ = false;
Patrick Williamse61c6792023-03-29 10:28:22 -0500370template <class... _As, template <class...> class _Ty>
371constexpr bool __is_instance_of_<_Ty<_As...>, _Ty> = true;
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500372
Patrick Williamse61c6792023-03-29 10:28:22 -0500373template <class _Ay, template <class...> class _Ty>
374concept __is_instance_of = __is_instance_of_<_Ay, _Ty>;
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500375
Patrick Williamse61c6792023-03-29 10:28:22 -0500376template <class _Ay, template <class...> class _Ty>
Patrick Williamsd2149042023-05-10 07:50:13 -0500377concept __is_not_instance_of = !__is_instance_of<_Ay, _Ty>;
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500378
379#if __has_builtin(__is_nothrow_constructible)
Patrick Williamse61c6792023-03-29 10:28:22 -0500380template <class _Ty, class... _As>
381concept __nothrow_constructible_from = constructible_from<_Ty, _As...> &&
382 __is_nothrow_constructible(_Ty, _As...);
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500383#else
Patrick Williamse61c6792023-03-29 10:28:22 -0500384template <class _Ty, class... _As>
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500385concept __nothrow_constructible_from =
Patrick Williamse61c6792023-03-29 10:28:22 -0500386 constructible_from<_Ty, _As...> &&
387 std::is_nothrow_constructible_v<_Ty, _As...>;
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500388#endif
389
390template <class _Ty>
Patrick Williamse61c6792023-03-29 10:28:22 -0500391concept __decay_copyable = constructible_from<__decay_t<_Ty>, _Ty>;
392
393template <class _Ty>
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500394concept __nothrow_decay_copyable =
Patrick Williamse61c6792023-03-29 10:28:22 -0500395 __nothrow_constructible_from<__decay_t<_Ty>, _Ty>;
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500396} // namespace stdexec
Patrick Williamsabbdd6a2023-01-20 10:12:50 -0600397
398#if !STDEXEC_HAS_STD_CONCEPTS_HEADER()
399namespace std
400{
401using namespace stdexec::__std_concepts;
402}
403#endif