blob: 1ec7a6e6f617302e335f4e6730c19b4bea236abd [file] [log] [blame]
/*
* Copyright (c) 2021-2022 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 "../stdexec/execution.hpp"
#ifdef __EDG__
#pragma diagnostic push
#pragma diag_suppress 1302
#endif
namespace exec
{
template <class... _TagValue>
using with_t = stdexec::__with<_TagValue...>;
namespace __detail
{
struct __with_t
{
template <class _Tag, class _Value>
with_t<_Tag, _Value> operator()(_Tag, _Value&& __val) const
{
return stdexec::__with_(_Tag(), (_Value&&)__val);
}
template <class _Tag>
with_t<_Tag> operator()(_Tag) const
{
return stdexec::__with_(_Tag());
}
};
} // namespace __detail
inline constexpr __detail::__with_t with{};
inline constexpr stdexec::__env::__make_env_t make_env{};
template <class... _Ts>
using make_env_t = stdexec::__make_env_t<_Ts...>;
namespace __read_with_default
{
using namespace stdexec;
struct read_with_default_t;
template <class _Tag, class _DefaultId, class _ReceiverId>
struct __operation : __immovable
{
using _Default = __t<_DefaultId>;
using _Receiver = __t<_ReceiverId>;
STDEXEC_NO_UNIQUE_ADDRESS _Default __default_;
_Receiver __rcvr_;
friend void tag_invoke(start_t, __operation& __self) noexcept
{
try
{
if constexpr (__callable<_Tag, env_of_t<_Receiver>>)
{
const auto& __env = get_env(__self.__rcvr_);
set_value(std::move(__self.__rcvr_), _Tag{}(__env));
}
else
{
set_value(std::move(__self.__rcvr_),
std::move(__self.__default_));
}
}
catch (...)
{
set_error(std::move(__self.__rcvr_), std::current_exception());
}
}
};
template <class _Tag, class _DefaultId>
struct __sender
{
using _Default = __t<_DefaultId>;
using is_sender = void;
STDEXEC_NO_UNIQUE_ADDRESS _Default __default_;
template <class _Env>
using __value_t = __minvoke<
__with_default<__mbind_back_q<__call_result_t, _Env>, _Default>, _Tag>;
template <class _Env>
using __default_t = __if_c<__callable<_Tag, _Env>, __ignore, _Default>;
template <class _Env>
using __completions_t =
completion_signatures<set_value_t(__value_t<_Env>),
set_error_t(std::exception_ptr)>;
template <__decays_to<__sender> _Self, class _Receiver>
requires receiver_of<_Receiver, __completions_t<env_of_t<_Receiver>>>
friend auto tag_invoke(connect_t, _Self&& __self, _Receiver __rcvr) //
noexcept(std::is_nothrow_move_constructible_v<_Receiver>)
-> __operation<_Tag, __x<__default_t<env_of_t<_Receiver>>>,
__x<_Receiver>>
{
return {{}, ((_Self&&)__self).__default_, (_Receiver&&)__rcvr};
}
friend auto tag_invoke(get_completion_signatures_t, __sender, no_env)
-> dependent_completion_signatures<no_env>;
template <__none_of<no_env> _Env>
friend auto tag_invoke(get_completion_signatures_t, __sender, _Env&&)
-> __completions_t<_Env>;
};
struct __read_with_default_t
{
template <class _Tag, class _Default>
constexpr auto operator()(_Tag, _Default&& __default) const
-> __sender<_Tag, __x<__decay_t<_Default>>>
{
return {(_Default&&)__default};
}
};
} // namespace __read_with_default
inline constexpr __read_with_default::__read_with_default_t read_with_default{};
namespace __write
{
using namespace stdexec;
struct __write_t;
template <class _ReceiverId, class _Env>
struct __operation_base
{
using _Receiver = __t<_ReceiverId>;
_Receiver __rcvr_;
const _Env __env_;
};
template <class _ReceiverId, class _Env>
struct __receiver
{
using _Receiver = stdexec::__t<_ReceiverId>;
struct __t : receiver_adaptor<__t>
{
_Receiver&& base() && noexcept
{
return (_Receiver&&)__op_->__rcvr_;
}
const _Receiver& base() const& noexcept
{
return __op_->__rcvr_;
}
auto get_env() const noexcept
-> __env::__env_join_t<const _Env&, env_of_t<_Receiver>>
{
return __env::__join_env(__op_->__env_, stdexec::get_env(base()));
}
__operation_base<_ReceiverId, _Env>* __op_;
};
};
template <class _SenderId, class _ReceiverId, class _Env>
struct __operation : __operation_base<_ReceiverId, _Env>
{
using _Sender = __t<_SenderId>;
using __base_t = __operation_base<_ReceiverId, _Env>;
using __receiver_t = __t<__receiver<_ReceiverId, _Env>>;
connect_result_t<_Sender, __receiver_t> __state_;
__operation(_Sender&& __sndr, auto&& __rcvr, auto&& __env) :
__base_t{(decltype(__rcvr))__rcvr, (decltype(__env))__env},
__state_{connect((_Sender&&)__sndr, __receiver_t{{}, this})}
{}
friend void tag_invoke(start_t, __operation& __self) noexcept
{
start(__self.__state_);
}
};
template <class _SenderId, class _Env>
struct __sender
{
using _Sender = stdexec::__t<_SenderId>;
using is_sender = void;
template <class _Receiver>
using __receiver_t = stdexec::__t<__receiver<__id<_Receiver>, _Env>>;
template <class _Self, class _Receiver>
using __operation_t = __operation<__id<__copy_cvref_t<_Self, _Sender>>,
__id<_Receiver>, _Env>;
struct __t
{
using __id = __sender;
_Sender __sndr_;
_Env __env_;
template <__decays_to<__t> _Self, receiver _Receiver>
requires sender_to<__copy_cvref_t<_Self, _Sender>,
__receiver_t<_Receiver>>
friend auto tag_invoke(connect_t, _Self&& __self, _Receiver __rcvr)
-> __operation_t<_Self, _Receiver>
{
return {((_Self&&)__self).__sndr_, (_Receiver&&)__rcvr,
((_Self&&)__self).__env_};
}
friend auto tag_invoke(stdexec::get_env_t, const __t& __self) //
noexcept(
stdexec::__nothrow_callable<stdexec::get_env_t, const _Sender&>)
-> stdexec::env_of_t<const _Sender&>
{
return stdexec::get_env(__self.__sndr_);
}
template <__decays_to<__t> _Self, class _BaseEnv>
friend auto tag_invoke(get_completion_signatures_t, _Self&&, _BaseEnv&&)
-> stdexec::__completion_signatures_of_t<
__copy_cvref_t<_Self, _Sender>,
__env::__env_join_t<_Env, _BaseEnv>>;
};
};
struct __write_t
{
template <class _Sender, class... _Funs>
using __sender_t =
__t<__sender<__id<__decay_t<_Sender>>,
__env::__env_join_t<__env::__env_fn<_Funs>...>>>;
template <__is_not_instance_of<__env::__env_fn> _Sender, class... _Funs>
requires sender<_Sender>
auto operator()(_Sender&& __sndr, __env::__env_fn<_Funs>... __withs) const
-> __sender_t<_Sender, _Funs...>
{
return {(_Sender&&)__sndr, __env::__join_env(std::move(__withs)...)};
}
template <class... _Funs>
auto operator()(__env::__env_fn<_Funs>... __withs) const
-> __binder_back<__write_t, __env::__env_fn<_Funs>...>
{
return {{}, {}, {std::move(__withs)...}};
}
};
} // namespace __write
inline constexpr __write::__write_t write{};
} // namespace exec
#ifdef __EDG__
#pragma diagnostic pop
#endif