Add execution::submit() customisation point object.

This commit is contained in:
Christopher Kohlhoff 2020-06-29 20:22:29 +10:00
parent 56409abe01
commit d4afc16918
10 changed files with 1453 additions and 0 deletions

View File

@ -325,6 +325,7 @@ nobase_include_HEADERS = \
asio/execution/set_error.hpp \
asio/execution/set_value.hpp \
asio/execution/start.hpp \
asio/execution/submit.hpp \
asio/executor.hpp \
asio/executor_work_guard.hpp \
asio/generic/basic_endpoint.hpp \
@ -520,6 +521,8 @@ nobase_include_HEADERS = \
asio/traits/static_query.hpp \
asio/traits/static_require.hpp \
asio/traits/static_require_concept.hpp \
asio/traits/submit_free.hpp \
asio/traits/submit_member.hpp \
asio/ts/buffer.hpp \
asio/ts/executor.hpp \
asio/ts/internet.hpp \

View File

@ -40,5 +40,6 @@
#include "asio/execution/set_error.hpp"
#include "asio/execution/set_value.hpp"
#include "asio/execution/start.hpp"
#include "asio/execution/submit.hpp"
#endif // ASIO_EXECUTION_HPP

View File

@ -0,0 +1,233 @@
//
// execution/detail/submit_receiver.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_EXECUTION_DETAIL_SUBMIT_RECEIVER_HPP
#define ASIO_EXECUTION_DETAIL_SUBMIT_RECEIVER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/variadic_templates.hpp"
#include "asio/execution/connect.hpp"
#include "asio/execution/receiver.hpp"
#include "asio/execution/set_done.hpp"
#include "asio/execution/set_error.hpp"
#include "asio/execution/set_value.hpp"
#include "asio/traits/set_done_member.hpp"
#include "asio/traits/set_error_member.hpp"
#include "asio/traits/set_value_member.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace execution {
namespace detail {
template <typename Sender, typename Receiver>
struct submit_receiver;
template <typename Sender, typename Receiver>
struct submit_receiver_wrapper
{
submit_receiver<Sender, Receiver>* p_;
explicit submit_receiver_wrapper(submit_receiver<Sender, Receiver>* p)
: p_(p)
{
}
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename... Args>
typename enable_if<is_receiver_of<Receiver, Args...>::value>::type
set_value(ASIO_MOVE_ARG(Args)... args) ASIO_RVALUE_REF_QUAL
ASIO_NOEXCEPT_IF((is_nothrow_receiver_of<Receiver, Args...>::value))
{
execution::set_value(
ASIO_MOVE_OR_LVALUE(
typename remove_cvref<Receiver>::type)(p_->r_),
ASIO_MOVE_CAST(Args)(args)...);
delete p_;
}
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
void set_value() ASIO_RVALUE_REF_QUAL
ASIO_NOEXCEPT_IF((is_nothrow_receiver_of<Receiver>::value))
{
execution::set_value(
ASIO_MOVE_OR_LVALUE(
typename remove_cvref<Receiver>::type)(p_->r_));
delete p_;
}
#define ASIO_PRIVATE_SUBMIT_RECEIVER_SET_VALUE_DEF(n) \
template <ASIO_VARIADIC_TPARAMS(n)> \
typename enable_if<is_receiver_of<Receiver, \
ASIO_VARIADIC_TARGS(n)>::value>::type \
set_value(ASIO_VARIADIC_MOVE_PARAMS(n)) ASIO_RVALUE_REF_QUAL \
ASIO_NOEXCEPT_IF((is_nothrow_receiver_of< \
Receiver, ASIO_VARIADIC_TARGS(n)>::value)) \
{ \
execution::set_value( \
ASIO_MOVE_OR_LVALUE( \
typename remove_cvref<Receiver>::type)(p_->r_), \
ASIO_VARIADIC_MOVE_ARGS(n)); \
delete p_; \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SUBMIT_RECEIVER_SET_VALUE_DEF)
#undef ASIO_PRIVATE_SUBMIT_RECEIVER_SET_VALUE_DEF
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename E>
void set_error(ASIO_MOVE_ARG(E) e)
ASIO_RVALUE_REF_QUAL ASIO_NOEXCEPT
{
execution::set_error(
ASIO_MOVE_OR_LVALUE(
typename remove_cvref<Receiver>::type)(p_->r_),
ASIO_MOVE_CAST(E)(e));
delete p_;
}
void set_done() ASIO_RVALUE_REF_QUAL ASIO_NOEXCEPT
{
execution::set_done(
ASIO_MOVE_OR_LVALUE(
typename remove_cvref<Receiver>::type)(p_->r_));
delete p_;
}
};
template <typename Sender, typename Receiver>
struct submit_receiver
{
typename remove_cvref<Receiver>::type r_;
#if defined(ASIO_HAS_MOVE)
typename connect_result_type<Sender,
submit_receiver_wrapper<Sender, Receiver> >::type state_;
#else // defined(ASIO_HAS_MOVE)
typename connect_result_type<Sender,
const submit_receiver_wrapper<Sender, Receiver>& >::type state_;
#endif // defined(ASIO_HAS_MOVE)
#if defined(ASIO_HAS_MOVE)
template <typename S, typename R>
explicit submit_receiver(ASIO_MOVE_ARG(S) s, ASIO_MOVE_ARG(R) r)
: r_(ASIO_MOVE_CAST(R)(r)),
state_(execution::connect(ASIO_MOVE_CAST(S)(s),
submit_receiver_wrapper<Sender, Receiver>(this)))
{
}
#else // defined(ASIO_HAS_MOVE)
explicit submit_receiver(Sender s, Receiver r)
: r_(r),
state_(execution::connect(s,
submit_receiver_wrapper<Sender, Receiver>(this)))
{
}
#endif // defined(ASIO_HAS_MOVE)
};
} // namespace detail
} // namespace execution
namespace traits {
#if !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Sender, typename Receiver, typename... Args>
struct set_value_member<
asio::execution::detail::submit_receiver_wrapper<
Sender, Receiver>,
void(Args...)>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
(asio::execution::is_nothrow_receiver_of<Receiver, Args...>::value));
typedef void result_type;
};
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Sender, typename Receiver>
struct set_value_member<
asio::execution::detail::submit_receiver_wrapper<
Sender, Receiver>,
void()>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
asio::execution::is_nothrow_receiver_of<Receiver>::value);
typedef void result_type;
};
#define ASIO_PRIVATE_SUBMIT_RECEIVER_TRAIT_DEF(n) \
template <typename Sender, typename Receiver, \
ASIO_VARIADIC_TPARAMS(n)> \
struct set_value_member< \
asio::execution::detail::submit_receiver_wrapper< \
Sender, Receiver>, \
void(ASIO_VARIADIC_TARGS(n))> \
{ \
ASIO_STATIC_CONSTEXPR(bool, is_valid = true); \
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = \
(asio::execution::is_nothrow_receiver_of<Receiver, \
ASIO_VARIADIC_TARGS(n)>::value)); \
typedef void result_type; \
}; \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SUBMIT_RECEIVER_TRAIT_DEF)
#undef ASIO_PRIVATE_SUBMIT_RECEIVER_TRAIT_DEF
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
#endif // !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)
template <typename Sender, typename Receiver, typename E>
struct set_error_member<
asio::execution::detail::submit_receiver_wrapper<
Sender, Receiver>, E>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
typedef void result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)
template <typename Sender, typename Receiver>
struct set_done_member<
asio::execution::detail::submit_receiver_wrapper<
Sender, Receiver> >
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
typedef void result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)
} // namespace traits
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_EXECUTION_DETAIL_SUBMIT_RECEIVER_HPP

