Skip to content

Commit

Permalink
Add experimental::prepend completion token adapter.
Browse files Browse the repository at this point in the history
The prepend completion token adapter can be used to pass additional
before the existing completion handler arguments. For example:

  timer.async_wait(
      asio::experimental::prepend(
        [](int i, std::error_code ec)
        {
          // ...
        },
      42)
    );

  std::future<std::tuple<int, std::error_code>> f = timer.async_wait(
      asio::experimental::prepend(
        asio::use_future,
        42
      )
    );
  • Loading branch information
chriskohlhoff committed Jun 30, 2021
1 parent 90f3b6c commit d6735d4
Show file tree
Hide file tree
Showing 4 changed files with 295 additions and 3 deletions.
2 changes: 2 additions & 0 deletions asio/include/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -347,10 +347,12 @@ nobase_include_HEADERS = \
asio/experimental/as_tuple.hpp \
asio/experimental/cancellation_condition.hpp \
asio/experimental/parallel_group.hpp \
asio/experimental/prepend.hpp \
asio/experimental/impl/append.hpp \
asio/experimental/impl/as_single.hpp \
asio/experimental/impl/as_tuple.hpp \
asio/experimental/impl/parallel_group.hpp \
asio/experimental/impl/prepend.hpp \
asio/generic/basic_endpoint.hpp \
asio/generic/datagram_protocol.hpp \
asio/generic/detail/endpoint.hpp \
Expand Down
8 changes: 5 additions & 3 deletions asio/include/asio/experimental/append.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ namespace asio {
namespace experimental {

/// Completion token type used to specify that the completion handler
/// arguments should be passed additional values.
/// arguments should be passed additional values after the results of the
/// operation.
template <typename CompletionToken, typename... Values>
class append_t
{
Expand All @@ -45,8 +46,9 @@ class append_t
std::tuple<Values...> values_;
};

/// Create a completion token to specify that the completion handler arguments
/// should be combined into a single tuple argument.
/// Completion token type used to specify that the completion handler
/// arguments should be passed additional values after the results of the
/// operation.
template <typename CompletionToken, typename... Values>
inline ASIO_CONSTEXPR append_t<
typename decay<CompletionToken>::type, typename decay<Values>::type...>
Expand Down
217 changes: 217 additions & 0 deletions asio/include/asio/experimental/impl/prepend.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
//
// experimental/impl/prepend.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 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_IMPL_EXPERIMENTAL_PREPEND_HPP
#define ASIO_IMPL_EXPERIMENTAL_PREPEND_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include "asio/detail/config.hpp"

#include "asio/associator.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_cont_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/variadic_templates.hpp"

#include "asio/detail/push_options.hpp"

namespace asio {
namespace experimental {
namespace detail {

// Class to adapt a prepend_t as a completion handler.
template <typename Handler, typename... Values>
class prepend_handler
{
public:
typedef void result_type;

template <typename H>
prepend_handler(ASIO_MOVE_ARG(H) handler, std::tuple<Values...> values)
: handler_(ASIO_MOVE_CAST(H)(handler)),
values_(ASIO_MOVE_CAST(std::tuple<Values...>)(values))
{
}

template <typename... Args>
void operator()(ASIO_MOVE_ARG(Args)... args)
{
this->invoke(
std::make_index_sequence<sizeof...(Values)>{},
ASIO_MOVE_CAST(Args)(args)...);
}

template <std::size_t... I, typename... Args>
void invoke(std::index_sequence<I...>, ASIO_MOVE_ARG(Args)... args)
{
ASIO_MOVE_OR_LVALUE(Handler)(handler_)(
ASIO_MOVE_CAST(Values)(std::get<I>(values_))...,
ASIO_MOVE_CAST(Args)(args)...);
}

//private:
Handler handler_;
std::tuple<Values...> values_;
};

template <typename Handler>
inline asio_handler_allocate_is_deprecated
asio_handler_allocate(std::size_t size,
prepend_handler<Handler>* this_handler)
{
#if defined(ASIO_NO_DEPRECATED)
asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
return asio_handler_allocate_is_no_longer_used();
#else // defined(ASIO_NO_DEPRECATED)
return asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
#endif // defined(ASIO_NO_DEPRECATED)
}

template <typename Handler>
inline asio_handler_deallocate_is_deprecated
asio_handler_deallocate(void* pointer, std::size_t size,
prepend_handler<Handler>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
#if defined(ASIO_NO_DEPRECATED)
return asio_handler_deallocate_is_no_longer_used();
#endif // defined(ASIO_NO_DEPRECATED)
}

template <typename Handler>
inline bool asio_handler_is_continuation(
prepend_handler<Handler>* this_handler)
{
return asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}

template <typename Function, typename Handler>
inline asio_handler_invoke_is_deprecated
asio_handler_invoke(Function& function,
prepend_handler<Handler>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
#if defined(ASIO_NO_DEPRECATED)
return asio_handler_invoke_is_no_longer_used();
#endif // defined(ASIO_NO_DEPRECATED)
}

template <typename Function, typename Handler>
inline asio_handler_invoke_is_deprecated
asio_handler_invoke(const Function& function,
prepend_handler<Handler>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
#if defined(ASIO_NO_DEPRECATED)
return asio_handler_invoke_is_no_longer_used();
#endif // defined(ASIO_NO_DEPRECATED)
}

template <typename Signature, typename... Values>
struct prepend_signature;

template <typename R, typename... Args, typename... Values>
struct prepend_signature<R(Args...), Values...>
{
typedef R type(Values..., typename decay<Args>::type...);
};

} // namespace detail
} // namespace experimental

#if !defined(GENERATING_DOCUMENTATION)

template <typename CompletionToken, typename... Values, typename Signature>
struct async_result<
experimental::prepend_t<CompletionToken, Values...>, Signature>
: async_result<CompletionToken,
typename experimental::detail::prepend_signature<
Signature, Values...>::type>
{
typedef typename experimental::detail::prepend_signature<
Signature, Values...>::type signature;

template <typename Initiation>
struct init_wrapper
{
init_wrapper(Initiation init)
: initiation_(ASIO_MOVE_CAST(Initiation)(init))
{
}

template <typename Handler, typename... Args>
void operator()(
ASIO_MOVE_ARG(Handler) handler,
std::tuple<Values...> values,
ASIO_MOVE_ARG(Args)... args)
{
ASIO_MOVE_CAST(Initiation)(initiation_)(
experimental::detail::prepend_handler<
typename decay<Handler>::type, Values...>(
ASIO_MOVE_CAST(Handler)(handler),
ASIO_MOVE_CAST(std::tuple<Values...>)(values)),
ASIO_MOVE_CAST(Args)(args)...);
}

Initiation initiation_;
};

template <typename Initiation, typename RawCompletionToken, typename... Args>
static ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, signature,
(async_initiate<CompletionToken, signature>(
declval<init_wrapper<typename decay<Initiation>::type> >(),
declval<CompletionToken&>(),
declval<std::tuple<Values...> >(),
declval<ASIO_MOVE_ARG(Args)>()...)))
initiate(
ASIO_MOVE_ARG(Initiation) initiation,
ASIO_MOVE_ARG(RawCompletionToken) token,
ASIO_MOVE_ARG(Args)... args)
{
return async_initiate<CompletionToken, signature>(
init_wrapper<typename decay<Initiation>::type>(
ASIO_MOVE_CAST(Initiation)(initiation)),
token.token_,
ASIO_MOVE_CAST(std::tuple<Values...>)(token.values_),
ASIO_MOVE_CAST(Args)(args)...);
}
};

template <template <typename, typename> class Associator,
typename Handler, typename DefaultCandidate>
struct associator<Associator,
experimental::detail::prepend_handler<Handler>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
static typename Associator<Handler, DefaultCandidate>::type get(
const experimental::detail::prepend_handler<Handler>& h,
const DefaultCandidate& c = DefaultCandidate()) ASIO_NOEXCEPT
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};

#endif // !defined(GENERATING_DOCUMENTATION)

} // namespace asio

