blob: 79a97403b03532b4dc5fbd1648beccdf75ea069e [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 Williams8723a542024-02-12 11:18:32 -060022#include "__detail/__concepts.hpp"
23#include "__detail/__config.hpp"
24#include "__detail/__meta.hpp"
25#include "__detail/__type_traits.hpp"
26
Patrick Williams5b5d15b2022-08-23 09:35:15 -050027#include <version>
28
Patrick Williams5e7ef082023-01-05 11:08:53 -060029// Perhaps the stdlib lacks support for concepts though:
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060030#if __has_include(<concepts>) && __cpp_lib_concepts >= 202002
31#define STDEXEC_HAS_STD_CONCEPTS_HEADER() 1
32#else
33#define STDEXEC_HAS_STD_CONCEPTS_HEADER() 0
34#endif
35
36#if STDEXEC_HAS_STD_CONCEPTS_HEADER()
Patrick Williams5b5d15b2022-08-23 09:35:15 -050037#include <concepts>
Patrick Williams5b5d15b2022-08-23 09:35:15 -050038#else
39#include <type_traits>
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060040#endif
Patrick Williams5b5d15b2022-08-23 09:35:15 -050041
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060042namespace stdexec::__std_concepts
Patrick Williams5b5d15b2022-08-23 09:35:15 -050043{
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060044// Make sure we're using a same_as concept that doesn't instantiate std::is_same
Patrick Williamse61c6792023-03-29 10:28:22 -050045template <class _Ap, class _Bp>
46concept same_as = __same_as<_Ap, _Bp> && __same_as<_Bp, _Ap>;
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060047
48#if STDEXEC_HAS_STD_CONCEPTS_HEADER()
49
50using std::convertible_to;
51using std::derived_from;
52using std::equality_comparable;
53using std::integral;
54
55#else
56
Patrick Williams5b5d15b2022-08-23 09:35:15 -050057template <class T>
58concept integral = std::is_integral_v<T>;
59
Patrick Williamse61c6792023-03-29 10:28:22 -050060template <class _Ap, class _Bp>
Patrick Williamsfa663ae2023-06-23 15:47:27 -050061concept derived_from = //
62 STDEXEC_IS_BASE_OF(_Bp, _Ap) && //
63 STDEXEC_IS_CONVERTIBLE_TO(const volatile _Ap*, const volatile _Bp*);
Patrick Williams5b5d15b2022-08-23 09:35:15 -050064
65template <class _From, class _To>
Patrick Williamsfa663ae2023-06-23 15:47:27 -050066concept convertible_to = //
67 STDEXEC_IS_CONVERTIBLE_TO(_From, _To) && //
Patrick Williams5b5d15b2022-08-23 09:35:15 -050068 requires(_From (&__fun)()) { static_cast<_To>(__fun()); };
69
Patrick Williamse61c6792023-03-29 10:28:22 -050070template <class _Ty>
71concept equality_comparable = //
72 requires(__cref_t<_Ty> __t) {
73 {
74 __t == __t
Patrick Williamsd2149042023-05-10 07:50:13 -050075 } -> convertible_to<bool>;
Patrick Williamse61c6792023-03-29 10:28:22 -050076 {
77 __t != __t
Patrick Williamsd2149042023-05-10 07:50:13 -050078 } -> convertible_to<bool>;
Patrick Williamse61c6792023-03-29 10:28:22 -050079 };
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060080#endif
81} // namespace stdexec::__std_concepts
Patrick Williams5b5d15b2022-08-23 09:35:15 -050082
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060083namespace stdexec
84{
85using namespace __std_concepts;
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060086
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060087// Avoid using libstdc++'s object concepts because they instantiate a
88// lot of templates.
Patrick Williams1f7438a2024-01-23 16:54:44 -060089#if STDEXEC_HAS_BUILTIN(__is_nothrow_destructible)
90template <class _Ty>
91concept destructible = __is_nothrow_destructible(_Ty);
92#else
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060093template <class _Ty>
Patrick Williamse61c6792023-03-29 10:28:22 -050094inline constexpr bool __destructible_ = //
Patrick Williamsabbdd6a2023-01-20 10:12:50 -060095 requires {
96 {
97 ((_Ty && (*)() noexcept) nullptr)().~_Ty()
98 } noexcept;
99 };
100template <class _Ty>
101inline constexpr bool __destructible_<_Ty&> = true;
102template <class _Ty>
103inline constexpr bool __destructible_<_Ty&&> = true;
Patrick Williamse61c6792023-03-29 10:28:22 -0500104template <class _Ty, std::size_t _Np>
105inline constexpr bool __destructible_<_Ty[_Np]> = __destructible_<_Ty>;
Patrick Williamsabbdd6a2023-01-20 10:12:50 -0600106
107template <class T>
108concept destructible = __destructible_<T>;
Patrick Williams1f7438a2024-01-23 16:54:44 -0600109#endif
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500110
Patrick Williams5932cd62023-11-16 11:13:00 -0600111#if STDEXEC_HAS_BUILTIN(__is_constructible)
Patrick Williamse61c6792023-03-29 10:28:22 -0500112template <class _Ty, class... _As>
113concept constructible_from = //
114 destructible<_Ty> && //
115 __is_constructible(_Ty, _As...);
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500116#else
Patrick Williamse61c6792023-03-29 10:28:22 -0500117template <class _Ty, class... _As>
118concept constructible_from = //
119 destructible<_Ty> && //
Patrick Williams5932cd62023-11-16 11:13:00 -0600120 std::is_constructible_v<_Ty, _As...>;
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500121#endif
122
Patrick Williamse61c6792023-03-29 10:28:22 -0500123template <class _Ty>
124concept default_initializable = //
125 constructible_from<_Ty> && //
126 requires { _Ty{}; } && //
127 requires { ::new _Ty; };
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500128
Patrick Williamse61c6792023-03-29 10:28:22 -0500129template <class _Ty>
130concept move_constructible = //
131 constructible_from<_Ty, _Ty>;
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500132
Patrick Williamse61c6792023-03-29 10:28:22 -0500133template <class _Ty>
134concept copy_constructible = //
135 move_constructible<_Ty> //
136 && constructible_from<_Ty, const _Ty&>;
137
138template <class _LHS, class _RHS>
Patrick Williams3e20fa82023-05-10 10:10:29 -0500139concept assignable_from = //
140 same_as<_LHS, _LHS&> && //
Patrick Williamse61c6792023-03-29 10:28:22 -0500141 // std::common_reference_with<
142 // const std::remove_reference_t<_LHS>&,
143 // const std::remove_reference_t<_RHS>&> &&
144 requires(_LHS __lhs, _RHS&& __rhs) {
145 {
Patrick Williamsd2149042023-05-10 07:50:13 -0500146 __lhs = ((_RHS&&)__rhs)
147 } -> same_as<_LHS>;
Patrick Williamse61c6792023-03-29 10:28:22 -0500148 };
149
150namespace __swap
151{
152using std::swap;
153
154template <class _Ty, class _Uy>
Patrick Williams3e20fa82023-05-10 10:10:29 -0500155concept swappable_with = //
156 requires(_Ty&& __t, _Uy&& __u) { //
157 swap((_Ty&&)__t, (_Uy&&)__u);
158 };
Patrick Williamse61c6792023-03-29 10:28:22 -0500159
160inline constexpr const auto __fn = //
161 []<class _Ty, swappable_with<_Ty> _Uy>(_Ty&& __t, _Uy&& __u) noexcept(
Patrick Williamsd2149042023-05-10 07:50:13 -0500162 noexcept(swap((_Ty&&)__t, (_Uy&&)__u))) {
163 swap((_Ty&&)__t, (_Uy&&)__u);
164};
Patrick Williamse61c6792023-03-29 10:28:22 -0500165} // namespace __swap
166
167using __swap::swappable_with;
168inline constexpr const auto& swap = __swap::__fn;
169
170template <class _Ty>
171concept swappable = //
172 swappable_with<_Ty, _Ty>;
173
174template <class _Ty>
175concept movable = //
176 std::is_object_v<_Ty> && //
177 move_constructible<_Ty> && //
178 assignable_from<_Ty&, _Ty> && //
179 swappable<_Ty>;
180
181template <class _Ty>
182concept copyable = //
183 copy_constructible<_Ty> && //
184 movable<_Ty> && //
185 assignable_from<_Ty&, _Ty&> && //
186 assignable_from<_Ty&, const _Ty&> && //
187 assignable_from<_Ty&, const _Ty>;
188
189template <class _Ty>
190concept semiregular = //
191 copyable<_Ty> && //
192 default_initializable<_Ty>;
193
194template <class _Ty>
195concept regular = //
196 semiregular<_Ty> && //
197 equality_comparable<_Ty>;
198
Patrick Williams3e20fa82023-05-10 10:10:29 -0500199// Not exactly right, but close.
200template <class _Ty>
201concept __boolean_testable_ = convertible_to<_Ty, bool>;
202
Patrick Williamse61c6792023-03-29 10:28:22 -0500203template <class T, class U>
204concept __partially_ordered_with = //
205 requires(__cref_t<T> t, __cref_t<U> u) {
206 {
207 t < u
Patrick Williamsd2149042023-05-10 07:50:13 -0500208 } -> __boolean_testable_;
Patrick Williamse61c6792023-03-29 10:28:22 -0500209 {
210 t > u
Patrick Williamsd2149042023-05-10 07:50:13 -0500211 } -> __boolean_testable_;
Patrick Williamse61c6792023-03-29 10:28:22 -0500212 {
213 t <= u
Patrick Williamsd2149042023-05-10 07:50:13 -0500214 } -> __boolean_testable_;
Patrick Williamse61c6792023-03-29 10:28:22 -0500215 {
216 t >= u
Patrick Williamsd2149042023-05-10 07:50:13 -0500217 } -> __boolean_testable_;
Patrick Williamse61c6792023-03-29 10:28:22 -0500218 {
219 u < t
Patrick Williamsd2149042023-05-10 07:50:13 -0500220 } -> __boolean_testable_;
Patrick Williamse61c6792023-03-29 10:28:22 -0500221 {
222 u > t
Patrick Williamsd2149042023-05-10 07:50:13 -0500223 } -> __boolean_testable_;
Patrick Williamse61c6792023-03-29 10:28:22 -0500224 {
225 u <= t
Patrick Williamsd2149042023-05-10 07:50:13 -0500226 } -> __boolean_testable_;
Patrick Williamse61c6792023-03-29 10:28:22 -0500227 {
228 u >= t
Patrick Williamsd2149042023-05-10 07:50:13 -0500229 } -> __boolean_testable_;
Patrick Williamse61c6792023-03-29 10:28:22 -0500230 };
231
232template <class _Ty>
233concept totally_ordered = //
234 equality_comparable<_Ty> && //
235 __partially_ordered_with<_Ty, _Ty>;
236
237template <class _Ty>
238concept __movable_value = //
239 move_constructible<__decay_t<_Ty>> && //
240 constructible_from<__decay_t<_Ty>, _Ty>;
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500241
Patrick Williams5932cd62023-11-16 11:13:00 -0600242template <class _Ty>
243concept __nothrow_movable_value = //
244 __movable_value<_Ty> && //
245 requires(_Ty&& __t) {
246 {
247 __decay_t<_Ty>{__decay_t<_Ty>{(_Ty&&)__t}}
248 } noexcept;
249 };
250
251#if STDEXEC_HAS_BUILTIN(__is_nothrow_constructible)
Patrick Williamse61c6792023-03-29 10:28:22 -0500252template <class _Ty, class... _As>
253concept __nothrow_constructible_from = constructible_from<_Ty, _As...> &&
254 __is_nothrow_constructible(_Ty, _As...);
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500255#else
Patrick Williamse61c6792023-03-29 10:28:22 -0500256template <class _Ty, class... _As>
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500257concept __nothrow_constructible_from =
Patrick Williamse61c6792023-03-29 10:28:22 -0500258 constructible_from<_Ty, _As...> &&
259 std::is_nothrow_constructible_v<_Ty, _As...>;
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500260#endif
261
262template <class _Ty>
Patrick Williams00e3a3a2023-05-19 15:14:49 -0500263concept __nothrow_move_constructible = __nothrow_constructible_from<_Ty, _Ty>;
264
265template <class _Ty>
266concept __nothrow_copy_constructible =
267 __nothrow_constructible_from<_Ty, const _Ty&>;
268
269template <class _Ty>
Patrick Williamse61c6792023-03-29 10:28:22 -0500270concept __decay_copyable = constructible_from<__decay_t<_Ty>, _Ty>;
271
272template <class _Ty>
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500273concept __nothrow_decay_copyable =
Patrick Williamse61c6792023-03-29 10:28:22 -0500274 __nothrow_constructible_from<__decay_t<_Ty>, _Ty>;
Patrick Williams3e20fa82023-05-10 10:10:29 -0500275
Patrick Williams5932cd62023-11-16 11:13:00 -0600276template <class _Ty, class _Up>
277concept __decays_to_derived_from = derived_from<__decay_t<_Ty>, _Up>;
Patrick Williams3e20fa82023-05-10 10:10:29 -0500278
Patrick Williams5b5d15b2022-08-23 09:35:15 -0500279} // namespace stdexec
Patrick Williamsabbdd6a2023-01-20 10:12:50 -0600280
Patrick Williams3e20fa82023-05-10 10:10:29 -0500281// #if !STDEXEC_HAS_STD_CONCEPTS_HEADER()
282// namespace std {
283// using namespace stdexec::__std_concepts;
284// }
285// #endif