View File

@ -0,0 +1,441 @@
//
// execution/submit.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_EXECUTION_SUBMIT_HPP
#define ASIO_EXECUTION_SUBMIT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/execution/detail/submit_receiver.hpp"
#include "asio/execution/executor.hpp"
#include "asio/execution/receiver.hpp"
#include "asio/execution/sender.hpp"
#include "asio/execution/start.hpp"
#include "asio/traits/submit_member.hpp"
#include "asio/traits/submit_free.hpp"
#include "asio/detail/push_options.hpp"
#if defined(GENERATING_DOCUMENTATION)
namespace asio {
namespace execution {
/// A customisation point that submits a sender to a receiver.
/**
* The name <tt>execution::submit</tt> denotes a customisation point object. For
* some subexpressions <tt>s</tt> and <tt>r</tt>, let <tt>S</tt> be a type such
* that <tt>decltype((s))</tt> is <tt>S</tt> and let <tt>R</tt> be a type such
* that <tt>decltype((r))</tt> is <tt>R</tt>. The expression
* <tt>execution::submit(s, r)</tt> is ill-formed if <tt>sender_to<S, R></tt> is
* not <tt>true</tt>. Otherwise, it is expression-equivalent to:
*
* @li <tt>s.submit(r)</tt>, if that expression is valid and <tt>S</tt> models
* <tt>sender</tt>. If the function selected does not submit the receiver
* object <tt>r</tt> via the sender <tt>s</tt>, the program is ill-formed with
* no diagnostic required.
*
* @li Otherwise, <tt>submit(s, r)</tt>, if that expression is valid and
* <tt>S</tt> models <tt>sender</tt>, with overload resolution performed in a
* context that includes the declaration <tt>void submit();</tt> and that does
* not include a declaration of <tt>execution::submit</tt>. If the function
* selected by overload resolution does not submit the receiver object
* <tt>r</tt> via the sender <tt>s</tt>, the program is ill-formed with no
* diagnostic required.
*
* @li Otherwise, <tt>execution::start((new submit_receiver<S,
* R>{s,r})->state_)</tt>, where <tt>submit_receiver</tt> is an
* implementation-defined class template equivalent to:
* @code template<class S, class R>
* struct submit_receiver {
* struct wrap {
* submit_receiver * p_;
* template<class...As>
* requires receiver_of<R, As...>
* void set_value(As&&... as) &&
* noexcept(is_nothrow_receiver_of_v<R, As...>) {
* execution::set_value(std::move(p_->r_), (As&&) as...);
* delete p_;
* }
* template<class E>
* requires receiver<R, E>
* void set_error(E&& e) && noexcept {
* execution::set_error(std::move(p_->r_), (E&&) e);
* delete p_;
* }
* void set_done() && noexcept {
* execution::set_done(std::move(p_->r_));
* delete p_;
* }
* };
* remove_cvref_t<R> r_;
* connect_result_t<S, wrap> state_;
* submit_receiver(S&& s, R&& r)
* : r_((R&&) r)
* , state_(execution::connect((S&&) s, wrap{this})) {}
* };
* @endcode
*/
inline constexpr unspecified submit = unspecified;
/// A type trait that determines whether a @c submit expression is
/// well-formed.
/**
* Class template @c can_submit is a trait that is derived from
* @c true_type if the expression <tt>execution::submit(std::declval<R>(),
* std::declval<E>())</tt> is well formed; otherwise @c false_type.
*/
template <typename S, typename R>
struct can_submit :
integral_constant<bool, automatically_determined>
{
};
} // namespace execution
} // namespace asio
#else // defined(GENERATING_DOCUMENTATION)
namespace asio_execution_submit_fn {
using asio::declval;
using asio::enable_if;
using asio::execution::is_sender_to;
using asio::traits::submit_free;
using asio::traits::submit_member;
void submit();
enum overload_type
{
call_member,
call_free,
adapter,
ill_formed
};
template <typename S, typename R, typename = void>
struct call_traits
{
ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
typedef void result_type;
};
template <typename S, typename R>
struct call_traits<S, void(R),
typename enable_if<
(
submit_member<S, R>::is_valid
&&
is_sender_to<S, R>::value
)
>::type> :
submit_member<S, R>
{
ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
};
template <typename S, typename R>
struct call_traits<S, void(R),
typename enable_if<
(
!submit_member<S, R>::is_valid
&&
submit_free<S, R>::is_valid
&&
is_sender_to<S, R>::value
)
>::type> :
submit_free<S, R>
{
ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
};
template <typename S, typename R>
struct call_traits<S, void(R),
typename enable_if<
(
!submit_member<S, R>::is_valid
&&
!submit_free<S, R>::is_valid
&&
is_sender_to<S, R>::value
)
>::type>
{
ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
typedef void result_type;
};
struct impl
{
#if defined(ASIO_HAS_MOVE)
template <typename S, typename R>
ASIO_CONSTEXPR typename enable_if<
call_traits<S, void(R)>::overload == call_member,
typename call_traits<S, void(R)>::result_type
>::type
operator()(S&& s, R&& r) const
ASIO_NOEXCEPT_IF((
call_traits<S, void(R)>::is_noexcept))
{
return ASIO_MOVE_CAST(S)(s).submit(ASIO_MOVE_CAST(R)(r));
}
template <typename S, typename R>
ASIO_CONSTEXPR typename enable_if<
call_traits<S, void(R)>::overload == call_free,
typename call_traits<S, void(R)>::result_type
>::type
operator()(S&& s, R&& r) const
ASIO_NOEXCEPT_IF((
call_traits<S, void(R)>::is_noexcept))
{
return submit(ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(R)(r));
}
template <typename S, typename R>
ASIO_CONSTEXPR typename enable_if<
call_traits<S, void(R)>::overload == adapter,
typename call_traits<S, void(R)>::result_type
>::type
operator()(S&& s, R&& r) const
ASIO_NOEXCEPT_IF((
call_traits<S, void(R)>::is_noexcept))
{
return asio::execution::start(
(new asio::execution::detail::submit_receiver<S, R>(
ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(R)(r)))->state_);
}
#else // defined(ASIO_HAS_MOVE)
template <typename S, typename R>
ASIO_CONSTEXPR typename enable_if<
call_traits<S&, void(R&)>::overload == call_member,
typename call_traits<S&, void(R&)>::result_type
>::type
operator()(S& s, R& r) const
ASIO_NOEXCEPT_IF((
call_traits<S&, void(R&)>::is_noexcept))
{
return s.submit(r);
}
template <typename S, typename R>
ASIO_CONSTEXPR typename enable_if<
call_traits<const S&, void(R&)>::overload == call_member,
typename call_traits<const S&, void(R&)>::result_type
>::type
operator()(const S& s, R& r) const
ASIO_NOEXCEPT_IF((
call_traits<const S&, void(R&)>::is_noexcept))
{
return s.submit(r);
}
template <typename S, typename R>
ASIO_CONSTEXPR typename enable_if<
call_traits<S&, void(R&)>::overload == call_free,
typename call_traits<S&, void(R&)>::result_type
>::type
operator()(S& s, R& r) const
ASIO_NOEXCEPT_IF((
call_traits<S&, void(R&)>::is_noexcept))
{
return submit(s, r);
}
template <typename S, typename R>
ASIO_CONSTEXPR typename enable_if<
call_traits<const S&, void(R&)>::overload == call_free,
typename call_traits<const S&, void(R&)>::result_type
>::type
operator()(const S& s, R& r) const
ASIO_NOEXCEPT_IF((
call_traits<const S&, void(R&)>::is_noexcept))
{
return submit(s, r);
}
template <typename S, typename R>
ASIO_CONSTEXPR typename enable_if<
call_traits<S&, void(R&)>::overload == adapter,
typename call_traits<S&, void(R&)>::result_type
>::type
operator()(S& s, R& r) const
ASIO_NOEXCEPT_IF((
call_traits<S&, void(R&)>::is_noexcept))
{
return asio::execution::start(
(new asio::execution::detail::submit_receiver<
S&, R&>(s, r))->state_);
}
template <typename S, typename R>
ASIO_CONSTEXPR typename enable_if<
call_traits<const S&, void(R&)>::overload == adapter,
typename call_traits<const S&, void(R&)>::result_type
>::type
operator()(const S& s, R& r) const
ASIO_NOEXCEPT_IF((
call_traits<const S&, void(R&)>::is_noexcept))
{
asio::execution::start(
(new asio::execution::detail::submit_receiver<
const S&, R&>(s, r))->state_);
}
template <typename S, typename R>
ASIO_CONSTEXPR typename enable_if<
call_traits<S&, void(const R&)>::overload == call_member,
typename call_traits<S&, void(const R&)>::result_type
>::type
operator()(S& s, const R& r) const
ASIO_NOEXCEPT_IF((
call_traits<S&, void(const R&)>::is_noexcept))
{
return s.submit(r);
}
template <typename S, typename R>
ASIO_CONSTEXPR typename enable_if<
call_traits<const S&, void(const R&)>::overload == call_member,
typename call_traits<const S&, void(const R&)>::result_type
>::type
operator()(const S& s, const R& r) const
ASIO_NOEXCEPT_IF((
call_traits<const S&, void(const R&)>::is_noexcept))
{
return s.submit(r);
}
template <typename S, typename R>
ASIO_CONSTEXPR typename enable_if<
call_traits<S&, void(const R&)>::overload == call_free,
typename call_traits<S&, void(const R&)>::result_type
>::type
operator()(S& s, const R& r) const
ASIO_NOEXCEPT_IF((
call_traits<S&, void(const R&)>::is_noexcept))
{
return submit(s, r);
}
template <typename S, typename R>
ASIO_CONSTEXPR typename enable_if<
call_traits<const S&, void(const R&)>::overload == call_free,
typename call_traits<const S&, void(const R&)>::result_type
>::type
operator()(const S& s, const R& r) const
ASIO_NOEXCEPT_IF((
call_traits<const S&, void(const R&)>::is_noexcept))
{
return submit(s, r);
}
template <typename S, typename R>
ASIO_CONSTEXPR typename enable_if<
call_traits<S&, void(const R&)>::overload == adapter,
typename call_traits<S&, void(const R&)>::result_type
>::type
operator()(S& s, const R& r) const
ASIO_NOEXCEPT_IF((
call_traits<S&, void(const R&)>::is_noexcept))
{
asio::execution::start(
(new asio::execution::detail::submit_receiver<
S&, const R&>(s, r))->state_);
}
template <typename S, typename R>
ASIO_CONSTEXPR typename enable_if<
call_traits<const S&, void(const R&)>::overload == adapter,
typename call_traits<const S&, void(const R&)>::result_type
>::type
operator()(const S& s, const R& r) const
ASIO_NOEXCEPT_IF((
call_traits<const S&, void(const R&)>::is_noexcept))
{
asio::execution::start(
(new asio::execution::detail::submit_receiver<
const S&, const R&>(s, r))->state_);
}
#endif // defined(ASIO_HAS_MOVE)
};
template <typename T = impl>
struct static_instance
{
static const T instance;
};
template <typename T>
const T static_instance<T>::instance = {};
} // namespace asio_execution_submit_fn
namespace asio {
namespace execution {
namespace {
static ASIO_CONSTEXPR const asio_execution_submit_fn::impl&
submit = asio_execution_submit_fn::static_instance<>::instance;
} // namespace
template <typename S, typename R>
struct can_submit :
integral_constant<bool,
asio_execution_submit_fn::call_traits<S, void(R)>::overload !=
asio_execution_submit_fn::ill_formed>
{
};
#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
template <typename S, typename R>
constexpr bool can_submit_v = can_submit<S, R>::value;
#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
template <typename S, typename R>
struct is_nothrow_submit :
integral_constant<bool,
asio_execution_submit_fn::call_traits<S, void(R)>::is_noexcept>
{
};
#if defined(ASIO_HAS_VARIABLE_TEMPLATES)
template <typename S, typename R>
constexpr bool is_nothrow_submit_v
= is_nothrow_submit<S, R>::value;
#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)
template <typename S, typename R>
struct submit_result_type
{
typedef typename asio_execution_submit_fn::call_traits<
S, void(R)>::result_type type;
};
} // namespace execution
} // namespace asio
#endif // defined(GENERATING_DOCUMENTATION)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_EXECUTION_SUBMIT_HPP