#include "asio/detail/pop_options.hpp"

#endif // ASIO_IMPL_EXPERIMENTAL_PREPEND_HPP
71 changes: 71 additions & 0 deletions asio/include/asio/experimental/prepend.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//
// experimental/prepend.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 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_EXPERIMENTAL_PREPEND_HPP
#define ASIO_EXPERIMENTAL_PREPEND_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include "asio/detail/config.hpp"
#include <tuple>
#include "asio/detail/type_traits.hpp"

#include "asio/detail/push_options.hpp"

namespace asio {
namespace experimental {

/// Completion token type used to specify that the completion handler
/// arguments should be passed additional values before the results of the
/// operation.
template <typename CompletionToken, typename... Values>
class prepend_t
{
public:
/// Constructor.
template <typename T, typename... V>
ASIO_CONSTEXPR explicit prepend_t(
ASIO_MOVE_ARG(T) completion_token,
ASIO_MOVE_ARG(V)... values)
: token_(ASIO_MOVE_CAST(T)(completion_token)),
values_(ASIO_MOVE_CAST(V)(values)...)
{
}

//private:
CompletionToken token_;
std::tuple<Values...> values_;
};

/// Completion token type used to specify that the completion handler
/// arguments should be passed additional values before the results of the
/// operation.
template <typename CompletionToken, typename... Values>
inline ASIO_CONSTEXPR prepend_t<
typename decay<CompletionToken>::type, typename decay<Values>::type...>
prepend(ASIO_MOVE_ARG(CompletionToken) completion_token,
ASIO_MOVE_ARG(Values)... values)
{
return prepend_t<
typename decay<CompletionToken>::type, typename decay<Values>::type...>(
ASIO_MOVE_CAST(CompletionToken)(completion_token),
ASIO_MOVE_CAST(Values)(values)...);
}

} // namespace experimental
} // namespace asio

#include "asio/detail/pop_options.hpp"

#include "asio/experimental/impl/prepend.hpp"

#endif // ASIO_EXPERIMENTAL_PREPEND_HPP

0 comments on commit d6735d4

Please sign in to comment.