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 "__execution_fwd.hpp" 19 20 // include these after __execution_fwd.hpp 21 #include "__concepts.hpp" 22 #include "__env.hpp" 23 #include "__senders_core.hpp" 24 #include "__tag_invoke.hpp" 25 26 namespace stdexec { 27 ///////////////////////////////////////////////////////////////////////////// 28 // [execution.senders.schedule] 29 namespace __sched { 30 template <class _Scheduler> 31 concept __has_schedule_member = requires(_Scheduler&& __sched) { 32 static_cast<_Scheduler &&>(__sched).schedule(); 33 }; 34 35 struct schedule_t { 36 template <class _Scheduler> 37 requires __has_schedule_member<_Scheduler> STDEXEC_ATTRIBUTEstdexec::__sched::schedule_t38 STDEXEC_ATTRIBUTE(host, device, always_inline) 39 auto operator()(_Scheduler&& __sched) const 40 noexcept(noexcept(static_cast<_Scheduler&&>(__sched).schedule())) 41 -> decltype(static_cast<_Scheduler&&>(__sched).schedule()) { 42 static_assert( 43 sender<decltype(static_cast<_Scheduler&&>(__sched).schedule())>, 44 "schedule() member functions must return a sender"); 45 return static_cast<_Scheduler&&>(__sched).schedule(); 46 } 47 48 template <class _Scheduler> 49 requires(!__has_schedule_member<_Scheduler>) && tag_invocable<schedule_t, _Scheduler> STDEXEC_ATTRIBUTEstdexec::__sched::schedule_t50 STDEXEC_ATTRIBUTE(host, device, always_inline) 51 auto operator()(_Scheduler&& __sched) const 52 noexcept(nothrow_tag_invocable<schedule_t, _Scheduler>) 53 -> tag_invoke_result_t<schedule_t, _Scheduler> { 54 static_assert(sender<tag_invoke_result_t<schedule_t, _Scheduler>>); 55 return tag_invoke(*this, static_cast<_Scheduler&&>(__sched)); 56 } 57 querystdexec::__sched::schedule_t58 static constexpr auto query(forwarding_query_t) noexcept -> bool { 59 return false; 60 } 61 }; 62 } // namespace __sched 63 64 using __sched::schedule_t; 65 inline constexpr schedule_t schedule{}; 66 67 struct scheduler_t { }; 68 69 template <class _Scheduler> 70 concept __has_schedule = requires(_Scheduler&& __sched) { 71 { schedule(static_cast<_Scheduler &&>(__sched)) } -> sender; 72 }; 73 74 template <class _Scheduler> 75 concept __sender_has_completion_scheduler = requires(_Scheduler&& __sched) { 76 { 77 stdexec::__decay_copy( 78 get_completion_scheduler<set_value_t>( 79 get_env(schedule(static_cast<_Scheduler &&>(__sched))))) 80 } -> same_as<__decay_t<_Scheduler>>; 81 }; 82 83 template <class _Scheduler> 84 concept scheduler = __has_schedule<_Scheduler> && __sender_has_completion_scheduler<_Scheduler> 85 && equality_comparable<__decay_t<_Scheduler>> 86 && copy_constructible<__decay_t<_Scheduler>>; 87 88 template <scheduler _Scheduler> 89 using schedule_result_t = __call_result_t<schedule_t, _Scheduler>; 90 91 template <class _SchedulerProvider> 92 concept __scheduler_provider = requires(const _SchedulerProvider& __sp) { 93 { get_scheduler(__sp) } -> scheduler; 94 }; 95 96 namespace __queries { 97 template <class _Env> STDEXEC_ATTRIBUTE(always_inline,host,device)98 STDEXEC_ATTRIBUTE(always_inline, host, device) 99 constexpr void get_scheduler_t::__validate() noexcept { 100 static_assert(__nothrow_callable<get_scheduler_t, const _Env&>); 101 static_assert(scheduler<__call_result_t<get_scheduler_t, const _Env&>>); 102 } 103 104 template <class _Env> STDEXEC_ATTRIBUTE(always_inline,host,device)105 STDEXEC_ATTRIBUTE(always_inline, host, device) 106 constexpr void get_delegation_scheduler_t::__validate() noexcept { 107 static_assert(__nothrow_callable<get_delegation_scheduler_t, const _Env&>); 108 static_assert(scheduler<__call_result_t<get_delegation_scheduler_t, const _Env&>>); 109 } 110 111 template <__completion_tag _Tag> 112 template <class _Env> STDEXEC_ATTRIBUTE(always_inline,host,device)113 STDEXEC_ATTRIBUTE(always_inline, host, device) 114 constexpr void get_completion_scheduler_t<_Tag>::__validate() noexcept { 115 static_assert(__nothrow_callable<get_completion_scheduler_t<_Tag>, const _Env&>); 116 static_assert(scheduler<__call_result_t<get_completion_scheduler_t<_Tag>, const _Env&>>); 117 } 118 } // namespace __queries 119 } // namespace stdexec 120