/* * Copyright (c) 2021-2024 NVIDIA Corporation * * Licensed under the Apache License Version 2.0 with LLVM Exceptions * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://llvm.org/LICENSE.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "__detail/__config.hpp" #include "__detail/__meta.hpp" #include "__detail/__tag_invoke.hpp" #include "concepts.hpp" #include #include #include #include namespace stdexec { template struct __composed { STDEXEC_ATTRIBUTE((no_unique_address)) _Fun0 __t0_; STDEXEC_ATTRIBUTE((no_unique_address)) _Fun1 __t1_; template requires __callable<_Fun1, _Ts...> && __callable<_Fun0, __call_result_t<_Fun1, _Ts...>> STDEXEC_ATTRIBUTE((always_inline)) __call_result_t<_Fun0, __call_result_t<_Fun1, _Ts...>> operator()( _Ts&&... __ts) && { return static_cast<_Fun0&&>(__t0_)( static_cast<_Fun1&&>(__t1_)(static_cast<_Ts&&>(__ts)...)); } template requires __callable && __callable> STDEXEC_ATTRIBUTE((always_inline)) __call_result_t<_Fun0, __call_result_t<_Fun1, _Ts...>> operator()( _Ts&&... __ts) const& { return __t0_(__t1_(static_cast<_Ts&&>(__ts)...)); } }; inline constexpr struct __compose_t { template STDEXEC_ATTRIBUTE((always_inline)) __composed<_Fun0, _Fun1> operator()(_Fun0 __fun0, _Fun1 __fun1) const { return {static_cast<_Fun0&&>(__fun0), static_cast<_Fun1&&>(__fun1)}; } } __compose{}; namespace __invoke_ { template inline constexpr bool __is_refwrap = false; template inline constexpr bool __is_refwrap> = true; struct __funobj { template STDEXEC_ATTRIBUTE((always_inline)) constexpr auto operator()(_Fun&& __fun, _Args&&... __args) const noexcept( noexcept((static_cast<_Fun&&>(__fun))(static_cast<_Args&&>(__args)...))) -> decltype((static_cast<_Fun&&>(__fun))( static_cast<_Args&&>(__args)...)) { return static_cast<_Fun&&>(__fun)(static_cast<_Args&&>(__args)...); } }; struct __memfn { template STDEXEC_ATTRIBUTE((always_inline)) constexpr auto operator()(_Memptr __mem_ptr, _Ty&& __ty, _Args&&... __args) const noexcept(noexcept(((static_cast<_Ty&&>(__ty)).* __mem_ptr)(static_cast<_Args&&>(__args)...))) -> decltype(((static_cast<_Ty&&>(__ty)).* __mem_ptr)(static_cast<_Args&&>(__args)...)) { return ((static_cast<_Ty&&>(__ty)).*__mem_ptr)( static_cast<_Args&&>(__args)...); } }; struct __memfn_refwrap { template STDEXEC_ATTRIBUTE((always_inline)) constexpr auto operator()(_Memptr __mem_ptr, _Ty __ty, _Args&&... __args) const noexcept(noexcept((__ty.get().* __mem_ptr)(static_cast<_Args&&>(__args)...))) -> decltype((__ty.get().* __mem_ptr)(static_cast<_Args&&>(__args)...)) { return (__ty.get().*__mem_ptr)(static_cast<_Args&&>(__args)...); } }; struct __memfn_smartptr { template STDEXEC_ATTRIBUTE((always_inline)) constexpr auto operator()(_Memptr __mem_ptr, _Ty&& __ty, _Args&&... __args) const noexcept(noexcept(((*static_cast<_Ty&&>(__ty)).* __mem_ptr)(static_cast<_Args&&>(__args)...))) -> decltype(((*static_cast<_Ty&&>(__ty)).* __mem_ptr)(static_cast<_Args&&>(__args)...)) { return ((*static_cast<_Ty&&>(__ty)).*__mem_ptr)( static_cast<_Args&&>(__args)...); } }; struct __memobj { template STDEXEC_ATTRIBUTE((always_inline)) constexpr auto operator()(_Mbr _Class::* __mem_ptr, _Ty&& __ty) const noexcept -> decltype(((static_cast<_Ty&&>(__ty)).*__mem_ptr)) { return ((static_cast<_Ty&&>(__ty)).*__mem_ptr); } }; struct __memobj_refwrap { template STDEXEC_ATTRIBUTE((always_inline)) constexpr auto operator()(_Mbr _Class::* __mem_ptr, _Ty __ty) const noexcept -> decltype((__ty.get().*__mem_ptr)) { return (__ty.get().*__mem_ptr); } }; struct __memobj_smartptr { template STDEXEC_ATTRIBUTE((always_inline)) constexpr auto operator()(_Mbr _Class::* __mem_ptr, _Ty&& __ty) const noexcept -> decltype(((*static_cast<_Ty&&>(__ty)).*__mem_ptr)) { return ((*static_cast<_Ty&&>(__ty)).*__mem_ptr); } }; auto __invoke_selector(__ignore, __ignore) noexcept -> __funobj; template auto __invoke_selector(_Mbr _Class::*, const _Ty&) noexcept { if constexpr (STDEXEC_IS_CONST(_Mbr) || STDEXEC_IS_CONST(const _Mbr)) { // member function ptr case if constexpr (STDEXEC_IS_BASE_OF(_Class, _Ty)) { return __memobj{}; } else if constexpr (__is_refwrap<_Ty>) { return __memobj_refwrap{}; } else { return __memobj_smartptr{}; } } else { // member object ptr case if constexpr (STDEXEC_IS_BASE_OF(_Class, _Ty)) { return __memfn{}; } else if constexpr (__is_refwrap<_Ty>) { return __memfn_refwrap{}; } else { return __memfn_smartptr{}; } } } struct __invoke_t { template STDEXEC_ATTRIBUTE((always_inline)) constexpr auto operator()(_Fun&& __fun) const noexcept(noexcept((static_cast<_Fun&&>(__fun))())) -> decltype((static_cast<_Fun&&>(__fun))()) { return static_cast<_Fun&&>(__fun)(); } template STDEXEC_ATTRIBUTE((always_inline)) constexpr auto operator()(_Fun&& __fun, _Ty&& __ty, _Args&&... __args) const noexcept(noexcept(__invoke_selector(__fun, __ty)( static_cast<_Fun&&>(__fun), static_cast<_Ty&&>(__ty), static_cast<_Args&&>(__args)...))) -> decltype(__invoke_selector(__fun, __ty)( static_cast<_Fun&&>(__fun), static_cast<_Ty&&>(__ty), static_cast<_Args&&>(__args)...)) { return decltype(__invoke_selector(__fun, __ty))()( static_cast<_Fun&&>(__fun), static_cast<_Ty&&>(__ty), static_cast<_Args&&>(__args)...); } }; } // namespace __invoke_ inline constexpr __invoke_::__invoke_t __invoke{}; template concept __invocable = // requires(_Fun&& __f, _As&&... __as) { __invoke(static_cast<_Fun&&>(__f), static_cast<_As&&>(__as)...); }; template concept __nothrow_invocable = // __invocable<_Fun, _As...> && // requires(_Fun&& __f, _As&&... __as) { { __invoke(static_cast<_Fun&&>(__f), static_cast<_As&&>(__as)...) } noexcept; }; template using __invoke_result_t = // decltype(__invoke(__declval<_Fun>(), __declval<_As>()...)); namespace __apply_ { using std::get; template STDEXEC_ATTRIBUTE((always_inline)) constexpr auto __impl(__indices<_Is...>, _Fn&& __fn, _Tup&& __tup) // noexcept(noexcept(__invoke(static_cast<_Fn&&>(__fn), get<_Is>(static_cast<_Tup&&>(__tup))...))) -> decltype(__invoke(static_cast<_Fn&&>(__fn), get<_Is>(static_cast<_Tup&&>(__tup))...)) { return __invoke(static_cast<_Fn&&>(__fn), get<_Is>(static_cast<_Tup&&>(__tup))...); } template using __tuple_indices = __make_indices>::value>; template using __result_t = decltype(__apply_::__impl( __tuple_indices<_Tup>(), __declval<_Fn>(), __declval<_Tup>())); } // namespace __apply_ template concept __applicable = __mvalid<__apply_::__result_t, _Fn, _Tup>; template concept __nothrow_applicable = __applicable<_Fn, _Tup> // && // noexcept(__apply_::__impl(__apply_::__tuple_indices<_Tup>(), __declval<_Fn>(), __declval<_Tup>())); template requires __applicable<_Fn, _Tup> using __apply_result_t = __apply_::__result_t<_Fn, _Tup>; struct __apply_t { template requires __applicable<_Fn, _Tup> STDEXEC_ATTRIBUTE((always_inline)) constexpr auto operator()(_Fn&& __fn, _Tup&& __tup) const noexcept(__nothrow_applicable<_Fn, _Tup>) -> __apply_result_t<_Fn, _Tup> { return __apply_::__impl(__apply_::__tuple_indices<_Tup>(), static_cast<_Fn&&>(__fn), static_cast<_Tup&&>(__tup)); } }; inline constexpr __apply_t __apply{}; template struct __field { STDEXEC_ATTRIBUTE((always_inline)) _Ty operator()(_Tag) const noexcept(__nothrow_decay_copyable) { return __t_; } _Ty __t_; }; template struct __mkfield_ { template STDEXEC_ATTRIBUTE((always_inline)) __field<_Tag, __decay_t<_Ty>> operator()(_Ty&& __ty) const noexcept(__nothrow_decay_copyable<_Ty>) { return {static_cast<_Ty&&>(__ty)}; } }; template inline constexpr __mkfield_<_Tag> __mkfield{}; } // namespace stdexec