View File

@ -0,0 +1,112 @@
//
// traits/submit_free.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_TRAITS_SUBMIT_FREE_HPP
#define ASIO_TRAITS_SUBMIT_FREE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/type_traits.hpp"
#if defined(ASIO_HAS_DECLTYPE) \
&& defined(ASIO_HAS_NOEXCEPT) \
&& defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
# define ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT 1
#endif // defined(ASIO_HAS_DECLTYPE)
// && defined(ASIO_HAS_NOEXCEPT)
// && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace traits {
template <typename S, typename R, typename = void>
struct submit_free_default;
template <typename S, typename R, typename = void>
struct submit_free;
} // namespace traits
namespace detail {
struct no_submit_free
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
};
#if defined(ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT)
template <typename S, typename R, typename = void>
struct submit_free_trait : no_submit_free
{
};
template <typename S, typename R>
struct submit_free_trait<S, R,
typename void_type<
decltype(submit(declval<S>(), declval<R>()))
>::type>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
using result_type = decltype(
submit(declval<S>(), declval<R>()));
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
submit(declval<S>(), declval<R>())));
};
#else // defined(ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT)
template <typename S, typename R, typename = void>
struct submit_free_trait :
conditional<
is_same<S, typename remove_reference<S>::type>::value
&& is_same<R, typename decay<R>::type>::value,
typename conditional<
is_same<S, typename add_const<S>::type>::value,
no_submit_free,
traits::submit_free<typename add_const<S>::type, R>
>::type,
traits::submit_free<
typename remove_reference<S>::type,
typename decay<R>::type>
>::type
{
};
#endif // defined(ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT)
} // namespace detail
namespace traits {
template <typename S, typename R, typename>
struct submit_free_default :
detail::submit_free_trait<S, R>
{
};
template <typename S, typename R, typename>
struct submit_free :
submit_free_default<S, R>
{
};
} // namespace traits
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_TRAITS_SUBMIT_FREE_HPP

