AimRT/install_x64/include/unifex/sender_concepts.hpp
2025-01-12 19:51:34 +08:00

394 lines
12 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/detail/unifex_fwd.hpp>
#include <unifex/tag_invoke.hpp>
#include <unifex/type_list.hpp>
#include <unifex/type_traits.hpp>
#include <unifex/receiver_concepts.hpp>
#include <exception>
#include <tuple>
#include <type_traits>
#include <utility>
#include <unifex/detail/prologue.hpp>
namespace unifex {
struct sender_base {};
template <typename>
struct sender_traits;
/// \cond
namespace detail {
template <template <template <typename...> class, template <typename...> class> class>
struct _has_value_types;
template <template <template <typename...> class> class>
struct _has_error_types;
template <typename S>
UNIFEX_CONCEPT_FRAGMENT( //
_has_sender_types_impl, //
requires() ( //
typename (std::bool_constant<S::sends_done>),
typename (_has_value_types<S::template value_types>),
typename (_has_error_types<S::template error_types>)
));
template <typename S>
UNIFEX_CONCEPT //
_has_sender_types = //
UNIFEX_FRAGMENT(detail::_has_sender_types_impl, S);
template <typename S>
UNIFEX_CONCEPT_FRAGMENT( //
_has_bulk_sender_types_impl, //
requires() ( //
typename (std::bool_constant<S::sends_done>),
typename (_has_value_types<S::template value_types>),
typename (_has_value_types<S::template next_types>),
typename (_has_error_types<S::template error_types>)
));
template <typename S>
UNIFEX_CONCEPT //
_has_bulk_sender_types = //
UNIFEX_FRAGMENT(detail::_has_bulk_sender_types_impl, S);
struct _void_sender_traits {
template <
template <typename...> class Variant,
template <typename...> class Tuple>
using value_types = Variant<Tuple<>>;
template <template <typename...> class Variant>
using error_types = Variant<std::exception_ptr>;
static constexpr bool sends_done = true;
};
template <typename S>
struct _typed_sender_traits {
template <
template <typename...> class Variant,
template <typename...> class Tuple>
using value_types = typename S::template value_types<Variant, Tuple>;
template <template <typename...> class Variant>
using error_types = typename S::template error_types<Variant>;
static constexpr bool sends_done = S::sends_done;
};
template <typename S>
struct _typed_bulk_sender_traits : _typed_sender_traits<S> {
template <
template <typename...> class Variant,
template <typename...> class Tuple>
using next_types = typename S::template next_types<Variant, Tuple>;
};
struct _no_sender_traits {
using _unspecialized = void;
};
// Workaround for unknown MSVC (19.28.29333) bug
#ifndef _MSC_VER
template <typename S>
UNIFEX_CONCEPT_FRAGMENT( //
_not_has_sender_traits, //
requires() ( //
typename (typename sender_traits<S>::_unspecialized)
));
template <typename S>
UNIFEX_CONCEPT //
_has_sender_traits = //
(!UNIFEX_FRAGMENT(detail::_not_has_sender_traits, S));
#else
template <typename S>
inline constexpr bool _has_sender_traits =
!std::is_base_of_v<_no_sender_traits, sender_traits<S>>;
#endif
template <typename S>
constexpr auto _select_sender_traits() noexcept {
if constexpr (_has_bulk_sender_types<S>) {
return _typed_bulk_sender_traits<S>{};
} else if constexpr (_has_sender_types<S>) {
return _typed_sender_traits<S>{};
} else if constexpr (std::is_base_of_v<sender_base, S>) {
return sender_base{};
} else {
return _no_sender_traits{};
}
}
} // namespace detail
template <typename S>
struct sender_traits : decltype(detail::_select_sender_traits<S>()) {};
template <typename S>
UNIFEX_CONCEPT //
sender = //
move_constructible<remove_cvref_t<S>> &&
detail::_has_sender_traits<remove_cvref_t<S>>;
template <typename S>
UNIFEX_CONCEPT //
typed_sender = //
sender<S> && //
detail::_has_sender_types<sender_traits<remove_cvref_t<S>>>;
template <typename S>
UNIFEX_CONCEPT //
typed_bulk_sender = //
sender<S> && //
detail::_has_bulk_sender_types<sender_traits<remove_cvref_t<S>>>;
namespace _start_cpo {
inline const struct _fn {
template(typename Operation)
(requires tag_invocable<_fn, Operation&>)
auto operator()(Operation& op) const noexcept
-> tag_invoke_result_t<_fn, Operation&> {
static_assert(
is_nothrow_tag_invocable_v<_fn, Operation&>,
"start() customisation must be noexcept");
return unifex::tag_invoke(_fn{}, op);
}
template(typename Operation)
(requires (!tag_invocable<_fn, Operation&>))
auto operator()(Operation& op) const noexcept -> decltype(op.start()) {
static_assert(
noexcept(op.start()),
"start() customisation must be noexcept");
return op.start();
}
} start{};
} // namespace _start
using _start_cpo::start;
namespace _connect {
template <typename Sender, typename Receiver>
using _member_connect_result_t =
decltype((UNIFEX_DECLVAL(Sender&&)).connect(
UNIFEX_DECLVAL(Receiver&&)));
template <typename Sender, typename Receiver>
UNIFEX_CONCEPT_FRAGMENT( //
_has_member_connect_, //
requires() ( //
typename(_member_connect_result_t<Sender, Receiver>)
));
template <typename Sender, typename Receiver>
UNIFEX_CONCEPT //
_with_member_connect = //
sender<Sender> &&
UNIFEX_FRAGMENT(_connect::_has_member_connect_, Sender, Receiver);
template <typename Sender, typename Receiver>
UNIFEX_CONCEPT //
_with_tag_invoke = //
sender<Sender> && tag_invocable<_cpo::_fn, Sender, Receiver>;
namespace _cpo {
struct _fn {
private:
template <typename Sender, typename Receiver>
static auto _select() {
if constexpr (_with_tag_invoke<Sender, Receiver>) {
return meta_tag_invoke_result<_fn>{};
} else if constexpr (_with_member_connect<Sender, Receiver>) {
return meta_quote2<_member_connect_result_t>{};
} else {
return type_always<void>{};
}
}
template <typename Sender, typename Receiver>
using _result_t = typename decltype(_fn::_select<Sender, Receiver>())
::template apply<Sender, Receiver>;
public:
template(typename Sender, typename Receiver)
(requires receiver<Receiver> AND
_with_tag_invoke<Sender, Receiver>)
auto operator()(Sender&& s, Receiver&& r) const
noexcept(is_nothrow_tag_invocable_v<_fn, Sender, Receiver>) ->
_result_t<Sender, Receiver> {
return unifex::tag_invoke(_fn{}, (Sender &&) s, (Receiver &&) r);
}
template(typename Sender, typename Receiver)
(requires receiver<Receiver> AND
(!_with_tag_invoke<Sender, Receiver>) AND
_with_member_connect<Sender, Receiver>)
auto operator()(Sender&& s, Receiver&& r) const
noexcept(noexcept(((Sender &&) s).connect((Receiver &&) r))) ->
_result_t<Sender, Receiver> {
return ((Sender &&) s).connect((Receiver &&) r);
}
};
} // namespace _cpo
} // namespace _connect
inline const _connect::_cpo::_fn connect {};
template <typename Sender, typename Receiver>
using connect_result_t =
decltype(connect(UNIFEX_DECLVAL(Sender), UNIFEX_DECLVAL(Receiver)));
#if UNIFEX_CXX_CONCEPTS
// Define the sender_to concept without macros for
// improved diagnostics:
template <typename Sender, typename Receiver>
concept //
sender_to = //
sender<Sender> &&
receiver<Receiver> &&
requires (Sender&& s, Receiver&& r) {
connect((Sender&&) s, (Receiver&&) r);
};
#else
template <typename Sender, typename Receiver>
UNIFEX_CONCEPT_FRAGMENT( //
_sender_to, //
requires (Sender&& s, Receiver&& r) ( //
connect((Sender&&) s, (Receiver&&) r)
));
template <typename Sender, typename Receiver>
UNIFEX_CONCEPT //
sender_to =
sender<Sender> &&
receiver<Receiver> &&
UNIFEX_FRAGMENT(_sender_to, Sender, Receiver);
#endif
/// \cond
template <typename Sender, typename Receiver>
using operation_t [[deprecated("Use connect_result_t instead of operation_t")]] =
connect_result_t<Sender, Receiver>;
template <typename Sender, typename Receiver>
[[deprecated("Use sender_to instead of is_connectable_v")]]
inline constexpr bool is_connectable_v =
is_callable_v<tag_t<connect>, Sender, Receiver>;
template <typename Sender, typename Receiver>
using is_connectable [[deprecated]] =
is_callable<tag_t<connect>, Sender, Receiver>;
/// \endcond
template <typename Sender, typename Receiver>
inline constexpr bool is_nothrow_connectable_v =
is_nothrow_callable_v<tag_t<connect>, Sender, Receiver>;
template <typename Sender, typename Receiver>
using is_nothrow_connectable = is_nothrow_callable<tag_t<connect>, Sender, Receiver>;
template <
typename Sender,
template <typename...> class Variant,
template <typename...> class Tuple>
using sender_value_types_t =
typename sender_traits<Sender>::template value_types<Variant, Tuple>;
template <
typename Sender,
template <typename...> class Variant>
using sender_error_types_t =
typename sender_traits<Sender>::template error_types<Variant>;
template <typename... Types>
struct single_value_type {
using type = std::tuple<Types...>;
};
template <typename T>
struct single_value_type<T> {
using type = T;
};
template <>
struct single_value_type<> {
using type = void;
};
template <typename... Overloads>
struct single_overload {};
template <typename Overload>
struct single_overload<Overload> {
using type = Overload;
};
template <>
struct single_overload<> {
private:
struct impl {
using type = void;
};
public:
using type = impl;
};
template <typename Sender>
using sender_single_value_return_type_t =
typename sender_value_types_t<Sender, single_overload, single_value_type>::type::type;
template <typename Sender>
using sender_single_value_result_t =
non_void_t<wrap_reference_t<decay_rvalue_t<sender_single_value_return_type_t<Sender>>>>;
template <typename Sender>
constexpr bool is_sender_nofail_v =
sender_error_types_t<Sender, is_empty_list>::value;
template <typename Sender>
using sender_value_type_list_t =
sender_value_types_t<Sender, type_list, type_list>;
template <typename Sender>
using sender_error_type_list_t = sender_error_types_t<Sender, type_list>;
/// \cond
namespace _single_sender {
template <typename... Types>
using _is_single_valued_tuple = std::bool_constant<1 >= sizeof...(Types)>;
template <typename... Types>
using _is_single_valued_variant =
std::bool_constant<sizeof...(Types) == 1 && (Types::value && ...)>;
} // namespace _single_sender
/// \endcond
template <typename Sender>
UNIFEX_CONCEPT_FRAGMENT( //
_single_typed_sender_impl, //
requires()(0) && //
sender_traits<remove_cvref_t<Sender>>::template value_types<
_single_sender::_is_single_valued_variant,
_single_sender::_is_single_valued_tuple>::value);
template <typename Sender>
UNIFEX_CONCEPT _single_typed_sender = //
typed_sender<Sender> &&
UNIFEX_FRAGMENT(unifex::_single_typed_sender_impl, Sender);
} // namespace unifex
#include <unifex/detail/epilogue.hpp>