1 /* 2 * Copyright (c) 2021-2024 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 18 #include <cstddef> 19 #include <cassert> 20 #include <compare> 21 #include <type_traits> 22 23 #include "__config.hpp" 24 #include "__concepts.hpp" 25 #include "__type_traits.hpp" 26 #include "__utility.hpp" 27 28 namespace stdexec { 29 //! Convenience metafunction getting the dependant type `__t` out of `_Tp`. 30 //! That is, `typename _Tp::__t`. 31 //! See MAINTAINERS.md#class-template-parameters for details. 32 template <class _Tp> 33 using __t = _Tp::__t; 34 35 template <class _Ty> 36 struct __mtype { 37 using __t = _Ty; 38 }; 39 40 template <class...> 41 inline constexpr bool __mnever = false; 42 43 template <auto _Value> 44 using __mtypeof = decltype(_Value); 45 46 template <class...> 47 struct __types; 48 49 template <class _Tp> 50 using __midentity = _Tp; 51 52 template <auto _Np> 53 struct __mconstant { 54 using type = __mconstant; 55 using value_type = __mtypeof<_Np>; 56 static constexpr auto value = _Np; 57 operator value_typestdexec::__mconstant58 constexpr operator value_type() const noexcept { 59 return value; 60 } 61 operator ()stdexec::__mconstant62 constexpr auto operator()() const noexcept -> value_type { 63 return value; 64 } 65 }; 66 67 // nvbugs#4679848 and nvbugs#4668709 also preclude __mconstant from representing a compile-time 68 // size_t. 69 enum class __u8 : unsigned char { 70 }; 71 72 #if STDEXEC_NVCC() || STDEXEC_EDG() 73 template <std::size_t _Np> 74 using __msize_t = std::integral_constant<std::size_t, _Np>; 75 #elif STDEXEC_MSVC() 76 template <std::size_t _Np> 77 using __msize_t = __mconstant<_Np>; 78 #else 79 template <std::size_t _Np> 80 using __msize_t = __u8 (*)[_Np + 1]; // +1 to avoid zero-size array 81 #endif 82 83 //! Metafunction selects the first of two type arguments. 84 template <class _Tp, class _Up> 85 using __mfirst = _Tp; 86 87 //! Metafunction selects the second of two type arguments. 88 template <class _Tp, class _Up> 89 using __msecond = _Up; 90 91 template <class...> 92 struct __undefined; 93 94 template <class _Tp> 95 extern const __undefined<_Tp> __v; 96 97 template <class _Tp> 98 requires __typename<__mtypeof<_Tp::value>> 99 inline constexpr __mtypeof<_Tp::value> __v<_Tp> = _Tp::value; 100 101 // These specializations exist because instantiating a variable template is cheaper than 102 // instantiating a class template. 103 template <class _Tp, class _Up> 104 inline constexpr bool __v<std::is_same<_Tp, _Up>> = false; 105 106 template <class _Tp> 107 inline constexpr bool __v<std::is_same<_Tp, _Tp>> = true; 108 109 template <class _Tp, _Tp _Ip> 110 inline constexpr _Tp __v<std::integral_constant<_Tp, _Ip>> = _Ip; 111 112 // `__mtypeof<_Np>` instead of `auto` to work around NVHPC/EDG bug. 113 template <auto _Np> 114 inline constexpr __mtypeof<_Np> __v<__mconstant<_Np>> = _Np; 115 116 template <std::size_t _Np> 117 inline constexpr std::size_t __v<__u8 (*)[_Np]> = _Np - 1; // see definition of __msize_t 118 119 template <std::size_t... _Is> 120 struct __iota; 121 122 template <std::size_t... _Is> 123 using __indices = __iota<_Is...> *; 124 125 #if STDEXEC_MSVC() 126 namespace __pack { 127 template <class _Ty, _Ty... _Is> 128 struct __idx; 129 130 template <class> 131 extern int __mkidx; 132 133 template <std::size_t... _Is> 134 extern __indices<_Is...> __mkidx<__idx<std::size_t, _Is...>>; 135 } // namespace __pack 136 137 template <std::size_t _Np> 138 using __make_indices = 139 decltype(__pack::__mkidx<__make_integer_seq<__pack::__idx, std::size_t, _Np>>); 140 #elif STDEXEC_HAS_BUILTIN(__make_integer_seq) 141 namespace __pack { 142 template <class _Ty, _Ty... _Is> 143 using __idx = __indices<_Is...>; 144 } // namespace __pack 145 146 template <std::size_t _Np> 147 using __make_indices = __make_integer_seq<__pack::__idx, std::size_t, _Np>; 148 #elif STDEXEC_HAS_BUILTIN(__integer_pack) 149 namespace __pack { 150 template <std::size_t _Np> 151 extern __indices<__integer_pack(_Np)...> __make_indices; 152 } // namespace __pack 153 154 template <std::size_t _Np> 155 using __make_indices = decltype(__pack::__make_indices<_Np>); 156 #else 157 namespace __pack { 158 template <std::size_t... _Is> 159 auto __mk_indices(__indices<0, _Is...>) -> __indices<_Is...>; 160 161 template <std::size_t _Np, class = char[_Np], std::size_t... _Is> 162 auto __mk_indices(__indices<_Np, _Is...>) 163 -> decltype(__mk_indices(__indices<_Np - 1, 0, (_Is + 1)...>{})); 164 } // namespace __pack 165 166 template <std::size_t _Np> 167 using __make_indices = decltype(__pack::__mk_indices(__indices<_Np>{})); 168 #endif 169 170 template <class... _Ts> 171 using __indices_for = __make_indices<sizeof...(_Ts)>; 172 173 STDEXEC_PRAGMA_PUSH() 174 STDEXEC_PRAGMA_IGNORE_MSVC(4293) 175 __mpow2(std::size_t __size)176 constexpr auto __mpow2(std::size_t __size) noexcept -> std::size_t { 177 --__size; 178 __size |= __size >> 1; 179 __size |= __size >> 2; 180 __size |= __size >> 4; 181 __size |= __size >> 8; 182 if constexpr (sizeof(__size) >= 4) 183 __size |= __size >> 16; 184 if constexpr (sizeof(__size) >= 8) 185 __size |= __size >> 32; 186 return ++__size; 187 } 188 189 STDEXEC_PRAGMA_POP() 190 191 template <std::size_t _Len> 192 struct __mstring { 193 #if STDEXEC_EDG() 194 template <std::size_t _Ny, std::size_t... _Is> __mstringstdexec::__mstring195 constexpr __mstring(const char (&__str)[_Ny], __indices<_Is...>) noexcept 196 : __what_{(_Is < _Ny ? __str[_Is] : '\0')...} { 197 } 198 199 template <std::size_t _Ny> __mstringstdexec::__mstring200 constexpr __mstring(const char (&__str)[_Ny], int = 0) noexcept 201 : __mstring{__str, __make_indices<_Len>{}} { 202 } 203 #else 204 template <std::size_t _Ny> 205 constexpr __mstring(const char (&__str)[_Ny], int = 0) noexcept { 206 for (auto __i = 0ull; char __ch: __str) { 207 __what_[__i++] = __ch; 208 } 209 } 210 #endif 211 __lengthstdexec::__mstring212 static constexpr auto __length() noexcept -> std::size_t { 213 return _Len; 214 } 215 216 constexpr auto operator==(const __mstring &) const noexcept -> bool = default; 217 218 template <std::size_t _OtherLen> operator ==stdexec::__mstring219 constexpr auto operator==(const __mstring<_OtherLen> &) const noexcept -> bool { 220 return false; 221 } 222 223 #if !STDEXEC_EDG() 224 constexpr auto operator<=>(const __mstring &) const noexcept -> std::strong_ordering = default; 225 #endif 226 227 template <std::size_t _OtherLen> 228 constexpr auto operator <=>stdexec::__mstring229 operator<=>(const __mstring<_OtherLen> &__other) const noexcept -> std::strong_ordering { 230 constexpr std::size_t __len = _Len < _OtherLen ? _Len : _OtherLen; 231 for (std::size_t __i = 0; __i < __len; ++__i) { 232 auto __cmp = (__what_[__i] <=> __other.__what_[__i]); 233 if (__cmp != 0) { 234 return __cmp; 235 } 236 } 237 if constexpr (_Len == _OtherLen) { 238 return std::strong_ordering::equal; 239 } 240 return (_Len < _OtherLen) ? std::strong_ordering::less : std::strong_ordering::greater; 241 } 242 243 char __what_[_Len]{}; 244 }; 245 246 template <std::size_t _Len> 247 __mstring(const char (&__str)[_Len]) -> __mstring<_Len>; 248 249 template <std::size_t _Len> 250 __mstring(const char (&__str)[_Len], int) -> __mstring<__mpow2(_Len)>; 251 252 STDEXEC_PRAGMA_PUSH() 253 STDEXEC_PRAGMA_IGNORE_GNU("-Wuser-defined-literals") 254 255 // Use a standard user-defined string literal template 256 template <__mstring _Str> 257 [[deprecated("Use _mstr instead")]] operator ""__csz()258 constexpr auto operator""__csz() noexcept -> __mtypeof<_Str> { 259 return _Str; 260 } 261 262 // Use a standard user-defined string literal template 263 template <__mstring _Str> operator ""_mstr()264 constexpr auto operator""_mstr() noexcept -> __mtypeof<_Str> { 265 return _Str; 266 } 267 STDEXEC_PRAGMA_POP()268 STDEXEC_PRAGMA_POP() 269 270 template <class T> 271 constexpr auto __mnameof() noexcept { 272 #if STDEXEC_MSVC() 273 return __mstring{__FUNCSIG__, 0}; 274 #else 275 return __mstring{__PRETTY_FUNCTION__, 0}; 276 #endif 277 } 278 279 using __msuccess = int; 280 281 template <class _What, class... _With> 282 struct _WARNING_ { }; 283 284 template <class _What, class... _With> 285 struct _ERROR_ { 286 using __what_t = _What; 287 auto operator,(__msuccess) const noexcept -> _ERROR_; 288 }; 289 290 template <__mstring... _What> 291 struct _WHAT_ { }; 292 293 template <class _What, class... _With> 294 using __mexception = _ERROR_<_What, _With...>; 295 296 template <class> 297 extern __msuccess __ok_v; 298 299 template <class _What, class... _With> 300 extern _ERROR_<_What, _With...> __ok_v<__mexception<_What, _With...>>; 301 302 template <class _Ty> 303 using __ok_t = decltype(__ok_v<_Ty>); 304 305 template <class... _Ts> 306 using __disp = decltype((__msuccess(), ..., __ok_t<_Ts>())); 307 308 template <class _Arg> 309 concept __ok = STDEXEC_IS_SAME(__ok_t<_Arg>, __msuccess); 310 311 template <class _Arg> 312 concept __merror = !STDEXEC_IS_SAME(__ok_t<_Arg>, __msuccess); 313 314 template <class... _Args> 315 concept _Ok = (STDEXEC_IS_SAME(__ok_t<_Args>, __msuccess) && ...); 316 317 //! The struct `__i` is the implementation of P2300's 318 //! [_`META-APPLY`_](https://eel.is/c++draft/exec#util.cmplsig-5). 319 //! > [Note [1](https://eel.is/c++draft/exec#util.cmplsig-note-1): 320 //! > The purpose of META-APPLY is to make it valid to use non-variadic 321 //! > templates as Variant and Tuple arguments to gather-signatures. — end note] 322 //! In addition to avoiding the dreaded "pack expanded into non-pack argument" error, 323 //! it is part of the meta-error propagation mechanism. if any of the argument types 324 //! are a specialization of `_ERROR_`, `__i` will short-circuit and return the error. 325 //! `__minvoke` and `__meval` are implemented in terms of `__i`. 326 template <bool _ArgsOK, bool _FnOK = true> 327 struct __i; 328 329 #if STDEXEC_EDG() 330 // Most compilers memoize alias template specializations, but 331 // nvc++ does not. So we memoize the type computations by 332 // indirecting through a class template specialization. 333 template <template <class...> class _Fn, class... _Args> 334 using __meval__ = __i<_Ok<_Args...>>::template __g<_Fn, _Args...>; 335 336 template <template <class...> class _Fn, class... _Args> 337 struct __meval_ { }; 338 339 template <template <class...> class _Fn, class... _Args> 340 requires __typename<__meval__<_Fn, _Args...>> 341 struct __meval_<_Fn, _Args...> { 342 using __t = __meval__<_Fn, _Args...>; 343 }; 344 345 template <template <class...> class _Fn, class... _Args> 346 using __meval = __t<__meval_<_Fn, _Args...>>; 347 348 template <class _Fn, class... _Args> 349 using __minvoke__ = __i<_Ok<_Args...>, _Ok<_Fn>>::template __f<_Fn>::template __f<_Args...>; 350 351 template <class _Fn, class... _Args> 352 struct __minvoke_ { }; 353 354 template <class _Fn, class... _Args> 355 requires __typename<__minvoke__<_Fn, _Args...>> 356 struct __minvoke_<_Fn, _Args...> { 357 using __t = __minvoke__<_Fn, _Args...>; 358 }; 359 360 template <class _Fn, class... _Args> 361 using __minvoke = __t<__minvoke_<_Fn, _Args...>>; 362 363 #else 364 365 template <template <class...> class _Fn, class... _Args> 366 using __meval = __i<_Ok<_Args...>>::template __g<_Fn, _Args...>; 367 368 //! Metafunction invocation 369 //! Given a metafunction, `_Fn`, and args. 370 //! We expect `_Fn::__f` to be type alias template "implementing" the metafunction `_Fn`. 371 template <class _Fn, class... _Args> 372 using __minvoke = __i<_Ok<_Args...>, _Ok<_Fn>>::template __f<_Fn>::template __f<_Args...>; 373 374 #endif 375 376 template <class _Fn, class... _Args> 377 using __mcall = _Fn::template __f<_Args...>; 378 379 template <class _Fn, class _Arg> 380 using __mcall1 = _Fn::template __f<_Arg>; 381 382 struct __disp_q { 383 template <class... _Args> 384 using __f = __disp<_Args...>; 385 }; 386 387 template <> 388 struct __i<true, true> { 389 template <template <class...> class _Fn, class... _Args> 390 using __g = _Fn<_Args...>; 391 392 template <class _Fn> 393 using __f = _Fn; 394 }; 395 396 template <> 397 struct __i<false, true> { 398 template <template <class...> class, class... _Args> 399 using __g = __disp<_Args...>; 400 401 template <class> 402 using __f = __disp_q; 403 }; 404 405 template <bool _ArgsOK> 406 struct __i<_ArgsOK, false> { 407 template <class _Fn> 408 using __f = _Fn; 409 }; 410 411 //! This struct template is like [mpl::quote](https://www.boost.org/doc/libs/1_86_0/libs/mpl/doc/refmanual/quote.html). 412 //! It turns an alias/class template into a metafunction that also propagates "meta-exceptions". 413 //! All of the meta utilities recognize specializations of stdexec::_ERROR_ as an error type. 414 //! Error types short-circuit the evaluation of the metafunction and are automatically propagated like an exception. 415 //! Note: `__minvoke` and `__meval` also participate in this error propagation. 416 //! 417 //! This design lets us report type errors briefly at the library boundary, even if the 418 //! actual error happens deep inside a meta-program. 419 template <template <class...> class _Fn> 420 struct __q { 421 template <class... _Args> 422 using __f = __i<_Ok<_Args...>>::template __g<_Fn, _Args...>; 423 }; 424 425 template <template <class...> class _Fn> 426 struct __qq { 427 template <class... _Args> 428 using __f = _Fn<_Args...>; 429 }; 430 431 template <template <class> class _Fn> 432 struct __q1 { 433 template <class _Ty> 434 using __f = _Fn<_Ty>; 435 }; 436 437 template <template <class, class> class _Fn> 438 struct __q2 { 439 template <class _Ty, class _Uy> 440 using __f = _Fn<_Ty, _Uy>; 441 }; 442 443 template <template <class...> class _Fn> 444 using __mtry_q = __q<_Fn>; 445 446 template <class _Fn> 447 struct __mtry : __mtry_q<_Fn::template __f> { }; 448 449 template <template <class...> class _Fn, class... _Front> 450 struct __mbind_front_q { 451 template <class... _Args> 452 using __f = __meval<_Fn, _Front..., _Args...>; 453 }; 454 455 template <class _Fn, class... _Front> 456 using __mbind_front = __mbind_front_q<_Fn::template __f, _Front...>; 457 458 template <template <class...> class _Fn, class... _Back> 459 struct __mbind_back_q { 460 template <class... _Args> 461 using __f = __meval<_Fn, _Args..., _Back...>; 462 }; 463 464 template <class _Fn, class... _Back> 465 using __mbind_back = __mbind_back_q<_Fn::template __f, _Back...>; 466 467 template <template <class...> class _Tp, class... _Args> 468 concept __mvalid = requires { typename __meval<_Tp, _Args...>; }; 469 470 template <class _Fn, class... _Args> 471 concept __minvocable = __mvalid<_Fn::template __f, _Args...>; 472 473 template <template <class...> class _Tp, class... _Args> 474 concept __msucceeds = __mvalid<_Tp, _Args...> && __ok<__meval<_Tp, _Args...>>; 475 476 template <class _Fn, class... _Args> 477 concept __minvocable_succeeds = __minvocable<_Fn, _Args...> && __ok<__minvoke<_Fn, _Args...>>; 478 479 template <class _Fn, class... _Args> 480 struct __minvoke_force_ { 481 using __t = __minvoke<_Fn, _Args...>; 482 }; 483 template <class _Fn, class... _Args> 484 using __minvoke_force = __t<__minvoke_force_<_Fn, _Args...>>; 485 486 template <class _Fn, class... _Args> 487 struct __mdefer_ { }; 488 489 template <class _Fn, class... _Args> 490 requires __minvocable<_Fn, _Args...> 491 struct __mdefer_<_Fn, _Args...> { 492 using __t = __minvoke<_Fn, _Args...>; 493 }; 494 495 template <class _Fn, class... _Args> 496 struct __mdefer : __mdefer_<_Fn, _Args...> { }; 497 498 template <class _Fn, class... _Args> 499 using __mmemoize = __t<__mdefer<_Fn, _Args...>>; 500 501 template <template <class...> class _Fn, class... _Args> 502 using __mmemoize_q = __mmemoize<__q<_Fn>, _Args...>; 503 504 struct __if_ { 505 //! Metafunction selects `_True` if the bool template is `true`, otherwise the second. 506 //! That is, `__<true>::__f<A, B>` is `A` and `__<false>::__f<A, B>` is B. 507 //! This is similar to `std::conditional_t<Cond, A, B>`. 508 template <bool> 509 struct __ { 510 template <class _True, class...> 511 using __f = _True; 512 }; 513 514 template <class _Pred, class _True, class... _False> 515 using __f = __minvoke<__<static_cast<bool>(__v<_Pred>)>, _True, _False...>; 516 }; 517 518 // Specialization; see above. 519 template <> 520 struct __if_::__<false> { 521 template <class, class _False> 522 using __f = _False; 523 }; 524 525 template <class _Pred, class _True = void, class... _False> 526 requires(sizeof...(_False) <= 1) 527 using __if = __minvoke<__if_, _Pred, _True, _False...>; 528 529 template <bool _Pred, class _True = void, class... _False> 530 requires(sizeof...(_False) <= 1) 531 using __if_c = __minvoke<__if_::__<_Pred>, _True, _False...>; 532 533 template <class _Pred, class _True, class _False, class... _Args> 534 using __minvoke_if = __minvoke<__if<_Pred, _True, _False>, _Args...>; 535 536 template <bool _Pred, class _True, class _False, class... _Args> 537 using __minvoke_if_c = __minvoke<__if_c<_Pred, _True, _False>, _Args...>; 538 539 template <class _Tp> 540 struct __mconst { 541 template <class...> 542 using __f = _Tp; 543 }; 544 545 inline constexpr __mstring __mbad_substitution = 546 "The specified meta-function could not be evaluated with the types provided."_mstr; 547 548 template <__mstring _Diagnostic = __mbad_substitution> 549 struct _BAD_SUBSTITUTION_ { }; 550 551 template <class... _Args> 552 struct _WITH_TYPES_; 553 554 template <template <class...> class _Fun> 555 struct _WITH_META_FUNCTION_T_ { 556 template <class... _Args> 557 using __f = __mexception<_BAD_SUBSTITUTION_<>, _WITH_META_FUNCTION_T_, _WITH_TYPES_<_Args...>>; 558 }; 559 560 template <class _Fun> 561 struct _WITH_META_FUNCTION_ { 562 template <class... _Args> 563 using __f = __mexception<_BAD_SUBSTITUTION_<>, _WITH_META_FUNCTION_, _WITH_TYPES_<_Args...>>; 564 }; 565 566 template <template <class...> class _Try, class _Catch> 567 struct __mtry_catch_q { 568 template <class... _Args> 569 using __f = __minvoke<__if_c<__mvalid<_Try, _Args...>, __q<_Try>, _Catch>, _Args...>; 570 }; 571 572 template <class _Try, class _Catch> 573 struct __mtry_catch { 574 template <class... _Args> 575 using __f = __minvoke<__if_c<__minvocable<_Try, _Args...>, _Try, _Catch>, _Args...>; 576 }; 577 578 template <class _Fn, class _Default> 579 using __with_default = __mtry_catch<_Fn, __mconst<_Default>>; 580 581 template <template <class...> class _Fn, class _Default> 582 using __with_default_q = __mtry_catch_q<_Fn, __mconst<_Default>>; 583 584 template <class _Fn, class _Default, class... _Args> 585 using __minvoke_or = __minvoke<__with_default<_Fn, _Default>, _Args...>; 586 587 template <template <class...> class _Fn, class _Default, class... _Args> 588 using __meval_or = __minvoke<__with_default_q<_Fn, _Default>, _Args...>; 589 590 template <template <class...> class _Fn> 591 struct __mtry_eval_ { 592 template <class... _Args> 593 using __f = __meval<_Fn, _Args...>; 594 }; 595 596 template <template <class...> class _Fn, class... _Args> 597 using __mtry_eval = 598 __minvoke<__mtry_catch<__mtry_eval_<_Fn>, _WITH_META_FUNCTION_T_<_Fn>>, _Args...>; 599 600 template <class _Fn, class... _Args> 601 using __mtry_invoke = __minvoke<__mtry_catch<_Fn, _WITH_META_FUNCTION_<_Fn>>, _Args...>; 602 603 template <class _Ty, class... _Default> 604 using __msuccess_or_t = __if_c<__ok<_Ty>, _Ty, _Default...>; 605 606 template <class _Ty, class... _Default> 607 using __merror_or_t = __if_c<__merror<_Ty>, _Ty, _Default...>; 608 609 template <class _Fn, class _Continuation = __q<__types>> 610 struct __mtransform { 611 template <class... _Args> 612 using __f = __minvoke<_Continuation, __minvoke<_Fn, _Args>...>; 613 }; 614 615 template <bool> 616 struct __mfold_right_ { 617 template <class _Fn, class _State, class _Head, class... _Tail> 618 using __f = 619 __minvoke<__mfold_right_<sizeof...(_Tail) == 0>, _Fn, __minvoke<_Fn, _State, _Head>, _Tail...>; 620 }; 621 622 template <> 623 struct __mfold_right_<true> { // empty pack 624 template <class _Fn, class _State, class...> 625 using __f = _State; 626 }; 627 628 template <class _Init, class _Fn> 629 struct __mfold_right { 630 template <class... _Args> 631 using __f = __minvoke<__mfold_right_<sizeof...(_Args) == 0>, _Fn, _Init, _Args...>; 632 }; 633 634 template <bool> 635 struct __mfold_left_ { 636 template <class _Fn, class _State, class _Head, class... _Tail> 637 using __f = 638 __minvoke<_Fn, __mcall<__mfold_left_<sizeof...(_Tail) == 0>, _Fn, _State, _Tail...>, _Head>; 639 }; 640 641 template <> 642 struct __mfold_left_<true> { // empty pack 643 template <class _Fn, class _State, class...> 644 using __f = _State; 645 }; 646 647 template <class _Init, class _Fn> 648 struct __mfold_left { 649 template <class... _Args> 650 using __f = __minvoke<__mfold_left_<sizeof...(_Args) == 0>, _Fn, _Init, _Args...>; 651 }; 652 653 template <class _Fn> 654 struct __mcurry { 655 template <class... _Ts> 656 using __f = __minvoke<_Fn, _Ts...>; 657 }; 658 659 template <class _Tp> 660 struct __muncurry_; 661 662 template <template <class...> class _Ap, class... _As> 663 struct __muncurry_<_Ap<_As...>> { 664 template <class _Fn> 665 using __f = __minvoke<_Fn, _As...>; 666 }; 667 668 template <std::size_t... _Ns> 669 struct __muncurry_<__indices<_Ns...>> { 670 template <class _Fn> 671 using __f = __minvoke<_Fn, __msize_t<_Ns>...>; 672 }; 673 674 template <template <class _Np, _Np...> class _Cp, class _Np, _Np... _Ns> 675 struct __muncurry_<_Cp<_Np, _Ns...>> { 676 template <class _Fn> 677 using __f = __minvoke<_Fn, std::integral_constant<_Np, _Ns>...>; 678 }; 679 680 template <class _What, class... _With> 681 struct __muncurry_<_ERROR_<_What, _With...>> { 682 template <class _Fn> 683 using __f = _ERROR_<_What, _With...>; 684 }; 685 686 template <class _Fn> 687 struct __muncurry { 688 template <class _Tp> 689 using __f = __muncurry_<_Tp>::template __f<_Fn>; 690 }; 691 692 template <class _Fn, class _List> 693 using __mapply = __minvoke<__muncurry<_Fn>, _List>; 694 695 template <bool> 696 struct __mconcat_ { 697 template < 698 class... _Ts, 699 template <class...> class _Ap = __types, 700 class... _As, 701 template <class...> class _Bp = __types, 702 class... _Bs, 703 template <class...> class _Cp = __types, 704 class... _Cs, 705 template <class...> class _Dp = __types, 706 class... _Ds, 707 class... _Tail 708 > 709 static auto __f( 710 __types<_Ts...> *, 711 _Ap<_As...> *, 712 _Bp<_Bs...> * = nullptr, 713 _Cp<_Cs...> * = nullptr, 714 _Dp<_Ds...> * = nullptr, 715 _Tail *...__tail) 716 -> __midentity<decltype(__mconcat_<(sizeof...(_Tail) == 0)>::__f( 717 static_cast<__types<_Ts..., _As..., _Bs..., _Cs..., _Ds...> *>(nullptr), 718 __tail...))>; 719 }; 720 721 template <> 722 struct __mconcat_<true> { 723 template <class... _As> 724 static auto __f(__types<_As...> *) -> __types<_As...>; 725 }; 726 727 template <class _Continuation = __qq<__types>> 728 struct __mconcat { 729 template <class... _Args> 730 using __f = __mapply< 731 _Continuation, 732 decltype(__mconcat_<(sizeof...(_Args) == 0)>::__f({}, static_cast<_Args *>(nullptr)...)) 733 >; 734 }; 735 736 struct __msize { 737 template <class... _Ts> 738 using __f = __msize_t<sizeof...(_Ts)>; 739 }; 740 741 template <class _Ty> 742 struct __mcount { 743 template <class... _Ts> 744 using __f = __msize_t<(__same_as<_Ts, _Ty> + ... + 0)>; 745 }; 746 747 template <class _Fn> 748 struct __mcount_if { 749 template <class... _Ts> 750 using __f = __msize_t<(bool(__v<__minvoke<_Fn, _Ts>>) + ... + 0)>; 751 }; 752 753 template <class _Tp> 754 struct __mcontains { 755 template <class... _Args> 756 using __f = __mbool<(__same_as<_Tp, _Args> || ...)>; 757 }; 758 759 template <class _Continuation = __q<__types>> 760 struct __mpush_back { 761 template <class _List, class _Item> 762 using __f = __mapply<__mbind_back<_Continuation, _Item>, _List>; 763 }; 764 765 template <class...> 766 struct __mcompose { }; 767 768 template <class _First> 769 struct __mcompose<_First> : _First { }; 770 771 template <class _Second, class _First> 772 struct __mcompose<_Second, _First> { 773 template <class... _Args> 774 using __f = __minvoke<_Second, __minvoke<_First, _Args...>>; 775 }; 776 777 template <class _Last, class _Penultimate, class... _Rest> 778 struct __mcompose<_Last, _Penultimate, _Rest...> { 779 template <class... _Args> 780 using __f = __minvoke<_Last, __minvoke<__mcompose<_Penultimate, _Rest...>, _Args...>>; 781 }; 782 783 template <template <class...> class _Second, template <class...> class _First> 784 struct __mcompose_q { 785 template <class... _Args> 786 using __f = _Second<_First<_Args...>>; 787 }; 788 789 template <class _Old, class _New, class _Continuation = __q<__types>> 790 struct __mreplace { 791 template <class... _Args> 792 using __f = __minvoke<_Continuation, __if_c<__same_as<_Args, _Old>, _New, _Args>...>; 793 }; 794 795 template <class _Old, class _Continuation = __q<__types>> 796 struct __mremove { 797 template <class... _Args> 798 using __f = __minvoke< 799 __mconcat<_Continuation>, 800 __if_c<__same_as<_Args, _Old>, __types<>, __types<_Args>>... 801 >; 802 }; 803 804 template <class _Pred, class _Continuation = __q<__types>> 805 struct __mremove_if { 806 template <class... _Args> 807 using __f = __minvoke< 808 __mconcat<_Continuation>, 809 __if<__minvoke<_Pred, _Args>, __types<>, __types<_Args>>... 810 >; 811 }; 812 813 template <class _Return> 814 struct __qf { 815 template <class... _Args> 816 using __f = _Return(_Args...); 817 }; 818 819 template <class _Ty, class...> 820 using __mfront_ = _Ty; 821 template <class... _As> 822 using __mfront = __meval<__mfront_, _As...>; 823 template <class... _As> 824 requires(sizeof...(_As) == 1) 825 using __msingle = __mfront<_As...>; 826 template <class _Default, class... _As> 827 requires(sizeof...(_As) <= 1) 828 using __msingle_or_ = __mfront<_As..., _Default>; 829 template <class _Default> 830 using __msingle_or = __mbind_front_q<__msingle_or_, _Default>; 831 832 //! A concept checking if `_Ty` has a dependent type `_Ty::__id`. 833 //! See MAINTAINERS.md#class-template-parameters. 834 template <class _Ty> 835 concept __has_id = requires { typename _Ty::__id; }; 836 837 //! Identity mapping `_Ty` to itself. 838 //! That is, `std::is_same_v<T, typename _Id<T>::__t>`. 839 template <class _Ty> 840 struct _Id { 841 using __t = _Ty; 842 843 // Uncomment the line below to find any code that likely misuses the 844 // ADL isolation mechanism. In particular, '__id<T>' when T is a 845 // reference is a likely misuse. The static_assert below will trigger 846 // when the type passed to the __id alias template is a reference to 847 // a type that is setup to use ADL isolation. 848 //static_assert(!__has_id<std::remove_cvref_t<_Ty>>); 849 }; 850 851 //! Helper metafunction detail of `__id`, below. 852 template <bool = true> 853 struct __id_ { 854 template <class _Ty> 855 using __f = _Ty::__id; 856 }; 857 858 template <> 859 struct __id_<false> { 860 template <class _Ty> 861 using __f = _Id<_Ty>; 862 }; 863 864 //! Metafunction mapping `_Ty` to either 865 //! * `typename _Ty::__id` if that exists, or to 866 //! * `_Ty` (itself) otherwise. 867 //! See MAINTAINERS.md#class-template-parameters. 868 template <class _Ty> 869 using __id = __minvoke<__id_<__has_id<_Ty>>, _Ty>; 870 871 template <class _From, class _To = __decay_t<_From>> 872 using __cvref_t = __copy_cvref_t<_From, __t<_To>>; 873 874 template <class _From, class _To = __decay_t<_From>> 875 using __cvref_id = __copy_cvref_t<_From, __id<_To>>; 876 877 #if STDEXEC_EDG() 878 // nvc++ doesn't cache the results of alias template specializations. 879 // To avoid repeated computation of the same function return type, 880 // cache the result ourselves in a class template specialization. 881 template <class _Fun, class... _As> 882 using __call_result_ = decltype(__declval<_Fun>()(__declval<_As>()...)); 883 template <class _Fun, class... _As> 884 using __call_result_t = __t<__mdefer<__q<__call_result_>, _Fun, _As...>>; 885 #else 886 template <class _Fun, class... _As> 887 using __call_result_t = decltype(__declval<_Fun>()(__declval<_As>()...)); 888 #endif 889 890 // BUGBUG TODO file this bug with nvc++ 891 #if STDEXEC_EDG() 892 template <const auto &_Fun, class... _As> 893 using __result_of = __call_result_t<decltype(_Fun), _As...>; 894 #else 895 template <const auto &_Fun, class... _As> 896 using __result_of = decltype(_Fun(__declval<_As>()...)); 897 #endif 898 899 template <const auto &_Fun, class... _As> 900 inline constexpr bool __noexcept_of = noexcept(_Fun(__declval<_As>()...)); 901 902 // For emplacing non-movable types into optionals: 903 template <class _Fn> 904 requires std::is_nothrow_move_constructible_v<_Fn> 905 struct __emplace_from { 906 _Fn __fn_; 907 using __t = __call_result_t<_Fn>; 908 operator __tstdexec::__emplace_from909 operator __t() && noexcept(__nothrow_callable<_Fn>) { 910 return static_cast<_Fn &&>(__fn_)(); 911 } 912 operator ()stdexec::__emplace_from913 auto operator()() && noexcept(__nothrow_callable<_Fn>) -> __t { 914 return static_cast<_Fn &&>(__fn_)(); 915 } 916 }; 917 918 template <class _Fn> 919 __emplace_from(_Fn) -> __emplace_from<_Fn>; 920 921 template <class _Fn, class _Continuation, class _List1, class _List2> 922 struct __mzip_with2_ 923 : __mzip_with2_< 924 _Fn, 925 _Continuation, 926 __mapply<__qq<__types>, _List1>, 927 __mapply<__qq<__types>, _List2> 928 > { }; 929 930 template < 931 class _Fn, 932 class _Continuation, 933 template <class...> class _Cp, 934 class... _Cs, 935 template <class...> class _Dp, 936 class... _Ds 937 > 938 requires requires { typename __minvoke<_Continuation, __minvoke<_Fn, _Cs, _Ds>...>; } 939 struct __mzip_with2_<_Fn, _Continuation, _Cp<_Cs...>, _Dp<_Ds...>> { 940 using __t = __minvoke<_Continuation, __minvoke<_Fn, _Cs, _Ds>...>; 941 }; 942 943 template <class _Fn, class _Continuation = __q<__types>> 944 struct __mzip_with2 { 945 template <class _Cp, class _Dp> 946 using __f = __t<__mzip_with2_<_Fn, _Continuation, _Cp, _Dp>>; 947 }; 948 949 template <bool> 950 struct __mfind_if_ { 951 template <class _Fn, class _Continuation, class _Head, class... _Tail> 952 using __f = __minvoke< 953 __if_c< 954 __v<__minvoke<_Fn, _Head>>, 955 __mbind_front<_Continuation, _Head>, 956 __mbind_front<__mfind_if_<(sizeof...(_Tail) != 0)>, _Fn, _Continuation> 957 >, 958 _Tail... 959 >; 960 }; 961 962 template <> 963 struct __mfind_if_<false> { 964 template <class _Fn, class _Continuation> 965 using __f = __minvoke<_Continuation>; 966 }; 967 968 template <class _Fn, class _Continuation = __q<__types>> 969 struct __mfind_if { 970 template <class... _Args> 971 using __f = __minvoke<__mfind_if_<(sizeof...(_Args) != 0)>, _Fn, _Continuation, _Args...>; 972 }; 973 974 template <class _Fn> 975 struct __mfind_if_i { 976 template <class... _Args> 977 using __f = __msize_t<(sizeof...(_Args) - __v<__minvoke<__mfind_if<_Fn, __msize>, _Args...>>)>; 978 }; 979 980 #if STDEXEC_MSVC() 981 # define __mvalue_of(...) __VA_ARGS__::value 982 #else 983 # define __mvalue_of(...) __v<__VA_ARGS__> 984 #endif 985 986 template <class... _Booleans> 987 using __mand_t = __mbool<(__mvalue_of(_Booleans) && ...)>; 988 template <class... _Booleans> 989 using __mand = __meval<__mand_t, _Booleans...>; 990 991 template <class... _Booleans> 992 using __mor_t = __mbool<(__mvalue_of(_Booleans) || ...)>; 993 template <class... _Booleans> 994 using __mor = __meval<__mor_t, _Booleans...>; 995 996 template <class _Boolean> 997 using __mnot_t = __mbool<!__mvalue_of(_Boolean)>; 998 template <class _Boolean> 999 using __mnot = __meval<__mnot_t, _Boolean>; 1000 1001 #if STDEXEC_EDG() 1002 template <class... _Ints> 1003 struct __mplus_t : __mconstant<(__v<_Ints> + ...)> { }; 1004 #else 1005 template <class... _Ints> 1006 using __mplus_t = __mconstant<(__mvalue_of(_Ints) + ...)>; 1007 #endif 1008 1009 #undef __mvalue_of 1010 1011 template <class _Fn> 1012 struct __mall_of { 1013 template <class... _Args> 1014 using __f = __mand<__minvoke<_Fn, _Args>...>; 1015 }; 1016 1017 template <class _Fn> 1018 struct __mnone_of { 1019 template <class... _Args> 1020 using __f = __mand<__mnot<__minvoke<_Fn, _Args>>...>; 1021 }; 1022 1023 template <class _Fn> 1024 struct __many_of { 1025 template <class... _Args> 1026 using __f = __mor<__minvoke<_Fn, _Args>...>; 1027 }; 1028 1029 #if !STDEXEC_STD_NO_PACK_INDEXING() 1030 STDEXEC_PRAGMA_PUSH() 1031 STDEXEC_PRAGMA_IGNORE_GNU("-Wc++26-extensions") 1032 1033 template <bool> 1034 struct __m_at_ { 1035 template <class _Np, class... _Ts> 1036 using __f = _Ts...[__v<_Np>]; 1037 }; 1038 1039 template <class _Np, class... _Ts> 1040 using __m_at = __minvoke<__m_at_<__v<_Np> == ~0ul>, _Np, _Ts...>; 1041 1042 template <std::size_t _Np, class... _Ts> 1043 using __m_at_c = __minvoke<__m_at_<_Np == ~0ul>, __msize_t<_Np>, _Ts...>; 1044 1045 STDEXEC_PRAGMA_POP() 1046 #elif STDEXEC_HAS_BUILTIN(__type_pack_element) 1047 template <bool> 1048 struct __m_at_ { 1049 template <class _Np, class... _Ts> 1050 using __f = __type_pack_element<__v<_Np>, _Ts...>; 1051 }; 1052 1053 template <class _Np, class... _Ts> 1054 using __m_at = __minvoke<__m_at_<__v<_Np> == ~0ul>, _Np, _Ts...>; 1055 1056 template <std::size_t _Np, class... _Ts> 1057 using __m_at_c = __minvoke<__m_at_<_Np == ~0ul>, __msize_t<_Np>, _Ts...>; 1058 #else 1059 template <std::size_t> 1060 using __void_ptr = void *; 1061 1062 template <class _Ty> 1063 using __mtype_ptr = __mtype<_Ty> *; 1064 1065 template <class _Ty> 1066 struct __m_at_; 1067 1068 template <std::size_t... _Is> 1069 struct __m_at_<__indices<_Is...>> { 1070 template <class _Up, class... _Us> 1071 static _Up __f_(__void_ptr<_Is>..., _Up *, _Us *...); 1072 template <class... _Ts> 1073 using __f = __t<decltype(__m_at_::__f_(__mtype_ptr<_Ts>()...))>; 1074 }; 1075 1076 template <std::size_t _Np, class... _Ts> 1077 using __m_at_c = __minvoke<__m_at_<__make_indices<_Np>>, _Ts...>; 1078 1079 template <class _Np, class... _Ts> 1080 using __m_at = __m_at_c<__v<_Np>, _Ts...>; 1081 #endif 1082 1083 template <class... _Ts> 1084 using __mback = __m_at_c<sizeof...(_Ts) - 1, _Ts...>; 1085 1086 template <class _Continuation = __q<__types>> 1087 struct __mpop_back { 1088 template <class> 1089 struct __impl; 1090 1091 template <std::size_t... _Idx> 1092 struct __impl<__indices<_Idx...>> { 1093 template <class... _Ts> 1094 using __f = __minvoke<_Continuation, __m_at_c<_Idx, _Ts...>...>; 1095 }; 1096 1097 template <class... _Ts> 1098 requires(sizeof...(_Ts) != 0) 1099 using __f = __minvoke<__impl<__make_indices<sizeof...(_Ts) - 1>>, _Ts...>; 1100 }; 1101 1102 template <std::size_t _Np> 1103 struct __placeholder { 1104 __placeholder() = default; 1105 __placeholderstdexec::__placeholder1106 constexpr __placeholder(void *) noexcept { 1107 } 1108 __get_placeholder_offset(__placeholder)1109 constexpr friend auto __get_placeholder_offset(__placeholder) noexcept -> std::size_t { 1110 return _Np; 1111 } 1112 }; 1113 1114 using __0 = __placeholder<0>; 1115 using __1 = __placeholder<1>; 1116 using __2 = __placeholder<2>; 1117 using __3 = __placeholder<3>; 1118 1119 #if defined(__cpp_pack_indexing) 1120 STDEXEC_PRAGMA_PUSH() 1121 STDEXEC_PRAGMA_IGNORE_GNU("-Wc++26-extensions") 1122 1123 template <std::size_t _Np> 1124 struct __nth_pack_element_t { 1125 template <class... _Ts> STDEXEC_ATTRIBUTEstdexec::__nth_pack_element_t1126 STDEXEC_ATTRIBUTE(always_inline) 1127 constexpr auto operator()(_Ts &&...__ts) const noexcept -> decltype(auto) { 1128 static_assert(_Np < sizeof...(_Ts)); 1129 return static_cast<_Ts...[_Np] &&>(__ts...[_Np]); 1130 } 1131 }; 1132 STDEXEC_PRAGMA_POP()1133 STDEXEC_PRAGMA_POP() 1134 #else 1135 template <class... _Ignore> 1136 struct __nth_pack_element_impl { 1137 template <class _Ty, class... _Us> 1138 STDEXEC_ATTRIBUTE(always_inline) 1139 constexpr _Ty &&operator()(_Ignore..., _Ty &&__t, _Us &&...) const noexcept { 1140 return static_cast<decltype(__t) &&>(__t); 1141 } 1142 }; 1143 1144 template <std::size_t _Np> 1145 struct __nth_pack_element_t { 1146 template <std::size_t... _Is> 1147 STDEXEC_ATTRIBUTE(always_inline) 1148 static constexpr auto __impl(__indices<_Is...>) noexcept { 1149 return __nth_pack_element_impl<__ignore_t<_Is>...>(); 1150 } 1151 1152 template <class... _Ts> 1153 STDEXEC_ATTRIBUTE(always_inline) 1154 constexpr decltype(auto) operator()(_Ts &&...__ts) const noexcept { 1155 static_assert(_Np < sizeof...(_Ts)); 1156 return __impl(__make_indices<_Np>())(static_cast<_Ts &&>(__ts)...); 1157 } 1158 }; 1159 #endif 1160 1161 template <std::size_t _Np> 1162 inline constexpr __nth_pack_element_t<_Np> __nth_pack_element{}; 1163 1164 template <auto... _Vs> 1165 struct __mliterals { 1166 template <std::size_t _Np> STDEXEC_ATTRIBUTEstdexec::__mliterals1167 STDEXEC_ATTRIBUTE(always_inline) 1168 static constexpr auto __nth() noexcept { 1169 return stdexec::__nth_pack_element<_Np>(_Vs...); 1170 } 1171 }; 1172 1173 template <std::size_t _Np> 1174 struct __nth_member { 1175 template <class _Ty> STDEXEC_ATTRIBUTEstdexec::__nth_member1176 STDEXEC_ATTRIBUTE(always_inline) 1177 constexpr auto operator()(_Ty &&__ty) const noexcept -> decltype(auto) { 1178 return static_cast<_Ty &&>(__ty).*(__ty.__mbrs_.template __nth<_Np>()); 1179 } 1180 }; 1181 1182 template <class _Set, class... _Ty> 1183 concept __mset_contains = (STDEXEC_IS_BASE_OF(__mtype<_Ty>, _Set) && ...); 1184 1185 struct __mset_nil; 1186 1187 namespace __set { 1188 template <class... _Ts> 1189 struct __inherit : __mtype<__mset_nil> { 1190 template <template <class...> class _Fn> 1191 using rebind = _Fn<_Ts...>; 1192 }; 1193 1194 template <class _Ty, class... _Ts> 1195 struct __inherit<_Ty, _Ts...> 1196 : __mtype<_Ty> 1197 , __inherit<_Ts...> { 1198 template <template <class...> class _Fn> 1199 using rebind = _Fn<_Ty, _Ts...>; 1200 }; 1201 1202 template <class... _Set> 1203 auto operator+(__inherit<_Set...> &) -> __inherit<_Set...>; 1204 1205 template <class... _Set, class _Ty> 1206 auto operator%(__inherit<_Set...> &, __mtype<_Ty> &) -> __if_c< 1207 __mset_contains<__inherit<_Set...>, _Ty>, 1208 __inherit<_Set...>, 1209 __inherit<_Ty, _Set...> 1210 > &; 1211 1212 template <class _ExpectedSet, class... _Ts> 1213 concept __mset_eq = (sizeof...(_Ts) == __v<__mapply<__msize, _ExpectedSet>>) 1214 && __mset_contains<_ExpectedSet, _Ts...>; 1215 1216 template <class _ExpectedSet> 1217 struct __eq { 1218 template <class... _Ts> 1219 using __f = __mbool<__mset_eq<_ExpectedSet, _Ts...>>; 1220 }; 1221 } // namespace __set 1222 1223 template <class... _Ts> 1224 using __mset = __set::__inherit<_Ts...>; 1225 1226 template <class _Set, class... _Ts> 1227 using __mset_insert = decltype(+(__declval<_Set &>() % ... % __declval<__mtype<_Ts> &>())); 1228 1229 template <class... _Ts> 1230 using __mmake_set = __mset_insert<__mset<>, _Ts...>; 1231 1232 template <class _Set1, class _Set2> 1233 concept __mset_eq = __v<__mapply<__set::__eq<_Set1>, _Set2>>; 1234 1235 template <class _Continuation = __q<__types>> 1236 struct __munique { 1237 template <class... _Ts> 1238 using __f = __mapply<_Continuation, __mmake_set<_Ts...>>; 1239 }; 1240 } // namespace stdexec 1241