View File

@ -0,0 +1,112 @@
//
// traits/submit_member.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_TRAITS_SUBMIT_MEMBER_HPP
#define ASIO_TRAITS_SUBMIT_MEMBER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/type_traits.hpp"
#if defined(ASIO_HAS_DECLTYPE) \
&& defined(ASIO_HAS_NOEXCEPT) \
&& defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
# define ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT 1
#endif // defined(ASIO_HAS_DECLTYPE)
// && defined(ASIO_HAS_NOEXCEPT)
// && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace traits {
template <typename S, typename R, typename = void>
struct submit_member_default;
template <typename S, typename R, typename = void>
struct submit_member;
} // namespace traits
namespace detail {
struct no_submit_member
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = false);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
};
#if defined(ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT)
template <typename S, typename R, typename = void>
struct submit_member_trait : no_submit_member
{
};
template <typename S, typename R>
struct submit_member_trait<S, R,
typename void_type<
decltype(declval<S>().submit(declval<R>()))
>::type>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
using result_type = decltype(
declval<S>().submit(declval<R>()));
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(
declval<S>().submit(declval<R>())));
};
#else // defined(ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT)
template <typename S, typename R, typename = void>
struct submit_member_trait :
conditional<
is_same<S, typename remove_reference<S>::type>::value
&& is_same<R, typename decay<R>::type>::value,
typename conditional<
is_same<S, typename add_const<S>::type>::value,
no_submit_member,
traits::submit_member<typename add_const<S>::type, R>
>::type,
traits::submit_member<
typename remove_reference<S>::type,
typename decay<R>::type>
>::type
{
};
#endif // defined(ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT)
} // namespace detail
namespace traits {
template <typename S, typename R, typename>
struct submit_member_default :
detail::submit_member_trait<S, R>
{
};
template <typename S, typename R, typename>
struct submit_member :
submit_member_default<S, R>
{
};
} // namespace traits
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_TRAITS_SUBMIT_MEMBER_HPP

