Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 1 | /* |
| 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 Williams | 5e7ef08 | 2023-01-05 11:08:53 -0600 | [diff] [blame] | 18 | #if __cpp_concepts < 201907L |
| 19 | #error This library requires support for C++20 concepts |
| 20 | #endif |
| 21 | |
Patrick Williams | 8723a54 | 2024-02-12 11:18:32 -0600 | [diff] [blame^] | 22 | #include "__detail/__concepts.hpp" |
| 23 | #include "__detail/__config.hpp" |
| 24 | #include "__detail/__meta.hpp" |
| 25 | #include "__detail/__type_traits.hpp" |
| 26 | |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 27 | #include <version> |
| 28 | |
Patrick Williams | 5e7ef08 | 2023-01-05 11:08:53 -0600 | [diff] [blame] | 29 | // Perhaps the stdlib lacks support for concepts though: |
Patrick Williams | abbdd6a | 2023-01-20 10:12:50 -0600 | [diff] [blame] | 30 | #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 Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 37 | #include <concepts> |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 38 | #else |
| 39 | #include <type_traits> |
Patrick Williams | abbdd6a | 2023-01-20 10:12:50 -0600 | [diff] [blame] | 40 | #endif |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 41 | |
Patrick Williams | abbdd6a | 2023-01-20 10:12:50 -0600 | [diff] [blame] | 42 | namespace stdexec::__std_concepts |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 43 | { |
Patrick Williams | abbdd6a | 2023-01-20 10:12:50 -0600 | [diff] [blame] | 44 | // Make sure we're using a same_as concept that doesn't instantiate std::is_same |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 45 | template <class _Ap, class _Bp> |
| 46 | concept same_as = __same_as<_Ap, _Bp> && __same_as<_Bp, _Ap>; |
Patrick Williams | abbdd6a | 2023-01-20 10:12:50 -0600 | [diff] [blame] | 47 | |
| 48 | #if STDEXEC_HAS_STD_CONCEPTS_HEADER() |
| 49 | |
| 50 | using std::convertible_to; |
| 51 | using std::derived_from; |
| 52 | using std::equality_comparable; |
| 53 | using std::integral; |
| 54 | |
| 55 | #else |
| 56 | |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 57 | template <class T> |
| 58 | concept integral = std::is_integral_v<T>; |
| 59 | |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 60 | template <class _Ap, class _Bp> |
Patrick Williams | fa663ae | 2023-06-23 15:47:27 -0500 | [diff] [blame] | 61 | concept derived_from = // |
| 62 | STDEXEC_IS_BASE_OF(_Bp, _Ap) && // |
| 63 | STDEXEC_IS_CONVERTIBLE_TO(const volatile _Ap*, const volatile _Bp*); |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 64 | |
| 65 | template <class _From, class _To> |
Patrick Williams | fa663ae | 2023-06-23 15:47:27 -0500 | [diff] [blame] | 66 | concept convertible_to = // |
| 67 | STDEXEC_IS_CONVERTIBLE_TO(_From, _To) && // |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 68 | requires(_From (&__fun)()) { static_cast<_To>(__fun()); }; |
| 69 | |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 70 | template <class _Ty> |
| 71 | concept equality_comparable = // |
| 72 | requires(__cref_t<_Ty> __t) { |
| 73 | { |
| 74 | __t == __t |
Patrick Williams | d214904 | 2023-05-10 07:50:13 -0500 | [diff] [blame] | 75 | } -> convertible_to<bool>; |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 76 | { |
| 77 | __t != __t |
Patrick Williams | d214904 | 2023-05-10 07:50:13 -0500 | [diff] [blame] | 78 | } -> convertible_to<bool>; |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 79 | }; |
Patrick Williams | abbdd6a | 2023-01-20 10:12:50 -0600 | [diff] [blame] | 80 | #endif |
| 81 | } // namespace stdexec::__std_concepts |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 82 | |
Patrick Williams | abbdd6a | 2023-01-20 10:12:50 -0600 | [diff] [blame] | 83 | namespace stdexec |
| 84 | { |
| 85 | using namespace __std_concepts; |
Patrick Williams | abbdd6a | 2023-01-20 10:12:50 -0600 | [diff] [blame] | 86 | |
Patrick Williams | abbdd6a | 2023-01-20 10:12:50 -0600 | [diff] [blame] | 87 | // Avoid using libstdc++'s object concepts because they instantiate a |
| 88 | // lot of templates. |
Patrick Williams | 1f7438a | 2024-01-23 16:54:44 -0600 | [diff] [blame] | 89 | #if STDEXEC_HAS_BUILTIN(__is_nothrow_destructible) |
| 90 | template <class _Ty> |
| 91 | concept destructible = __is_nothrow_destructible(_Ty); |
| 92 | #else |
Patrick Williams | abbdd6a | 2023-01-20 10:12:50 -0600 | [diff] [blame] | 93 | template <class _Ty> |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 94 | inline constexpr bool __destructible_ = // |
Patrick Williams | abbdd6a | 2023-01-20 10:12:50 -0600 | [diff] [blame] | 95 | requires { |
| 96 | { |
| 97 | ((_Ty && (*)() noexcept) nullptr)().~_Ty() |
| 98 | } noexcept; |
| 99 | }; |
| 100 | template <class _Ty> |
| 101 | inline constexpr bool __destructible_<_Ty&> = true; |
| 102 | template <class _Ty> |
| 103 | inline constexpr bool __destructible_<_Ty&&> = true; |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 104 | template <class _Ty, std::size_t _Np> |
| 105 | inline constexpr bool __destructible_<_Ty[_Np]> = __destructible_<_Ty>; |
Patrick Williams | abbdd6a | 2023-01-20 10:12:50 -0600 | [diff] [blame] | 106 | |
| 107 | template <class T> |
| 108 | concept destructible = __destructible_<T>; |
Patrick Williams | 1f7438a | 2024-01-23 16:54:44 -0600 | [diff] [blame] | 109 | #endif |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 110 | |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 111 | #if STDEXEC_HAS_BUILTIN(__is_constructible) |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 112 | template <class _Ty, class... _As> |
| 113 | concept constructible_from = // |
| 114 | destructible<_Ty> && // |
| 115 | __is_constructible(_Ty, _As...); |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 116 | #else |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 117 | template <class _Ty, class... _As> |
| 118 | concept constructible_from = // |
| 119 | destructible<_Ty> && // |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 120 | std::is_constructible_v<_Ty, _As...>; |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 121 | #endif |
| 122 | |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 123 | template <class _Ty> |
| 124 | concept default_initializable = // |
| 125 | constructible_from<_Ty> && // |
| 126 | requires { _Ty{}; } && // |
| 127 | requires { ::new _Ty; }; |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 128 | |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 129 | template <class _Ty> |
| 130 | concept move_constructible = // |
| 131 | constructible_from<_Ty, _Ty>; |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 132 | |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 133 | template <class _Ty> |
| 134 | concept copy_constructible = // |
| 135 | move_constructible<_Ty> // |
| 136 | && constructible_from<_Ty, const _Ty&>; |
| 137 | |
| 138 | template <class _LHS, class _RHS> |
Patrick Williams | 3e20fa8 | 2023-05-10 10:10:29 -0500 | [diff] [blame] | 139 | concept assignable_from = // |
| 140 | same_as<_LHS, _LHS&> && // |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 141 | // 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 Williams | d214904 | 2023-05-10 07:50:13 -0500 | [diff] [blame] | 146 | __lhs = ((_RHS&&)__rhs) |
| 147 | } -> same_as<_LHS>; |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 148 | }; |
| 149 | |
| 150 | namespace __swap |
| 151 | { |
| 152 | using std::swap; |
| 153 | |
| 154 | template <class _Ty, class _Uy> |
Patrick Williams | 3e20fa8 | 2023-05-10 10:10:29 -0500 | [diff] [blame] | 155 | concept swappable_with = // |
| 156 | requires(_Ty&& __t, _Uy&& __u) { // |
| 157 | swap((_Ty&&)__t, (_Uy&&)__u); |
| 158 | }; |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 159 | |
| 160 | inline constexpr const auto __fn = // |
| 161 | []<class _Ty, swappable_with<_Ty> _Uy>(_Ty&& __t, _Uy&& __u) noexcept( |
Patrick Williams | d214904 | 2023-05-10 07:50:13 -0500 | [diff] [blame] | 162 | noexcept(swap((_Ty&&)__t, (_Uy&&)__u))) { |
| 163 | swap((_Ty&&)__t, (_Uy&&)__u); |
| 164 | }; |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 165 | } // namespace __swap |
| 166 | |
| 167 | using __swap::swappable_with; |
| 168 | inline constexpr const auto& swap = __swap::__fn; |
| 169 | |
| 170 | template <class _Ty> |
| 171 | concept swappable = // |
| 172 | swappable_with<_Ty, _Ty>; |
| 173 | |
| 174 | template <class _Ty> |
| 175 | concept movable = // |
| 176 | std::is_object_v<_Ty> && // |
| 177 | move_constructible<_Ty> && // |
| 178 | assignable_from<_Ty&, _Ty> && // |
| 179 | swappable<_Ty>; |
| 180 | |
| 181 | template <class _Ty> |
| 182 | concept 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 | |
| 189 | template <class _Ty> |
| 190 | concept semiregular = // |
| 191 | copyable<_Ty> && // |
| 192 | default_initializable<_Ty>; |
| 193 | |
| 194 | template <class _Ty> |
| 195 | concept regular = // |
| 196 | semiregular<_Ty> && // |
| 197 | equality_comparable<_Ty>; |
| 198 | |
Patrick Williams | 3e20fa8 | 2023-05-10 10:10:29 -0500 | [diff] [blame] | 199 | // Not exactly right, but close. |
| 200 | template <class _Ty> |
| 201 | concept __boolean_testable_ = convertible_to<_Ty, bool>; |
| 202 | |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 203 | template <class T, class U> |
| 204 | concept __partially_ordered_with = // |
| 205 | requires(__cref_t<T> t, __cref_t<U> u) { |
| 206 | { |
| 207 | t < u |
Patrick Williams | d214904 | 2023-05-10 07:50:13 -0500 | [diff] [blame] | 208 | } -> __boolean_testable_; |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 209 | { |
| 210 | t > u |
Patrick Williams | d214904 | 2023-05-10 07:50:13 -0500 | [diff] [blame] | 211 | } -> __boolean_testable_; |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 212 | { |
| 213 | t <= u |
Patrick Williams | d214904 | 2023-05-10 07:50:13 -0500 | [diff] [blame] | 214 | } -> __boolean_testable_; |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 215 | { |
| 216 | t >= u |
Patrick Williams | d214904 | 2023-05-10 07:50:13 -0500 | [diff] [blame] | 217 | } -> __boolean_testable_; |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 218 | { |
| 219 | u < t |
Patrick Williams | d214904 | 2023-05-10 07:50:13 -0500 | [diff] [blame] | 220 | } -> __boolean_testable_; |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 221 | { |
| 222 | u > t |
Patrick Williams | d214904 | 2023-05-10 07:50:13 -0500 | [diff] [blame] | 223 | } -> __boolean_testable_; |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 224 | { |
| 225 | u <= t |
Patrick Williams | d214904 | 2023-05-10 07:50:13 -0500 | [diff] [blame] | 226 | } -> __boolean_testable_; |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 227 | { |
| 228 | u >= t |
Patrick Williams | d214904 | 2023-05-10 07:50:13 -0500 | [diff] [blame] | 229 | } -> __boolean_testable_; |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 230 | }; |
| 231 | |
| 232 | template <class _Ty> |
| 233 | concept totally_ordered = // |
| 234 | equality_comparable<_Ty> && // |
| 235 | __partially_ordered_with<_Ty, _Ty>; |
| 236 | |
| 237 | template <class _Ty> |
| 238 | concept __movable_value = // |
| 239 | move_constructible<__decay_t<_Ty>> && // |
| 240 | constructible_from<__decay_t<_Ty>, _Ty>; |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 241 | |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 242 | template <class _Ty> |
| 243 | concept __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 Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 252 | template <class _Ty, class... _As> |
| 253 | concept __nothrow_constructible_from = constructible_from<_Ty, _As...> && |
| 254 | __is_nothrow_constructible(_Ty, _As...); |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 255 | #else |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 256 | template <class _Ty, class... _As> |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 257 | concept __nothrow_constructible_from = |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 258 | constructible_from<_Ty, _As...> && |
| 259 | std::is_nothrow_constructible_v<_Ty, _As...>; |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 260 | #endif |
| 261 | |
| 262 | template <class _Ty> |
Patrick Williams | 00e3a3a | 2023-05-19 15:14:49 -0500 | [diff] [blame] | 263 | concept __nothrow_move_constructible = __nothrow_constructible_from<_Ty, _Ty>; |
| 264 | |
| 265 | template <class _Ty> |
| 266 | concept __nothrow_copy_constructible = |
| 267 | __nothrow_constructible_from<_Ty, const _Ty&>; |
| 268 | |
| 269 | template <class _Ty> |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 270 | concept __decay_copyable = constructible_from<__decay_t<_Ty>, _Ty>; |
| 271 | |
| 272 | template <class _Ty> |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 273 | concept __nothrow_decay_copyable = |
Patrick Williams | e61c679 | 2023-03-29 10:28:22 -0500 | [diff] [blame] | 274 | __nothrow_constructible_from<__decay_t<_Ty>, _Ty>; |
Patrick Williams | 3e20fa8 | 2023-05-10 10:10:29 -0500 | [diff] [blame] | 275 | |
Patrick Williams | 5932cd6 | 2023-11-16 11:13:00 -0600 | [diff] [blame] | 276 | template <class _Ty, class _Up> |
| 277 | concept __decays_to_derived_from = derived_from<__decay_t<_Ty>, _Up>; |
Patrick Williams | 3e20fa8 | 2023-05-10 10:10:29 -0500 | [diff] [blame] | 278 | |
Patrick Williams | 5b5d15b | 2022-08-23 09:35:15 -0500 | [diff] [blame] | 279 | } // namespace stdexec |
Patrick Williams | abbdd6a | 2023-01-20 10:12:50 -0600 | [diff] [blame] | 280 | |
Patrick Williams | 3e20fa8 | 2023-05-10 10:10:29 -0500 | [diff] [blame] | 281 | // #if !STDEXEC_HAS_STD_CONCEPTS_HEADER() |
| 282 | // namespace std { |
| 283 | // using namespace stdexec::__std_concepts; |
| 284 | // } |
| 285 | // #endif |