14c2d73ddSPatrick Williams /*
25cee9157SPatrick Williams  * Copyright (c) 2021-2024 NVIDIA Corporation
34c2d73ddSPatrick Williams  *
44c2d73ddSPatrick Williams  * Licensed under the Apache License Version 2.0 with LLVM Exceptions
54c2d73ddSPatrick Williams  * (the "License"); you may not use this file except in compliance with
64c2d73ddSPatrick Williams  * the License. You may obtain a copy of the License at
74c2d73ddSPatrick Williams  *
84c2d73ddSPatrick Williams  *   https://llvm.org/LICENSE.txt
94c2d73ddSPatrick Williams  *
104c2d73ddSPatrick Williams  * Unless required by applicable law or agreed to in writing, software
114c2d73ddSPatrick Williams  * distributed under the License is distributed on an "AS IS" BASIS,
124c2d73ddSPatrick Williams  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134c2d73ddSPatrick Williams  * See the License for the specific language governing permissions and
144c2d73ddSPatrick Williams  * limitations under the License.
154c2d73ddSPatrick Williams  */
164c2d73ddSPatrick Williams #pragma once
174c2d73ddSPatrick Williams 
184c2d73ddSPatrick Williams #include "__concepts.hpp"
195cee9157SPatrick Williams #include "__cpo.hpp"
204c2d73ddSPatrick Williams #include "__execution_fwd.hpp"
218723a542SPatrick Williams #include "__meta.hpp"
225cee9157SPatrick Williams #include "__stop_token.hpp"
235cee9157SPatrick Williams #include "__tag_invoke.hpp"
245cee9157SPatrick Williams #include "__tuple.hpp"
254c2d73ddSPatrick Williams 
268723a542SPatrick Williams #include <exception>
275cee9157SPatrick Williams #include <functional>
288723a542SPatrick Williams #include <type_traits>
294c2d73ddSPatrick Williams 
304c2d73ddSPatrick Williams STDEXEC_PRAGMA_PUSH()
314c2d73ddSPatrick Williams STDEXEC_PRAGMA_IGNORE_EDG(probable_guiding_friend)
324c2d73ddSPatrick Williams STDEXEC_PRAGMA_IGNORE_EDG(type_qualifiers_ignored_on_reference)
334c2d73ddSPatrick Williams 
344c2d73ddSPatrick Williams namespace stdexec
354c2d73ddSPatrick Williams {
364c2d73ddSPatrick Williams // [exec.queries.queryable]
374c2d73ddSPatrick Williams template <class T>
384c2d73ddSPatrick Williams concept queryable = destructible<T>;
394c2d73ddSPatrick Williams 
404c2d73ddSPatrick Williams template <class Tag>
414c2d73ddSPatrick Williams struct __query
424c2d73ddSPatrick Williams {
434c2d73ddSPatrick Williams     template <class Sig>
444c2d73ddSPatrick Williams     static inline constexpr Tag (*signature)(Sig) = nullptr;
454c2d73ddSPatrick Williams };
464c2d73ddSPatrick Williams 
474c2d73ddSPatrick Williams //////////////////////////////////////////////////////////////////////////////////////////////////
484c2d73ddSPatrick Williams // [exec.queries]
494c2d73ddSPatrick Williams namespace __queries
504c2d73ddSPatrick Williams {
515cee9157SPatrick Williams template <class _Tp>
525cee9157SPatrick Williams concept __is_bool_constant = //
535cee9157SPatrick Williams     requires {               //
545cee9157SPatrick Williams         typename __mbool<_Tp::value>;
555cee9157SPatrick Williams     };
565cee9157SPatrick Williams 
574c2d73ddSPatrick Williams struct forwarding_query_t
584c2d73ddSPatrick Williams {
594c2d73ddSPatrick Williams     template <class _Query>
operator ()stdexec::__queries::forwarding_query_t605cee9157SPatrick Williams     consteval auto operator()(_Query __query) const noexcept -> bool
614c2d73ddSPatrick Williams     {
624c2d73ddSPatrick Williams         if constexpr (tag_invocable<forwarding_query_t, _Query>)
634c2d73ddSPatrick Williams         {
645cee9157SPatrick Williams             using __result_t = tag_invoke_result_t<forwarding_query_t, _Query>;
655cee9157SPatrick Williams             // If this a integral type wrapper, unpack it and return the value.
665cee9157SPatrick Williams             // Otherwise, return the result of the tag_invoke call expression.
675cee9157SPatrick Williams             if constexpr (__is_bool_constant<__result_t>)
685cee9157SPatrick Williams             {
695cee9157SPatrick Williams                 return __result_t::value;
705cee9157SPatrick Williams             }
715cee9157SPatrick Williams             else
725cee9157SPatrick Williams             {
736e675883SPatrick Williams                 return tag_invoke(*this, static_cast<_Query&&>(__query));
744c2d73ddSPatrick Williams             }
755cee9157SPatrick Williams         }
765cee9157SPatrick Williams         else if constexpr (derived_from<_Query, forwarding_query_t>)
774c2d73ddSPatrick Williams         {
784c2d73ddSPatrick Williams             return true;
794c2d73ddSPatrick Williams         }
804c2d73ddSPatrick Williams         else
814c2d73ddSPatrick Williams         {
824c2d73ddSPatrick Williams             return false;
834c2d73ddSPatrick Williams         }
844c2d73ddSPatrick Williams     }
854c2d73ddSPatrick Williams };
864c2d73ddSPatrick Williams 
874c2d73ddSPatrick Williams struct query_or_t
884c2d73ddSPatrick Williams {
894c2d73ddSPatrick Williams     template <class _Query, class _Queryable, class _Default>
operator ()stdexec::__queries::query_or_t904c2d73ddSPatrick Williams     constexpr auto operator()(_Query, _Queryable&&, _Default&& __default) const
914c2d73ddSPatrick Williams         noexcept(__nothrow_constructible_from<_Default, _Default&&>) -> _Default
924c2d73ddSPatrick Williams     {
936e675883SPatrick Williams         return static_cast<_Default&&>(__default);
944c2d73ddSPatrick Williams     }
954c2d73ddSPatrick Williams 
964c2d73ddSPatrick Williams     template <class _Query, class _Queryable, class _Default>
974c2d73ddSPatrick Williams         requires __callable<_Query, _Queryable>
operator ()stdexec::__queries::query_or_t984c2d73ddSPatrick Williams     constexpr auto operator()(_Query __query, _Queryable&& __queryable,
994c2d73ddSPatrick Williams                               _Default&&) const
1004c2d73ddSPatrick Williams         noexcept(__nothrow_callable<_Query, _Queryable>)
1014c2d73ddSPatrick Williams             -> __call_result_t<_Query, _Queryable>
1024c2d73ddSPatrick Williams     {
1036e675883SPatrick Williams         return static_cast<_Query&&>(__query)(
1046e675883SPatrick Williams             static_cast<_Queryable&&>(__queryable));
1054c2d73ddSPatrick Williams     }
1064c2d73ddSPatrick Williams };
1074c2d73ddSPatrick Williams 
1084c2d73ddSPatrick Williams struct execute_may_block_caller_t : __query<execute_may_block_caller_t>
1094c2d73ddSPatrick Williams {
1104c2d73ddSPatrick Williams     template <class _Tp>
1114c2d73ddSPatrick Williams         requires tag_invocable<execute_may_block_caller_t, __cref_t<_Tp>>
operator ()stdexec::__queries::execute_may_block_caller_t1126e675883SPatrick Williams     constexpr auto operator()(_Tp&& __t) const noexcept -> bool
1134c2d73ddSPatrick Williams     {
1144c2d73ddSPatrick Williams         static_assert(
1154c2d73ddSPatrick Williams             same_as<bool, tag_invoke_result_t<execute_may_block_caller_t,
1164c2d73ddSPatrick Williams                                               __cref_t<_Tp>>>);
1174c2d73ddSPatrick Williams         static_assert(
1184c2d73ddSPatrick Williams             nothrow_tag_invocable<execute_may_block_caller_t, __cref_t<_Tp>>);
1194c2d73ddSPatrick Williams         return tag_invoke(execute_may_block_caller_t{}, std::as_const(__t));
1204c2d73ddSPatrick Williams     }
1214c2d73ddSPatrick Williams 
operator ()stdexec::__queries::execute_may_block_caller_t1226e675883SPatrick Williams     constexpr auto operator()(auto&&) const noexcept -> bool
1234c2d73ddSPatrick Williams     {
1244c2d73ddSPatrick Williams         return true;
1254c2d73ddSPatrick Williams     }
1264c2d73ddSPatrick Williams };
1274c2d73ddSPatrick Williams 
1284c2d73ddSPatrick Williams struct get_forward_progress_guarantee_t :
1294c2d73ddSPatrick Williams     __query<get_forward_progress_guarantee_t>
1304c2d73ddSPatrick Williams {
1314c2d73ddSPatrick Williams     template <class _Tp>
1324c2d73ddSPatrick Williams         requires tag_invocable<get_forward_progress_guarantee_t, __cref_t<_Tp>>
operator ()stdexec::__queries::get_forward_progress_guarantee_t1334c2d73ddSPatrick Williams     constexpr auto operator()(_Tp&& __t) const noexcept(
1344c2d73ddSPatrick Williams         nothrow_tag_invocable<get_forward_progress_guarantee_t, __cref_t<_Tp>>)
1355cee9157SPatrick Williams         -> __decay_t<tag_invoke_result_t<get_forward_progress_guarantee_t,
1365cee9157SPatrick Williams                                          __cref_t<_Tp>>>
1374c2d73ddSPatrick Williams     {
1384c2d73ddSPatrick Williams         return tag_invoke(get_forward_progress_guarantee_t{},
1394c2d73ddSPatrick Williams                           std::as_const(__t));
1404c2d73ddSPatrick Williams     }
1414c2d73ddSPatrick Williams 
142*06f265f6SPatrick Williams     constexpr auto
operator ()stdexec::__queries::get_forward_progress_guarantee_t143*06f265f6SPatrick Williams         operator()(auto&&) const noexcept -> stdexec::forward_progress_guarantee
1444c2d73ddSPatrick Williams     {
1454c2d73ddSPatrick Williams         return stdexec::forward_progress_guarantee::weakly_parallel;
1464c2d73ddSPatrick Williams     }
1474c2d73ddSPatrick Williams };
1484c2d73ddSPatrick Williams 
1494c2d73ddSPatrick Williams struct __has_algorithm_customizations_t :
1504c2d73ddSPatrick Williams     __query<__has_algorithm_customizations_t>
1514c2d73ddSPatrick Williams {
1524c2d73ddSPatrick Williams     template <class _Tp>
1534c2d73ddSPatrick Williams     using __result_t =
1544c2d73ddSPatrick Williams         tag_invoke_result_t<__has_algorithm_customizations_t, __cref_t<_Tp>>;
1554c2d73ddSPatrick Williams 
1564c2d73ddSPatrick Williams     template <class _Tp>
1574c2d73ddSPatrick Williams         requires tag_invocable<__has_algorithm_customizations_t, __cref_t<_Tp>>
operator ()stdexec::__queries::__has_algorithm_customizations_t158*06f265f6SPatrick Williams     constexpr auto operator()(_Tp&&) const
159*06f265f6SPatrick Williams         noexcept(noexcept(__result_t<_Tp>{})) -> __result_t<_Tp>
1604c2d73ddSPatrick Williams     {
1614c2d73ddSPatrick Williams         using _Boolean = tag_invoke_result_t<__has_algorithm_customizations_t,
1624c2d73ddSPatrick Williams                                              __cref_t<_Tp>>;
1634c2d73ddSPatrick Williams         static_assert(_Boolean{}
1644c2d73ddSPatrick Williams                           ? true
1656e675883SPatrick Williams                           : false); // must be contextually convertible to bool
1664c2d73ddSPatrick Williams         return _Boolean{};
1674c2d73ddSPatrick Williams     }
1684c2d73ddSPatrick Williams 
operator ()stdexec::__queries::__has_algorithm_customizations_t1696e675883SPatrick Williams     constexpr auto operator()(auto&&) const noexcept -> std::false_type
1704c2d73ddSPatrick Williams     {
1714c2d73ddSPatrick Williams         return {};
1724c2d73ddSPatrick Williams     }
1734c2d73ddSPatrick Williams };
1744c2d73ddSPatrick Williams 
1754c2d73ddSPatrick Williams // TODO: implement allocator concept
1764c2d73ddSPatrick Williams template <class _T0>
1774c2d73ddSPatrick Williams concept __allocator_c = true;
1784c2d73ddSPatrick Williams 
1794c2d73ddSPatrick Williams struct get_scheduler_t : __query<get_scheduler_t>
1804c2d73ddSPatrick Williams {
querystdexec::__queries::get_scheduler_t1815cee9157SPatrick Williams     static constexpr auto query(forwarding_query_t) noexcept -> bool
1824c2d73ddSPatrick Williams     {
1834c2d73ddSPatrick Williams         return true;
1844c2d73ddSPatrick Williams     }
1854c2d73ddSPatrick Williams 
1864c2d73ddSPatrick Williams     template <class _Env>
1874c2d73ddSPatrick Williams         requires tag_invocable<get_scheduler_t, const _Env&>
1884c2d73ddSPatrick Williams     auto operator()(const _Env& __env) const noexcept
1894c2d73ddSPatrick Williams         -> tag_invoke_result_t<get_scheduler_t, const _Env&>;
1904c2d73ddSPatrick Williams 
1916e675883SPatrick Williams     template <class _Tag = get_scheduler_t>
1924c2d73ddSPatrick Williams     auto operator()() const noexcept;
1934c2d73ddSPatrick Williams };
1944c2d73ddSPatrick Williams 
1954c2d73ddSPatrick Williams struct get_delegatee_scheduler_t : __query<get_delegatee_scheduler_t>
1964c2d73ddSPatrick Williams {
querystdexec::__queries::get_delegatee_scheduler_t1975cee9157SPatrick Williams     static constexpr auto query(forwarding_query_t) noexcept -> bool
1984c2d73ddSPatrick Williams     {
1994c2d73ddSPatrick Williams         return true;
2004c2d73ddSPatrick Williams     }
2014c2d73ddSPatrick Williams 
2024c2d73ddSPatrick Williams     template <class _Env>
2034c2d73ddSPatrick Williams         requires tag_invocable<get_delegatee_scheduler_t, const _Env&>
2044c2d73ddSPatrick Williams     auto operator()(const _Env& __t) const noexcept
2054c2d73ddSPatrick Williams         -> tag_invoke_result_t<get_delegatee_scheduler_t, const _Env&>;
2064c2d73ddSPatrick Williams 
2076e675883SPatrick Williams     template <class _Tag = get_delegatee_scheduler_t>
2084c2d73ddSPatrick Williams     auto operator()() const noexcept;
2094c2d73ddSPatrick Williams };
2104c2d73ddSPatrick Williams 
2114c2d73ddSPatrick Williams struct get_allocator_t : __query<get_allocator_t>
2124c2d73ddSPatrick Williams {
querystdexec::__queries::get_allocator_t2135cee9157SPatrick Williams     static constexpr auto query(forwarding_query_t) noexcept -> bool
2144c2d73ddSPatrick Williams     {
2154c2d73ddSPatrick Williams         return true;
2164c2d73ddSPatrick Williams     }
2174c2d73ddSPatrick Williams 
2184c2d73ddSPatrick Williams     template <class _Env>
2194c2d73ddSPatrick Williams         requires tag_invocable<get_allocator_t, const _Env&>
operator ()stdexec::__queries::get_allocator_t2204c2d73ddSPatrick Williams     auto operator()(const _Env& __env) const noexcept
2214c2d73ddSPatrick Williams         -> tag_invoke_result_t<get_allocator_t, const _Env&>
2224c2d73ddSPatrick Williams     {
2234c2d73ddSPatrick Williams         static_assert(nothrow_tag_invocable<get_allocator_t, const _Env&>);
2244c2d73ddSPatrick Williams         static_assert(
2254c2d73ddSPatrick Williams             __allocator_c<tag_invoke_result_t<get_allocator_t, const _Env&>>);
2264c2d73ddSPatrick Williams         return tag_invoke(get_allocator_t{}, __env);
2274c2d73ddSPatrick Williams     }
2284c2d73ddSPatrick Williams 
2296e675883SPatrick Williams     template <class _Tag = get_allocator_t>
2304c2d73ddSPatrick Williams     auto operator()() const noexcept;
2314c2d73ddSPatrick Williams };
2324c2d73ddSPatrick Williams 
2334c2d73ddSPatrick Williams struct get_stop_token_t : __query<get_stop_token_t>
2344c2d73ddSPatrick Williams {
querystdexec::__queries::get_stop_token_t2355cee9157SPatrick Williams     static constexpr auto query(forwarding_query_t) noexcept -> bool
2364c2d73ddSPatrick Williams     {
2374c2d73ddSPatrick Williams         return true;
2384c2d73ddSPatrick Williams     }
2394c2d73ddSPatrick Williams 
2405cee9157SPatrick Williams     template <class _Env, class _Token = never_stop_token>
operator ()stdexec::__queries::get_stop_token_t2415cee9157SPatrick Williams     auto operator()(const _Env&) const noexcept -> _Token
2424c2d73ddSPatrick Williams     {
2434c2d73ddSPatrick Williams         return {};
2444c2d73ddSPatrick Williams     }
2454c2d73ddSPatrick Williams 
2465cee9157SPatrick Williams     template <class _Env, class = void>
2474c2d73ddSPatrick Williams         requires tag_invocable<get_stop_token_t, const _Env&>
operator ()stdexec::__queries::get_stop_token_t2484c2d73ddSPatrick Williams     auto operator()(const _Env& __env) const noexcept
2494c2d73ddSPatrick Williams         -> tag_invoke_result_t<get_stop_token_t, const _Env&>
2504c2d73ddSPatrick Williams     {
2514c2d73ddSPatrick Williams         static_assert(nothrow_tag_invocable<get_stop_token_t, const _Env&>);
2525cee9157SPatrick Williams         static_assert(
2535cee9157SPatrick Williams             stoppable_token<
2545cee9157SPatrick Williams                 __decay_t<tag_invoke_result_t<get_stop_token_t, const _Env&>>>);
2554c2d73ddSPatrick Williams         return tag_invoke(get_stop_token_t{}, __env);
2564c2d73ddSPatrick Williams     }
2574c2d73ddSPatrick Williams 
2586e675883SPatrick Williams     template <class _Tag = get_stop_token_t>
2594c2d73ddSPatrick Williams     auto operator()() const noexcept;
2604c2d73ddSPatrick Williams };
2614c2d73ddSPatrick Williams 
2625cee9157SPatrick Williams template <class _Queryable, class _Tag>
2634c2d73ddSPatrick Williams concept __has_completion_scheduler_for =
2644c2d73ddSPatrick Williams     queryable<_Queryable> && //
2655cee9157SPatrick Williams     tag_invocable<get_completion_scheduler_t<_Tag>, const _Queryable&>;
2664c2d73ddSPatrick Williams 
2675cee9157SPatrick Williams template <__completion_tag _Tag>
2685cee9157SPatrick Williams struct get_completion_scheduler_t : __query<get_completion_scheduler_t<_Tag>>
2694c2d73ddSPatrick Williams {
querystdexec::__queries::get_completion_scheduler_t2705cee9157SPatrick Williams     static constexpr auto query(forwarding_query_t) noexcept -> bool
2714c2d73ddSPatrick Williams     {
2724c2d73ddSPatrick Williams         return true;
2734c2d73ddSPatrick Williams     }
2744c2d73ddSPatrick Williams 
2755cee9157SPatrick Williams     template <__has_completion_scheduler_for<_Tag> _Queryable>
2764c2d73ddSPatrick Williams     auto operator()(const _Queryable& __queryable) const noexcept
2775cee9157SPatrick Williams         -> tag_invoke_result_t<get_completion_scheduler_t<_Tag>,
2784c2d73ddSPatrick Williams                                const _Queryable&>;
2794c2d73ddSPatrick Williams };
2804c2d73ddSPatrick Williams 
2814c2d73ddSPatrick Williams struct get_domain_t
2824c2d73ddSPatrick Williams {
2834c2d73ddSPatrick Williams     template <class _Ty>
2844c2d73ddSPatrick Williams         requires tag_invocable<get_domain_t, const _Ty&>
operator ()stdexec::__queries::get_domain_t2854c2d73ddSPatrick Williams     constexpr auto operator()(const _Ty& __ty) const noexcept
2865cee9157SPatrick Williams         -> __decay_t<tag_invoke_result_t<get_domain_t, const _Ty&>>
2874c2d73ddSPatrick Williams     {
2884c2d73ddSPatrick Williams         static_assert(nothrow_tag_invocable<get_domain_t, const _Ty&>,
2894c2d73ddSPatrick Williams                       "Customizations of get_domain must be noexcept.");
2905cee9157SPatrick Williams         static_assert(
2915cee9157SPatrick Williams             __class<__decay_t<tag_invoke_result_t<get_domain_t, const _Ty&>>>,
2924c2d73ddSPatrick Williams             "Customizations of get_domain must return a class type.");
2935cee9157SPatrick Williams         return {};
2944c2d73ddSPatrick Williams     }
2954c2d73ddSPatrick Williams 
querystdexec::__queries::get_domain_t2965cee9157SPatrick Williams     static constexpr auto query(forwarding_query_t) noexcept -> bool
2975cee9157SPatrick Williams     {
2985cee9157SPatrick Williams         return true;
2995cee9157SPatrick Williams     }
3005cee9157SPatrick Williams };
3015cee9157SPatrick Williams 
3025cee9157SPatrick Williams struct __is_scheduler_affine_t
3035cee9157SPatrick Williams {
3045cee9157SPatrick Williams     template <class _Env>
operator ()stdexec::__queries::__is_scheduler_affine_t3055cee9157SPatrick Williams     constexpr auto operator()(const _Env&) const noexcept
3065cee9157SPatrick Williams     {
3075cee9157SPatrick Williams         if constexpr (tag_invocable<__is_scheduler_affine_t, const _Env&>)
3085cee9157SPatrick Williams         {
3095cee9157SPatrick Williams             using _Result =
3105cee9157SPatrick Williams                 tag_invoke_result_t<__is_scheduler_affine_t, const _Env&>;
3115cee9157SPatrick Williams             static_assert(__same_as<decltype(__v<_Result>), const bool>);
3125cee9157SPatrick Williams             return _Result();
3135cee9157SPatrick Williams         }
3145cee9157SPatrick Williams         else
3155cee9157SPatrick Williams         {
3165cee9157SPatrick Williams             return std::false_type();
3175cee9157SPatrick Williams         }
3185cee9157SPatrick Williams     }
3195cee9157SPatrick Williams 
querystdexec::__queries::__is_scheduler_affine_t3205cee9157SPatrick Williams     static constexpr auto query(forwarding_query_t) noexcept -> bool
3215cee9157SPatrick Williams     {
3225cee9157SPatrick Williams         return false;
3235cee9157SPatrick Williams     }
3245cee9157SPatrick Williams };
3255cee9157SPatrick Williams 
3265cee9157SPatrick Williams struct __root_t
3275cee9157SPatrick Williams {
3285cee9157SPatrick Williams     template <class _Env>
3295cee9157SPatrick Williams         requires tag_invocable<__root_t, const _Env&>
operator ()stdexec::__queries::__root_t3305cee9157SPatrick Williams     constexpr auto operator()(const _Env& __env) const noexcept -> bool
3315cee9157SPatrick Williams     {
3325cee9157SPatrick Williams         STDEXEC_ASSERT(tag_invoke(__root_t{}, __env) == true);
3335cee9157SPatrick Williams         return true;
3345cee9157SPatrick Williams     }
3355cee9157SPatrick Williams 
querystdexec::__queries::__root_t3365cee9157SPatrick Williams     static constexpr auto query(forwarding_query_t) noexcept -> bool
3375cee9157SPatrick Williams     {
3385cee9157SPatrick Williams         return false;
3395cee9157SPatrick Williams     }
3405cee9157SPatrick Williams };
3415cee9157SPatrick Williams 
3425cee9157SPatrick Williams struct __root_env
3435cee9157SPatrick Williams {
3445cee9157SPatrick Williams     using __t = __root_env;
3455cee9157SPatrick Williams     using __id = __root_env;
3465cee9157SPatrick Williams 
STDEXEC_MEMFN_DECLstdexec::__queries::__root_env3475cee9157SPatrick Williams     constexpr STDEXEC_MEMFN_DECL(auto __root)(this const __root_env&) noexcept
3486e675883SPatrick Williams         -> bool
3494c2d73ddSPatrick Williams     {
3504c2d73ddSPatrick Williams         return true;
3514c2d73ddSPatrick Williams     }
3524c2d73ddSPatrick Williams };
3534c2d73ddSPatrick Williams } // namespace __queries
3544c2d73ddSPatrick Williams 
3554c2d73ddSPatrick Williams using __queries::__has_algorithm_customizations_t;
3565cee9157SPatrick Williams using __queries::__is_scheduler_affine_t;
3575cee9157SPatrick Williams using __queries::__root_env;
3585cee9157SPatrick Williams using __queries::__root_t;
3594c2d73ddSPatrick Williams using __queries::execute_may_block_caller_t;
3604c2d73ddSPatrick Williams using __queries::forwarding_query_t;
3614c2d73ddSPatrick Williams using __queries::get_allocator_t;
3624c2d73ddSPatrick Williams using __queries::get_completion_scheduler_t;
3634c2d73ddSPatrick Williams using __queries::get_delegatee_scheduler_t;
3644c2d73ddSPatrick Williams using __queries::get_domain_t;
3654c2d73ddSPatrick Williams using __queries::get_forward_progress_guarantee_t;
3664c2d73ddSPatrick Williams using __queries::get_scheduler_t;
3674c2d73ddSPatrick Williams using __queries::get_stop_token_t;
3684c2d73ddSPatrick Williams using __queries::query_or_t;
3694c2d73ddSPatrick Williams 
3704c2d73ddSPatrick Williams inline constexpr forwarding_query_t forwarding_query{};
3714c2d73ddSPatrick Williams inline constexpr query_or_t query_or{}; // NOT TO SPEC
3724c2d73ddSPatrick Williams inline constexpr execute_may_block_caller_t execute_may_block_caller{};
3734c2d73ddSPatrick Williams inline constexpr __has_algorithm_customizations_t
3744c2d73ddSPatrick Williams     __has_algorithm_customizations{};
3754c2d73ddSPatrick Williams inline constexpr get_forward_progress_guarantee_t
3764c2d73ddSPatrick Williams     get_forward_progress_guarantee{};
3774c2d73ddSPatrick Williams inline constexpr get_scheduler_t get_scheduler{};
3784c2d73ddSPatrick Williams inline constexpr get_delegatee_scheduler_t get_delegatee_scheduler{};
3794c2d73ddSPatrick Williams inline constexpr get_allocator_t get_allocator{};
3804c2d73ddSPatrick Williams inline constexpr get_stop_token_t get_stop_token{};
3814c2d73ddSPatrick Williams #if !STDEXEC_GCC() || defined(__OPTIMIZE_SIZE__)
3825cee9157SPatrick Williams template <__completion_tag _Tag>
3835cee9157SPatrick Williams inline constexpr get_completion_scheduler_t<_Tag> get_completion_scheduler{};
3844c2d73ddSPatrick Williams #else
3854c2d73ddSPatrick Williams template <>
3864c2d73ddSPatrick Williams inline constexpr get_completion_scheduler_t<set_value_t>
3874c2d73ddSPatrick Williams     get_completion_scheduler<set_value_t>{};
3884c2d73ddSPatrick Williams template <>
3894c2d73ddSPatrick Williams inline constexpr get_completion_scheduler_t<set_error_t>
3904c2d73ddSPatrick Williams     get_completion_scheduler<set_error_t>{};
3914c2d73ddSPatrick Williams template <>
3924c2d73ddSPatrick Williams inline constexpr get_completion_scheduler_t<set_stopped_t>
3934c2d73ddSPatrick Williams     get_completion_scheduler<set_stopped_t>{};
3944c2d73ddSPatrick Williams #endif
3954c2d73ddSPatrick Williams 
3964c2d73ddSPatrick Williams template <class _Tag>
3974c2d73ddSPatrick Williams concept __forwarding_query = forwarding_query(_Tag{});
3984c2d73ddSPatrick Williams 
3994c2d73ddSPatrick Williams inline constexpr get_domain_t get_domain{};
4004c2d73ddSPatrick Williams 
4015cee9157SPatrick Williams template <class _Env>
4025cee9157SPatrick Williams using __domain_of_t = __decay_t<__call_result_t<get_domain_t, _Env>>;
4035cee9157SPatrick Williams 
4044c2d73ddSPatrick Williams template <class _Tag, class _Queryable, class _Default>
4054c2d73ddSPatrick Williams using __query_result_or_t =
4064c2d73ddSPatrick Williams     __call_result_t<query_or_t, _Tag, _Queryable, _Default>;
4074c2d73ddSPatrick Williams 
4084c2d73ddSPatrick Williams namespace __env
4094c2d73ddSPatrick Williams {
4101f7438aaSPatrick Williams // To be kept in sync with the promise type used in __connect_awaitable
4111f7438aaSPatrick Williams template <class _Env>
4121f7438aaSPatrick Williams struct __promise
4131f7438aaSPatrick Williams {
4141f7438aaSPatrick Williams     template <class _Ty>
await_transformstdexec::__env::__promise4156e675883SPatrick Williams     auto await_transform(_Ty&& __value) noexcept -> _Ty&&
4161f7438aaSPatrick Williams     {
4176e675883SPatrick Williams         return static_cast<_Ty&&>(__value);
4181f7438aaSPatrick Williams     }
4191f7438aaSPatrick Williams 
4201f7438aaSPatrick Williams     template <class _Ty>
4211f7438aaSPatrick Williams         requires tag_invocable<as_awaitable_t, _Ty, __promise&>
await_transformstdexec::__env::__promise4221f7438aaSPatrick Williams     auto await_transform(_Ty&& __value) //
4231f7438aaSPatrick Williams         noexcept(nothrow_tag_invocable<as_awaitable_t, _Ty, __promise&>)
4241f7438aaSPatrick Williams             -> tag_invoke_result_t<as_awaitable_t, _Ty, __promise&>
4251f7438aaSPatrick Williams     {
4266e675883SPatrick Williams         return tag_invoke(as_awaitable, static_cast<_Ty&&>(__value), *this);
4271f7438aaSPatrick Williams     }
4281f7438aaSPatrick Williams 
4295cee9157SPatrick Williams     auto get_env() const noexcept -> const _Env&;
4301f7438aaSPatrick Williams };
4311f7438aaSPatrick Williams 
4325cee9157SPatrick Williams template <class _Env, class _Query, class... _Args>
4335cee9157SPatrick Williams concept __queryable = //
4345cee9157SPatrick Williams     tag_invocable<_Query, const _Env&, _Args...>;
4355cee9157SPatrick Williams 
4365cee9157SPatrick Williams template <class _Env, class _Query, class... _Args>
4375cee9157SPatrick Williams concept __nothrow_queryable = //
4385cee9157SPatrick Williams     nothrow_tag_invocable<_Query, const _Env&, _Args...>;
4395cee9157SPatrick Williams 
4405cee9157SPatrick Williams template <class _Env, class _Query, class... _Args>
4415cee9157SPatrick Williams using __query_result_t = //
4425cee9157SPatrick Williams     tag_invoke_result_t<_Query, const _Env&, _Args...>;
4435cee9157SPatrick Williams 
4445cee9157SPatrick Williams // A singleton environment from a query/value pair
4455cee9157SPatrick Williams template <class _Query, class _Value>
4465cee9157SPatrick Williams struct prop
4475cee9157SPatrick Williams {
4485cee9157SPatrick Williams     using __t = prop;
4495cee9157SPatrick Williams     using __id = prop;
4505cee9157SPatrick Williams 
4515cee9157SPatrick Williams     STDEXEC_ATTRIBUTE((no_unique_address))
4525cee9157SPatrick Williams     _Query __query;
4535cee9157SPatrick Williams 
4545cee9157SPatrick Williams     STDEXEC_ATTRIBUTE((no_unique_address))
4555cee9157SPatrick Williams     _Value __value;
4565cee9157SPatrick Williams 
4575cee9157SPatrick Williams     STDEXEC_ATTRIBUTE((nodiscard))
querystdexec::__env::prop4585cee9157SPatrick Williams     constexpr const _Value& query(_Query) const noexcept
4595cee9157SPatrick Williams     {
4605cee9157SPatrick Williams         return __value;
4615cee9157SPatrick Williams     }
4625cee9157SPatrick Williams 
4635cee9157SPatrick Williams     prop& operator=(const prop&) = delete;
4645cee9157SPatrick Williams };
4655cee9157SPatrick Williams 
4665cee9157SPatrick Williams template <class _Query, class _Value>
4675cee9157SPatrick Williams prop(_Query, _Value) -> prop<_Query, std::unwrap_reference_t<_Value>>;
4685cee9157SPatrick Williams 
4695cee9157SPatrick Williams // utility for joining multiple environments
4705cee9157SPatrick Williams template <class... _Envs>
4715cee9157SPatrick Williams struct env
4725cee9157SPatrick Williams {
4735cee9157SPatrick Williams     using __t = env;
4745cee9157SPatrick Williams     using __id = env;
4755cee9157SPatrick Williams 
4765cee9157SPatrick Williams     __tuple_for<_Envs...> __tup_;
4775cee9157SPatrick Williams 
4785cee9157SPatrick Williams     // return a reference to the first child env for which
4795cee9157SPatrick Williams     // __queryable<_Envs, _Query, _Args...> is true.
4805cee9157SPatrick Williams     template <class _Query, class... _Args>
4815cee9157SPatrick Williams     STDEXEC_ATTRIBUTE((always_inline))
__get_1ststdexec::__env::env4825cee9157SPatrick Williams     constexpr decltype(auto) __get_1st() const noexcept
4835cee9157SPatrick Williams     {
4845cee9157SPatrick Williams         constexpr bool __flags[] = {__queryable<_Envs, _Query, _Args...>...};
485*06f265f6SPatrick Williams         constexpr std::size_t __idx =
486*06f265f6SPatrick Williams             __pos_of(__flags, __flags + sizeof...(_Envs));
4875cee9157SPatrick Williams         return __tup::get<__idx>(__tup_);
4885cee9157SPatrick Williams     }
4895cee9157SPatrick Williams 
4905cee9157SPatrick Williams     template <class _Query, class... _Args>
4915cee9157SPatrick Williams         requires(__queryable<_Envs, _Query, _Args...> || ...)
492*06f265f6SPatrick Williams     STDEXEC_ATTRIBUTE((always_inline))
querystdexec::__env::env493*06f265f6SPatrick Williams     constexpr decltype(auto) query(_Query __q, _Args&&... __args) const
4945cee9157SPatrick Williams         noexcept(__nothrow_queryable<decltype(__get_1st<_Query, _Args...>()),
4955cee9157SPatrick Williams                                      _Query, _Args...>)
4965cee9157SPatrick Williams     {
4975cee9157SPatrick Williams         return tag_invoke(__q, __get_1st<_Query, _Args...>(),
4985cee9157SPatrick Williams                           static_cast<_Args&&>(__args)...);
4995cee9157SPatrick Williams     }
5005cee9157SPatrick Williams 
5015cee9157SPatrick Williams     env& operator=(const env&) = delete;
5025cee9157SPatrick Williams };
5035cee9157SPatrick Williams 
5045cee9157SPatrick Williams // specialization for two envs to avoid warnings about elided braces
5055cee9157SPatrick Williams template <class _Env0, class _Env1>
5065cee9157SPatrick Williams struct env<_Env0, _Env1>
5075cee9157SPatrick Williams {
5085cee9157SPatrick Williams     using __t = env;
5095cee9157SPatrick Williams     using __id = env;
5105cee9157SPatrick Williams 
5115cee9157SPatrick Williams     STDEXEC_ATTRIBUTE((no_unique_address))
5125cee9157SPatrick Williams     _Env0 __env0_;
5135cee9157SPatrick Williams     STDEXEC_ATTRIBUTE((no_unique_address))
5145cee9157SPatrick Williams     _Env1 __env1_;
5155cee9157SPatrick Williams 
5165cee9157SPatrick Williams     // return a reference to the first child env for which
5175cee9157SPatrick Williams     // __queryable<_Envs, _Query, _Args...> is true.
5185cee9157SPatrick Williams     template <class _Query, class... _Args>
5195cee9157SPatrick Williams     STDEXEC_ATTRIBUTE((always_inline))
__get_1ststdexec::__env::env5205cee9157SPatrick Williams     constexpr decltype(auto) __get_1st() const noexcept
5215cee9157SPatrick Williams     {
5225cee9157SPatrick Williams         if constexpr (__queryable<_Env0, _Query, _Args...>)
5235cee9157SPatrick Williams         {
5245cee9157SPatrick Williams             return (__env0_);
5255cee9157SPatrick Williams         }
5265cee9157SPatrick Williams         else
5275cee9157SPatrick Williams         {
5285cee9157SPatrick Williams             return (__env1_);
5295cee9157SPatrick Williams         }
5305cee9157SPatrick Williams     }
5315cee9157SPatrick Williams 
5325cee9157SPatrick Williams     template <class _Query, class... _Args>
5335cee9157SPatrick Williams         requires __queryable<_Env0, _Query, _Args...> ||
5345cee9157SPatrick Williams                  __queryable<_Env1, _Query, _Args...>
535*06f265f6SPatrick Williams     STDEXEC_ATTRIBUTE((always_inline))
536*06f265f6SPatrick Williams     constexpr decltype(auto) query(_Query __q, _Args&&... __args) const
5375cee9157SPatrick Williams         noexcept(__nothrow_queryable<decltype(__get_1st<_Query, _Args...>()),
5385cee9157SPatrick Williams                                      _Query, _Args...>)
5395cee9157SPatrick Williams     {
5405cee9157SPatrick Williams         return tag_invoke(__q, __get_1st<_Query, _Args...>(),
5415cee9157SPatrick Williams                           static_cast<_Args&&>(__args)...);
5425cee9157SPatrick Williams     }
5435cee9157SPatrick Williams 
5445cee9157SPatrick Williams     env& operator=(const env&) = delete;
5455cee9157SPatrick Williams };
5465cee9157SPatrick Williams 
5475cee9157SPatrick Williams template <class... _Envs>
5485cee9157SPatrick Williams env(_Envs...) -> env<std::unwrap_reference_t<_Envs>...>;
5495cee9157SPatrick Williams 
5501f7438aaSPatrick Williams template <class _Value, class _Tag, class... _Tags>
5511f7438aaSPatrick Williams struct __with
5521f7438aaSPatrick Williams {
5531f7438aaSPatrick Williams     using __t = __with;
5541f7438aaSPatrick Williams     using __id = __with;
5556e675883SPatrick Williams     STDEXEC_ATTRIBUTE((no_unique_address))
5566e675883SPatrick Williams     _Value __value_;
5571f7438aaSPatrick Williams 
5588723a542SPatrick Williams     __with() = default;
5598723a542SPatrick Williams 
__withstdexec::__env::__with5608723a542SPatrick Williams     constexpr explicit __with(_Value __value) noexcept(
5611f7438aaSPatrick Williams         __nothrow_decay_copyable<_Value>) :
5626e675883SPatrick Williams         __value_(static_cast<_Value&&>(__value))
5631f7438aaSPatrick Williams     {}
5641f7438aaSPatrick Williams 
__withstdexec::__env::__with5651f7438aaSPatrick Williams     constexpr explicit __with(_Value __value, _Tag, _Tags...) noexcept(
5661f7438aaSPatrick Williams         __nothrow_decay_copyable<_Value>) :
5676e675883SPatrick Williams         __value_(static_cast<_Value&&>(__value))
5681f7438aaSPatrick Williams     {}
5691f7438aaSPatrick Williams 
5701f7438aaSPatrick Williams     template <__one_of<_Tag, _Tags...> _Key>
querystdexec::__env::__with5715cee9157SPatrick Williams     auto query(_Key) const noexcept -> const _Value&
5721f7438aaSPatrick Williams     {
5735cee9157SPatrick Williams         return __value_;
5741f7438aaSPatrick Williams     }
5755cee9157SPatrick Williams 
5765cee9157SPatrick Williams     __with& operator=(const __with&) = delete;
5771f7438aaSPatrick Williams };
5781f7438aaSPatrick Williams 
5791f7438aaSPatrick Williams template <class _Value, class _Tag, class... _Tags>
5801f7438aaSPatrick Williams __with(_Value, _Tag, _Tags...) -> __with<_Value, _Tag, _Tags...>;
5811f7438aaSPatrick Williams 
5825cee9157SPatrick Williams template <class _EnvId>
5831f7438aaSPatrick Williams struct __fwd
5841f7438aaSPatrick Williams {
5855cee9157SPatrick Williams     using _Env = __cvref_t<_EnvId>;
5861f7438aaSPatrick Williams     static_assert(__nothrow_move_constructible<_Env>);
5875cee9157SPatrick Williams 
5885cee9157SPatrick Williams     struct __t
5895cee9157SPatrick Williams     {
5901f7438aaSPatrick Williams         using __id = __fwd;
5916e675883SPatrick Williams         STDEXEC_ATTRIBUTE((no_unique_address))
5926e675883SPatrick Williams         _Env __env_;
5931f7438aaSPatrick Williams 
5945cee9157SPatrick Williams #if STDEXEC_GCC() && __GNUC__ < 12
5955cee9157SPatrick Williams         using __cvref_env_t = std::add_const_t<_Env>&;
5965cee9157SPatrick Williams #else
5975cee9157SPatrick Williams         using __cvref_env_t = const _Env&;
5985cee9157SPatrick Williams #endif
5995cee9157SPatrick Williams 
6001f7438aaSPatrick Williams         template <__forwarding_query _Tag>
6015cee9157SPatrick Williams             requires tag_invocable<_Tag, __cvref_env_t>
querystdexec::__env::__fwd::__t6025cee9157SPatrick Williams         auto query(_Tag) const
6035cee9157SPatrick Williams             noexcept(nothrow_tag_invocable<_Tag, __cvref_env_t>)
6045cee9157SPatrick Williams                 -> tag_invoke_result_t<_Tag, __cvref_env_t>
6051f7438aaSPatrick Williams         {
6065cee9157SPatrick Williams             return tag_invoke(_Tag(), __env_);
6075cee9157SPatrick Williams         }
6085cee9157SPatrick Williams 
6095cee9157SPatrick Williams         __t& operator=(const __t&) = delete;
6105cee9157SPatrick Williams     };
6115cee9157SPatrick Williams };
6125cee9157SPatrick Williams 
6135cee9157SPatrick Williams struct __fwd_fn
6145cee9157SPatrick Williams {
6155cee9157SPatrick Williams     template <class _Env>
operator ()stdexec::__env::__fwd_fn6165cee9157SPatrick Williams     auto operator()(_Env&& __env) const
6175cee9157SPatrick Williams     {
6185cee9157SPatrick Williams         return __t<__fwd<__cvref_id<_Env>>>{static_cast<_Env&&>(__env)};
6195cee9157SPatrick Williams     }
6205cee9157SPatrick Williams 
operator ()stdexec::__env::__fwd_fn6215cee9157SPatrick Williams     auto operator()(empty_env) const -> empty_env
6225cee9157SPatrick Williams     {
6235cee9157SPatrick Williams         return {};
6241f7438aaSPatrick Williams     }
6251f7438aaSPatrick Williams };
6261f7438aaSPatrick Williams 
6275cee9157SPatrick Williams template <class _EnvId, class _Tag>
6285cee9157SPatrick Williams struct __without_
6298723a542SPatrick Williams {
6305cee9157SPatrick Williams     using _Env = __cvref_t<_EnvId>;
6318723a542SPatrick Williams     static_assert(__nothrow_move_constructible<_Env>);
6325cee9157SPatrick Williams 
6335cee9157SPatrick Williams     struct __t
6345cee9157SPatrick Williams     {
6358723a542SPatrick Williams         using __id = __without_;
6365cee9157SPatrick Williams         _Env __env_;
6378723a542SPatrick Williams 
6385cee9157SPatrick Williams #if STDEXEC_GCC() && __GNUC__ < 12
6395cee9157SPatrick Williams         using __cvref_env_t = std::add_const_t<_Env>&;
6405cee9157SPatrick Williams #else
6415cee9157SPatrick Williams         using __cvref_env_t = const _Env&;
6425cee9157SPatrick Williams #endif
6438723a542SPatrick Williams 
6445cee9157SPatrick Williams         auto query(_Tag) const noexcept = delete;
6455cee9157SPatrick Williams 
6465cee9157SPatrick Williams         template <tag_invocable<__cvref_env_t> _Key>
6475cee9157SPatrick Williams         STDEXEC_ATTRIBUTE((always_inline))
querystdexec::__env::__without_::__t648*06f265f6SPatrick Williams         auto query(_Key) const noexcept(
649*06f265f6SPatrick Williams             nothrow_tag_invocable<_Key, __cvref_env_t>) -> decltype(auto)
6505cee9157SPatrick Williams         {
6515cee9157SPatrick Williams             return tag_invoke(_Key(), __env_);
6525cee9157SPatrick Williams         }
6535cee9157SPatrick Williams 
6545cee9157SPatrick Williams         __t& operator=(const __t&) = delete;
6555cee9157SPatrick Williams     };
6568723a542SPatrick Williams };
6578723a542SPatrick Williams 
6588723a542SPatrick Williams struct __without_fn
6598723a542SPatrick Williams {
6605cee9157SPatrick Williams     template <class _Env, class _Tag>
operator ()stdexec::__env::__without_fn661*06f265f6SPatrick Williams     constexpr auto operator()(_Env&& __env,
662*06f265f6SPatrick Williams                               _Tag) const noexcept -> decltype(auto)
6638723a542SPatrick Williams     {
6645cee9157SPatrick Williams         if constexpr (tag_invocable<_Tag, _Env>)
6658723a542SPatrick Williams         {
6665cee9157SPatrick Williams             using _Without = __t<__without_<__cvref_id<_Env>, _Tag>>;
6675cee9157SPatrick Williams             return _Without{static_cast<_Env&&>(__env)};
6688723a542SPatrick Williams         }
6698723a542SPatrick Williams         else
6708723a542SPatrick Williams         {
6716e675883SPatrick Williams             return static_cast<_Env>(static_cast<_Env&&>(__env));
6728723a542SPatrick Williams         }
6738723a542SPatrick Williams     }
6748723a542SPatrick Williams };
6758723a542SPatrick Williams 
6768723a542SPatrick Williams inline constexpr __without_fn __without{};
6778723a542SPatrick Williams 
6788723a542SPatrick Williams template <class _Env, class _Tag, class... _Tags>
6798723a542SPatrick Williams using __without_t = __result_of<__without, _Env, _Tag, _Tags...>;
6808723a542SPatrick Williams 
6811f7438aaSPatrick Williams template <__nothrow_move_constructible _Fun>
6821f7438aaSPatrick Williams struct __from
6831f7438aaSPatrick Williams {
6841f7438aaSPatrick Williams     using __t = __from;
6851f7438aaSPatrick Williams     using __id = __from;
6866e675883SPatrick Williams     STDEXEC_ATTRIBUTE((no_unique_address))
6876e675883SPatrick Williams     _Fun __fun_;
6881f7438aaSPatrick Williams 
6891f7438aaSPatrick Williams     template <class _Tag>
6901f7438aaSPatrick Williams         requires __callable<const _Fun&, _Tag>
querystdexec::__env::__from6915cee9157SPatrick Williams     auto query(_Tag) const noexcept(__nothrow_callable<const _Fun&, _Tag>)
6921f7438aaSPatrick Williams         -> __call_result_t<const _Fun&, _Tag>
6931f7438aaSPatrick Williams     {
6945cee9157SPatrick Williams         return __fun_(_Tag());
6951f7438aaSPatrick Williams     }
6965cee9157SPatrick Williams 
6975cee9157SPatrick Williams     __from& operator=(const __from&) = delete;
6981f7438aaSPatrick Williams };
6991f7438aaSPatrick Williams 
7001f7438aaSPatrick Williams template <class _Fun>
7011f7438aaSPatrick Williams __from(_Fun) -> __from<_Fun>;
7021f7438aaSPatrick Williams 
7031f7438aaSPatrick Williams struct __join_fn
7041f7438aaSPatrick Williams {
operator ()stdexec::__env::__join_fn7055cee9157SPatrick Williams     auto operator()(empty_env, empty_env) const noexcept -> empty_env
7061f7438aaSPatrick Williams     {
7071f7438aaSPatrick Williams         return {};
7081f7438aaSPatrick Williams     }
7091f7438aaSPatrick Williams 
7101f7438aaSPatrick Williams     template <class _Env>
operator ()stdexec::__env::__join_fn7115cee9157SPatrick Williams     auto operator()(_Env&& __env, empty_env = {}) const noexcept -> _Env
7121f7438aaSPatrick Williams     {
7136e675883SPatrick Williams         return static_cast<_Env&&>(__env);
7141f7438aaSPatrick Williams     }
7151f7438aaSPatrick Williams 
7161f7438aaSPatrick Williams     template <class _Env>
operator ()stdexec::__env::__join_fn7175cee9157SPatrick Williams     auto operator()(empty_env, _Env&& __env) const noexcept -> decltype(auto)
7181f7438aaSPatrick Williams     {
7195cee9157SPatrick Williams         return __fwd_fn()(static_cast<_Env&&>(__env));
7201f7438aaSPatrick Williams     }
7211f7438aaSPatrick Williams 
7225cee9157SPatrick Williams     template <class _First, class _Second>
operator ()stdexec::__env::__join_fn7235cee9157SPatrick Williams     auto operator()(_First&& __first, _Second&& __second) const noexcept
7245cee9157SPatrick Williams         -> env<_First, __call_result_t<__fwd_fn, _Second>>
7251f7438aaSPatrick Williams     {
7265cee9157SPatrick Williams         return {static_cast<_First&&>(__first),
7275cee9157SPatrick Williams                 __fwd_fn()(static_cast<_Second&&>(__second))};
7281f7438aaSPatrick Williams     }
7291f7438aaSPatrick Williams };
7301f7438aaSPatrick Williams 
7311f7438aaSPatrick Williams inline constexpr __join_fn __join{};
7321f7438aaSPatrick Williams 
7335cee9157SPatrick Williams template <class _First, class... _Second>
7345cee9157SPatrick Williams using __join_t = __result_of<__join, _First, _Second...>;
7355cee9157SPatrick Williams 
7365cee9157SPatrick Williams struct __as_root_env_fn
7375cee9157SPatrick Williams {
7385cee9157SPatrick Williams     template <class _Env>
operator ()stdexec::__env::__as_root_env_fn7395cee9157SPatrick Williams     constexpr auto operator()(_Env __env) const noexcept
7405cee9157SPatrick Williams         -> __join_t<__root_env, std::unwrap_reference_t<_Env>>
7415cee9157SPatrick Williams     {
7425cee9157SPatrick Williams         return __join(__root_env{},
7435cee9157SPatrick Williams                       static_cast<std::unwrap_reference_t<_Env>&&>(__env));
7445cee9157SPatrick Williams     }
7455cee9157SPatrick Williams };
7465cee9157SPatrick Williams 
7475cee9157SPatrick Williams inline constexpr __as_root_env_fn __as_root_env{};
7485cee9157SPatrick Williams 
7495cee9157SPatrick Williams template <class _Env>
7505cee9157SPatrick Williams using __as_root_env_t = __result_of<__as_root_env, _Env>;
7514c2d73ddSPatrick Williams } // namespace __env
7524c2d73ddSPatrick Williams 
7535cee9157SPatrick Williams using __env::env;
7545cee9157SPatrick Williams using __env::prop;
7555cee9157SPatrick Williams using empty_env = env<>;
7565cee9157SPatrick Williams 
7575cee9157SPatrick Williams /////////////////////////////////////////////////////////////////////////////
7585cee9157SPatrick Williams namespace __get_env
7595cee9157SPatrick Williams {
7605cee9157SPatrick Williams // For getting an execution environment from a receiver or the attributes from a
7615cee9157SPatrick Williams // sender.
7625cee9157SPatrick Williams struct get_env_t
7635cee9157SPatrick Williams {
7645cee9157SPatrick Williams     template <__same_as<get_env_t> _Self, class _EnvProvider>
7655cee9157SPatrick Williams     STDEXEC_ATTRIBUTE((always_inline))
tag_invoke(_Self,const _EnvProvider & __env_provider)7665cee9157SPatrick Williams     friend auto tag_invoke(_Self, const _EnvProvider& __env_provider) noexcept
7675cee9157SPatrick Williams         -> decltype(__env_provider.get_env())
7685cee9157SPatrick Williams     {
7695cee9157SPatrick Williams         static_assert(noexcept(__env_provider.get_env()),
7705cee9157SPatrick Williams                       "get_env() members must be noexcept");
7715cee9157SPatrick Williams         return __env_provider.get_env();
7725cee9157SPatrick Williams     }
7735cee9157SPatrick Williams 
7745cee9157SPatrick Williams     template <class _EnvProvider>
7755cee9157SPatrick Williams         requires tag_invocable<get_env_t, const _EnvProvider&>
776*06f265f6SPatrick Williams     STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__get_env::get_env_t777*06f265f6SPatrick Williams     constexpr auto operator()(const _EnvProvider& __env_provider) const noexcept
7785cee9157SPatrick Williams         -> tag_invoke_result_t<get_env_t, const _EnvProvider&>
7795cee9157SPatrick Williams     {
7805cee9157SPatrick Williams         static_assert(
7815cee9157SPatrick Williams             queryable<tag_invoke_result_t<get_env_t, const _EnvProvider&>>);
7825cee9157SPatrick Williams         static_assert(nothrow_tag_invocable<get_env_t, const _EnvProvider&>);
7835cee9157SPatrick Williams         return tag_invoke(*this, __env_provider);
7845cee9157SPatrick Williams     }
7855cee9157SPatrick Williams 
7865cee9157SPatrick Williams     template <class _EnvProvider>
operator ()stdexec::__get_env::get_env_t7875cee9157SPatrick Williams     constexpr auto operator()(const _EnvProvider&) const noexcept -> empty_env
7885cee9157SPatrick Williams     {
7895cee9157SPatrick Williams         return {};
7905cee9157SPatrick Williams     }
7915cee9157SPatrick Williams };
7925cee9157SPatrick Williams } // namespace __get_env
7935cee9157SPatrick Williams 
7945cee9157SPatrick Williams using __get_env::get_env_t;
7951f7438aaSPatrick Williams inline constexpr get_env_t get_env{};
7964c2d73ddSPatrick Williams 
7974c2d73ddSPatrick Williams template <class _EnvProvider>
7984c2d73ddSPatrick Williams concept environment_provider = //
7994c2d73ddSPatrick Williams     requires(_EnvProvider& __ep) {
800*06f265f6SPatrick Williams         { get_env(std::as_const(__ep)) } -> queryable;
8014c2d73ddSPatrick Williams     };
8025cee9157SPatrick Williams 
8035cee9157SPatrick Williams using __env::__as_root_env;
8045cee9157SPatrick Williams using __env::__as_root_env_t;
8055cee9157SPatrick Williams 
8065cee9157SPatrick Williams template <class _Env>
8075cee9157SPatrick Williams concept __is_root_env = requires(_Env&& __env) {
808*06f265f6SPatrick Williams                             { __root_t{}(__env) } -> same_as<bool>;
8095cee9157SPatrick Williams                         };
8105cee9157SPatrick Williams 
8115cee9157SPatrick Williams template <class _Sender>
8125cee9157SPatrick Williams concept __is_scheduler_affine = //
8135cee9157SPatrick Williams     requires {
8145cee9157SPatrick Williams         requires __v<
8155cee9157SPatrick Williams             __call_result_t<__is_scheduler_affine_t, env_of_t<_Sender>>>;
8165cee9157SPatrick Williams     };
8174c2d73ddSPatrick Williams } // namespace stdexec
8184c2d73ddSPatrick Williams 
8194c2d73ddSPatrick Williams STDEXEC_PRAGMA_POP()
820