247 lines
8.2 KiB
C++
247 lines
8.2 KiB
C++
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* 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 <unifex/config.hpp>
|
|
#include <unifex/async_trace.hpp>
|
|
#include <unifex/receiver_concepts.hpp>
|
|
#include <unifex/sender_concepts.hpp>
|
|
#include <unifex/tag_invoke.hpp>
|
|
#include <unifex/type_traits.hpp>
|
|
#include <unifex/std_concepts.hpp>
|
|
#include <unifex/bind_back.hpp>
|
|
|
|
#include <type_traits>
|
|
|
|
#include <unifex/detail/prologue.hpp>
|
|
|
|
namespace unifex
|
|
{
|
|
namespace _mat
|
|
{
|
|
template <typename Receiver>
|
|
struct _receiver {
|
|
class type;
|
|
};
|
|
template <typename Receiver>
|
|
using receiver_t = typename _receiver<remove_cvref_t<Receiver>>::type;
|
|
|
|
template <typename Receiver>
|
|
class _receiver<Receiver>::type {
|
|
public:
|
|
template(typename Receiver2)
|
|
(requires constructible_from<Receiver, Receiver2>)
|
|
explicit type(Receiver2&& receiver) noexcept(
|
|
std::is_nothrow_constructible_v<Receiver, Receiver2>)
|
|
: receiver_(static_cast<Receiver2&&>(receiver)) {}
|
|
|
|
template(typename... Values)
|
|
(requires receiver_of<Receiver, tag_t<unifex::set_value>, Values...>)
|
|
void
|
|
set_value(Values&&... values) && noexcept(
|
|
is_nothrow_receiver_of_v<Receiver, tag_t<unifex::set_value>, Values...>) {
|
|
unifex::set_value(
|
|
static_cast<Receiver&&>(receiver_),
|
|
unifex::set_value,
|
|
static_cast<Values&&>(values)...);
|
|
}
|
|
|
|
template(typename Error)
|
|
(requires receiver_of<Receiver, tag_t<unifex::set_error>, Error>)
|
|
void set_error(Error&& error) && noexcept {
|
|
if constexpr (is_nothrow_receiver_of_v<
|
|
Receiver,
|
|
tag_t<unifex::set_error>,
|
|
Error>) {
|
|
unifex::set_value(
|
|
static_cast<Receiver&&>(receiver_),
|
|
unifex::set_error,
|
|
static_cast<Error&&>(error));
|
|
} else {
|
|
UNIFEX_TRY {
|
|
unifex::set_value(
|
|
static_cast<Receiver&&>(receiver_),
|
|
unifex::set_error,
|
|
static_cast<Error&&>(error));
|
|
} UNIFEX_CATCH (...) {
|
|
unifex::set_error(
|
|
static_cast<Receiver&&>(receiver_), std::current_exception());
|
|
}
|
|
}
|
|
}
|
|
|
|
template(typename R = Receiver)
|
|
(requires receiver_of<R, tag_t<unifex::set_done>>)
|
|
void set_done() && noexcept {
|
|
if constexpr (is_nothrow_receiver_of_v<Receiver, tag_t<unifex::set_done>>) {
|
|
unifex::set_value(
|
|
static_cast<Receiver&&>(receiver_), unifex::set_done);
|
|
} else {
|
|
UNIFEX_TRY {
|
|
unifex::set_value(
|
|
static_cast<Receiver&&>(receiver_), unifex::set_done);
|
|
} UNIFEX_CATCH (...) {
|
|
unifex::set_error(
|
|
static_cast<Receiver&&>(receiver_), std::current_exception());
|
|
}
|
|
}
|
|
}
|
|
|
|
template(typename CPO, UNIFEX_DECLARE_NON_DEDUCED_TYPE(R, type))
|
|
(requires is_receiver_query_cpo_v<CPO> AND
|
|
is_callable_v<CPO, const Receiver&>)
|
|
friend auto tag_invoke(
|
|
CPO cpo,
|
|
const UNIFEX_USE_NON_DEDUCED_TYPE(R, type)& r) noexcept(is_nothrow_callable_v<
|
|
CPO,
|
|
const Receiver&>)
|
|
-> callable_result_t<CPO, const Receiver&> {
|
|
return static_cast<CPO&&>(cpo)(std::as_const(r.receiver_));
|
|
}
|
|
|
|
template <
|
|
typename Func,
|
|
UNIFEX_DECLARE_NON_DEDUCED_TYPE(CPO, tag_t<visit_continuations>),
|
|
UNIFEX_DECLARE_NON_DEDUCED_TYPE(R, type)>
|
|
friend void tag_invoke(
|
|
UNIFEX_USE_NON_DEDUCED_TYPE(CPO, tag_t<visit_continuations>),
|
|
const UNIFEX_USE_NON_DEDUCED_TYPE(R, type)& r,
|
|
Func&& func) noexcept(std::is_nothrow_invocable_v<
|
|
Func&,
|
|
const Receiver&>) {
|
|
std::invoke(func, std::as_const(r.receiver_));
|
|
}
|
|
|
|
private:
|
|
Receiver receiver_;
|
|
};
|
|
|
|
template <
|
|
template <typename...> class Variant,
|
|
template <typename...> class Tuple,
|
|
typename... ValueTuples>
|
|
struct error_variant {
|
|
template <typename... Errors>
|
|
using apply = Variant<
|
|
ValueTuples...,
|
|
Tuple<tag_t<set_error>, Errors>...,
|
|
Tuple<tag_t<set_done>>>;
|
|
};
|
|
|
|
template <
|
|
typename Source,
|
|
template <typename...> class Variant,
|
|
template <typename...> class Tuple>
|
|
struct value_types {
|
|
template <typename... Values>
|
|
using value_tuple = Tuple<tag_t<set_value>, Values...>;
|
|
|
|
template <typename... ValueTuples>
|
|
using value_variant = sender_error_types_t<
|
|
Source,
|
|
error_variant<Variant, Tuple, ValueTuples...>::template apply>;
|
|
|
|
using type =
|
|
sender_value_types_t<Source, value_variant, value_tuple>;
|
|
};
|
|
|
|
template <typename Source>
|
|
struct _sender {
|
|
class type;
|
|
};
|
|
template <typename Source>
|
|
using sender = typename _sender<remove_cvref_t<Source>>::type;
|
|
|
|
template <typename Source>
|
|
class _sender<Source>::type {
|
|
using sender = type;
|
|
public:
|
|
template <
|
|
template <typename...>
|
|
class Variant,
|
|
template <typename...>
|
|
class Tuple>
|
|
using value_types =
|
|
typename value_types<Source, Variant, Tuple>::type;
|
|
|
|
template <template <typename...> class Variant>
|
|
using error_types = Variant<std::exception_ptr>;
|
|
|
|
static constexpr bool sends_done = false;
|
|
|
|
template(typename Source2)
|
|
(requires constructible_from<Source, Source2>)
|
|
explicit type(Source2&& source) noexcept(
|
|
std::is_nothrow_constructible_v<Source, Source2>)
|
|
: source_(static_cast<Source2&&>(source)) {}
|
|
|
|
template(typename Self, typename Receiver)
|
|
(requires same_as<remove_cvref_t<Self>, type> AND
|
|
receiver<Receiver> AND
|
|
sender_to<member_t<Self, Source>, receiver_t<Receiver>>)
|
|
friend auto tag_invoke(tag_t<connect>, Self&& self, Receiver&& r) noexcept(
|
|
is_nothrow_connectable_v<member_t<Self, Source>, receiver_t<Receiver>> &&
|
|
std::is_nothrow_constructible_v<remove_cvref_t<Receiver>, Receiver>)
|
|
-> connect_result_t<member_t<Self, Source>, receiver_t<Receiver>> {
|
|
return unifex::connect(
|
|
static_cast<Self&&>(self).source_,
|
|
receiver_t<Receiver>{static_cast<Receiver&&>(r)});
|
|
}
|
|
|
|
private:
|
|
Source source_;
|
|
};
|
|
} // namespace _mat
|
|
|
|
namespace _mat_cpo {
|
|
inline const struct _fn {
|
|
private:
|
|
template <typename Source>
|
|
using _result_t =
|
|
typename conditional_t<
|
|
tag_invocable<_fn, Source>,
|
|
meta_tag_invoke_result<_fn>,
|
|
meta_quote1<_mat::sender>>::template apply<Source>;
|
|
public:
|
|
template(typename Source)
|
|
(requires tag_invocable<_fn, Source>)
|
|
auto operator()(Source&& source) const
|
|
noexcept(is_nothrow_tag_invocable_v<_fn, Source>)
|
|
-> _result_t<Source> {
|
|
return unifex::tag_invoke(_fn{}, (Source&&) source);
|
|
}
|
|
template(typename Source)
|
|
(requires (!tag_invocable<_fn, Source>))
|
|
auto operator()(Source&& source) const
|
|
noexcept(std::is_nothrow_constructible_v<_mat::sender<Source>, Source>)
|
|
-> _result_t<Source> {
|
|
return _mat::sender<Source>{(Source&&) source};
|
|
}
|
|
constexpr auto operator()() const
|
|
noexcept(is_nothrow_callable_v<
|
|
tag_t<bind_back>, _fn>)
|
|
-> bind_back_result_t<_fn> {
|
|
return bind_back(*this);
|
|
}
|
|
} materialize{};
|
|
} // namespace _mat_cpo
|
|
|
|
using _mat_cpo::materialize;
|
|
|
|
} // namespace unifex
|
|
|
|
#include <unifex/detail/epilogue.hpp>
|