View File

@ -167,6 +167,7 @@ UNIT_TEST_EXES = \
tests\unit\execution\set_error.exe \
tests\unit\execution\set_value.exe \
tests\unit\execution\start.exe \
tests\unit\execution\submit.exe \
tests\unit\executor.exe \
tests\unit\executor_work_guard.exe \
tests\unit\generic\basic_endpoint.exe \

View File

@ -63,6 +63,7 @@ check_PROGRAMS = \
unit/execution/set_error \
unit/execution/set_value \
unit/execution/start \
unit/execution/submit \
unit/execution_context \
unit/executor \
unit/executor_work_guard \
@ -225,6 +226,7 @@ TESTS = \
unit/execution/set_error \
unit/execution/set_value \
unit/execution/start \
unit/execution/submit \
unit/execution_context \
unit/executor \
unit/executor_work_guard \
@ -387,6 +389,7 @@ unit_execution_set_done_SOURCES = unit/execution/set_done.cpp
unit_execution_set_error_SOURCES = unit/execution/set_error.cpp
unit_execution_set_value_SOURCES = unit/execution/set_value.cpp
unit_execution_start_SOURCES = unit/execution/start.cpp
unit_execution_submit_SOURCES = unit/execution/submit.cpp
unit_execution_context_SOURCES = unit/execution_context.cpp
unit_executor_SOURCES = unit/executor.cpp
unit_executor_work_guard_SOURCES = unit/executor_work_guard.cpp

