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