View File

@ -26,3 +26,4 @@ set_done
set_error
set_value
start
submit

View File

@ -0,0 +1,546 @@
//
// submit.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Disable autolinking for unit tests.
#if !defined(BOOST_ALL_NO_LIB)
#define BOOST_ALL_NO_LIB 1
#endif // !defined(BOOST_ALL_NO_LIB)
// Test that header file is self-contained.
#include "asio/execution/submit.hpp"
#include "asio/error_code.hpp"
#include "../unit_test.hpp"
namespace exec = asio::execution;
static int call_count = 0;
struct operation_state
{
void start() ASIO_NOEXCEPT
{
}
};
namespace asio {
namespace traits {
#if !defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)
template <>
struct start_member<operation_state>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
typedef void result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)
} // namespace traits
} // namespace asio
struct no_submit_1
{
};
struct no_submit_2 : exec::sender_base
{
};
struct no_submit_3
{
template <typename R>
void submit(ASIO_MOVE_ARG(R) r)
{
(void)r;
}
};
#if !defined(ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT)
namespace asio {
namespace traits {
template <typename R>
struct submit_member<no_submit_3, R>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
typedef void result_type;
};
} // namespace traits
} // namespace asio
#endif // !defined(ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT)
struct const_member_submit : exec::sender_base
{
const_member_submit()
{
}
template <typename R>
operation_state connect(ASIO_MOVE_ARG(R) r) const
{
(void)r;
return operation_state();
}
template <typename R>
void submit(ASIO_MOVE_ARG(R) r) const
{
(void)r;
++call_count;
}
};
namespace asio {
namespace traits {
#if !defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)
template <typename R>
struct connect_member<const const_member_submit, R>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
typedef operation_state result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT)
template <typename R>
struct submit_member<const const_member_submit, R>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
typedef void result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT)
} // namespace traits
} // namespace asio
struct free_submit_const_receiver : exec::sender_base
{
free_submit_const_receiver()
{
}
template <typename R>
friend operation_state connect(
const free_submit_const_receiver&, ASIO_MOVE_ARG(R) r)
{
(void)r;
return operation_state();
}
template <typename R>
friend void submit(
const free_submit_const_receiver&, ASIO_MOVE_ARG(R) r)
{
(void)r;
++call_count;
}
};
namespace asio {
namespace traits {
#if !defined(ASIO_HAS_DEDUCED_CONNECT_FREE_TRAIT)
template <typename R>
struct connect_free<const free_submit_const_receiver, R>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
typedef operation_state result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_CONNECT_FREE_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT)
template <typename R>
struct submit_free<const free_submit_const_receiver, R>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
typedef void result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT)
} // namespace traits
} // namespace asio
struct non_const_member_submit : exec::sender_base
{
non_const_member_submit()
{
}
template <typename R>
operation_state connect(ASIO_MOVE_ARG(R) r)
{
(void)r;
return operation_state();
}
template <typename R>
void submit(ASIO_MOVE_ARG(R) r)
{
(void)r;
++call_count;
}
};
namespace asio {
namespace traits {
#if !defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)
template <typename R>
struct connect_member<non_const_member_submit, R>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
typedef operation_state result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT)
template <typename R>
struct submit_member<non_const_member_submit, R>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
typedef void result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT)
} // namespace traits
} // namespace asio
struct free_submit_non_const_receiver : exec::sender_base
{
free_submit_non_const_receiver()
{
}
template <typename R>
friend operation_state connect(
free_submit_non_const_receiver&, ASIO_MOVE_ARG(R) r)
{
(void)r;
return operation_state();
}
template <typename R>
friend void submit(
free_submit_non_const_receiver&, ASIO_MOVE_ARG(R) r)
{
(void)r;
++call_count;
}
};
namespace asio {
namespace traits {
#if !defined(ASIO_HAS_DEDUCED_CONNECT_FREE_TRAIT)
template <typename R>
struct connect_free<free_submit_non_const_receiver, R>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
typedef operation_state result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_CONNECT_FREE_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT)
template <typename R>
struct submit_free<free_submit_non_const_receiver, R>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
typedef void result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT)
} // namespace traits
} // namespace asio
struct receiver
{
receiver()
{
}
receiver(const receiver&)
{
}
#if defined(ASIO_HAS_MOVE)
receiver(receiver&&) ASIO_NOEXCEPT
{
}
#endif // defined(ASIO_HAS_MOVE)
template <typename E>
void set_error(ASIO_MOVE_ARG(E) e) ASIO_NOEXCEPT
{
(void)e;
}
void set_done() ASIO_NOEXCEPT
{
}
};
namespace asio {
namespace traits {
#if !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)
template <typename E>
struct set_error_member<receiver, E>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
typedef void result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)
template <>
struct set_done_member<receiver>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
typedef void result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)
} // namespace traits
} // namespace asio
struct executor
{
executor()
{
}
executor(const executor&) ASIO_NOEXCEPT
{
}
#if defined(ASIO_HAS_MOVE)
executor(executor&&) ASIO_NOEXCEPT
{
}
#endif // defined(ASIO_HAS_MOVE)
template <typename F>
void execute(ASIO_MOVE_ARG(F) f) const ASIO_NOEXCEPT
{
(void)f;
++call_count;
}
bool operator==(const executor&) const ASIO_NOEXCEPT
{
return true;
}
bool operator!=(const executor&) const ASIO_NOEXCEPT
{
return false;
}
};
namespace asio {
namespace traits {
#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
template <typename F>
struct execute_member<executor, F>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
typedef void result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
template <>
struct equality_comparable<executor>
{
ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
};
#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
} // namespace traits
} // namespace asio
void test_can_submit()
{
ASIO_CONSTEXPR bool b1 = exec::can_submit<
no_submit_1&, receiver>::value;
ASIO_CHECK(b1 == false);
ASIO_CONSTEXPR bool b2 = exec::can_submit<
const no_submit_1&, receiver>::value;
ASIO_CHECK(b2 == false);
ASIO_CONSTEXPR bool b3 = exec::can_submit<
no_submit_2&, receiver>::value;
ASIO_CHECK(b3 == false);
ASIO_CONSTEXPR bool b4 = exec::can_submit<
const no_submit_2&, receiver>::value;
ASIO_CHECK(b4 == false);
ASIO_CONSTEXPR bool b5 = exec::can_submit<
no_submit_3&, receiver>::value;
ASIO_CHECK(b5 == false);
ASIO_CONSTEXPR bool b6 = exec::can_submit<
const no_submit_3&, receiver>::value;
ASIO_CHECK(b6 == false);
ASIO_CONSTEXPR bool b7 = exec::can_submit<
const_member_submit&, receiver>::value;
ASIO_CHECK(b7 == true);
ASIO_CONSTEXPR bool b8 = exec::can_submit<
const const_member_submit&, receiver>::value;
ASIO_CHECK(b8 == true);
ASIO_CONSTEXPR bool b9 = exec::can_submit<
free_submit_const_receiver&, receiver>::value;
ASIO_CHECK(b9 == true);
ASIO_CONSTEXPR bool b10 = exec::can_submit<
const free_submit_const_receiver&, receiver>::value;
ASIO_CHECK(b10 == true);
ASIO_CONSTEXPR bool b11 = exec::can_submit<
non_const_member_submit&, receiver>::value;
ASIO_CHECK(b11 == true);
ASIO_CONSTEXPR bool b12 = exec::can_submit<
const non_const_member_submit&, receiver>::value;
ASIO_CHECK(b12 == false);
ASIO_CONSTEXPR bool b13 = exec::can_submit<
free_submit_non_const_receiver&, receiver>::value;
ASIO_CHECK(b13 == true);
ASIO_CONSTEXPR bool b14 = exec::can_submit<
const free_submit_non_const_receiver&, receiver>::value;
ASIO_CHECK(b14 == false);
ASIO_CONSTEXPR bool b15 = exec::can_submit<
executor&, receiver>::value;
ASIO_CHECK(b15 == true);
ASIO_CONSTEXPR bool b16 = exec::can_submit<
const executor&, receiver>::value;
ASIO_CHECK(b16 == true);
}
void increment(int* count)
{
++(*count);
}
void test_submit()
{
receiver r;
call_count = 0;
const_member_submit s1;
exec::submit(s1, r);
ASIO_CHECK(call_count == 1);
call_count = 0;
const const_member_submit s2;
exec::submit(s2, r);
ASIO_CHECK(call_count == 1);
call_count = 0;
exec::submit(const_member_submit(), r);
ASIO_CHECK(call_count == 1);
call_count = 0;
free_submit_const_receiver s3;
exec::submit(s3, r);
ASIO_CHECK(call_count == 1);
call_count = 0;
const free_submit_const_receiver s4;
exec::submit(s4, r);
ASIO_CHECK(call_count == 1);
call_count = 0;
exec::submit(free_submit_const_receiver(), r);
ASIO_CHECK(call_count == 1);
call_count = 0;
non_const_member_submit s5;
exec::submit(s5, r);
ASIO_CHECK(call_count == 1);
call_count = 0;
free_submit_non_const_receiver s6;
exec::submit(s6, r);
ASIO_CHECK(call_count == 1);
call_count = 0;
executor s7;
exec::submit(s7, r);
ASIO_CHECK(call_count == 1);
call_count = 0;
const executor s8;
exec::submit(s8, r);
ASIO_CHECK(call_count == 1);
call_count = 0;
exec::submit(executor(), r);
ASIO_CHECK(call_count == 1);
}
ASIO_TEST_SUITE
(
"submit",
ASIO_TEST_CASE(test_can_submit)
ASIO_TEST_CASE(test_submit)
)