blob: b8158b4731ee8b2c1018d48defd5ab040a79ea3e [file] [log] [blame]
//
// package.hpp
// ~~~~~~~~~~~
//
// Copyright (c) 2003-2015 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_USE_PACKAGE_HPP
#define ASIO_USE_PACKAGE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <future>
#include <memory>
#include "asio/async_result.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/variadic_templates.hpp"
#include "asio/handler_type.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// Class to enable lazy construction of a packaged_task from a completion
/// token.
/**
* The packaged_token class is used to adapt a function object as a packaged
* task. When this adapter is passed as a completion token to an asynchronous
* operation, the result of the function object is retuned via a std::future.
*
* Use the @ref package function rather than using this class directly.
*/
template <typename Function, typename Allocator = std::allocator<void> >
class packaged_token
{
public:
/// The allocator type. The allocator is used when constructing the
/// @c std::promise object for a given asynchronous operation.
typedef Allocator allocator_type;
/// Construct using specified allocator.
explicit packaged_token(Function f)
: func_(std::move(f))
{
}
/// Construct using specified allocator.
packaged_token(Function f, const Allocator& allocator)
: func_(std::move(f)),
allocator_(allocator)
{
}
/// Obtain allocator.
allocator_type get_allocator() const ASIO_NOEXCEPT
{
return allocator_;
}
private:
template <class, class> friend class packaged_handler;
Function func_;
Allocator allocator_;
};
/// A packaged_task with an associated allocator.
template <typename Signature, typename Allocator>
class packaged_handler : public std::packaged_task<Signature>
{
public:
/// The allocator type. The allocator is used when constructing the
/// @c std::promise object for a given asynchronous operation.
typedef Allocator allocator_type;
/// Construct from a packaged token.
template <typename Function>
packaged_handler(
packaged_token<Function, Allocator>&& token)
#if defined(_MSC_VER)
: std::packaged_task<Signature>(std::move(token.func_)),
#elif defined(ASIO_HAS_CLANG_LIBCXX)
: std::packaged_task<Signature>(std::allocator_arg,
typename std::allocator_traits<
Allocator>::template rebind_alloc<char>(token.allocator_),
std::move(token.func_)),
#else
: std::packaged_task<Signature>(std::allocator_arg,
token.allocator_, std::move(token.func_)),
#endif
allocator_(token.allocator_)
{
}
/// Move construct from another packaged handler.
packaged_handler(packaged_handler&& other)
: std::packaged_task<Signature>(
static_cast<std::packaged_task<Signature>&&>(other)),
allocator_(other.allocator_)
{
}
/// Obtain allocator.
allocator_type get_allocator() const ASIO_NOEXCEPT
{
return allocator_;
}
private:
Allocator allocator_;
};
/// Wrap a function object in a packaged task.
/**
* The @c package function is used to adapt a function object as a packaged
* task. When this adapter is passed as a completion token to an asynchronous
* operation, the result of the function object is retuned via a std::future.
*
* @par Example
*
* @code std::future<std::size_t> fut =
* my_socket.async_read_some(buffer,
* package([](asio::error_code ec, std::size_t n)
* {
* return ec ? 0 : n;
* }));
* ...
* std::size_t n = fut.get(); @endcode
*/
template <typename Function>
inline packaged_token<typename decay<Function>::type, std::allocator<void> >
package(ASIO_MOVE_ARG(Function) function)
{
return packaged_token<typename decay<Function>::type, std::allocator<void> >(
ASIO_MOVE_CAST(Function)(function), std::allocator<void>());
}
/// Wrap a function object in a packaged task.
/**
* The @c package function is used to adapt a function object as a packaged
* task. When this adapter is passed as a completion token to an asynchronous
* operation, the result of the function object is retuned via a std::future.
*
* @par Example
*
* @code std::future<std::size_t> fut =
* my_socket.async_read_some(buffer,
* package([](asio::error_code ec, std::size_t n)
* {
* return ec ? 0 : n;
* }));
* ...
* std::size_t n = fut.get(); @endcode
*/
template <typename Function, typename Allocator>
inline packaged_token<typename decay<Function>::type, Allocator> package(
ASIO_MOVE_ARG(Function) function, const Allocator& a)
{
return packaged_token<typename decay<Function>::type, Allocator>(
ASIO_MOVE_CAST(Function)(function), a);
}
#if !defined(GENERATING_DOCUMENTATION)
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Function, typename Allocator, typename R, typename... Args>
struct handler_type<packaged_token<Function, Allocator>, R(Args...)>
{
typedef packaged_handler<
typename result_of<Function(Args...)>::type(Args...),
Allocator> type;
};
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Function, typename Allocator, typename R>
struct handler_type<packaged_token<Function, Allocator>, R()>
{
typedef packaged_handler<
typename result_of<Function()>::type(),
Allocator> type;
};
#define ASIO_PRIVATE_HANDLER_TYPE_DEF(n) \
template <typename Function, typename Allocator, \
typename R, ASIO_VARIADIC_TPARAMS(n)> \
struct handler_type< \
packaged_token<Function, Allocator>, R(ASIO_VARIADIC_TARGS(n))> \
{ \
typedef packaged_handler< \
typename result_of< \
Function(ASIO_VARIADIC_TARGS(n))>::type( \
ASIO_VARIADIC_TARGS(n)), \
Allocator> type; \
}; \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_HANDLER_TYPE_DEF)
#undef ASIO_PRIVATE_HANDLER_TYPE_DEF
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename R, typename... Args>
class async_result<std::packaged_task<R(Args...)> >
{
public:
typedef std::future<R> type;
explicit async_result(std::packaged_task<R(Args...)>& h)
: future_(h.get_future())
{
}
type get()
{
return std::move(future_);
}
private:
type future_;
};
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename R>
class async_result<std::packaged_task<R()> >
{
public:
typedef std::future<R> type;
explicit async_result(std::packaged_task<R()>& h)
: future_(h.get_future())
{
}
type get()
{
return std::move(future_);
}
private:
type future_;
};
#define ASIO_PRIVATE_ASYNC_RESULT_DEF(n) \
template <typename R, ASIO_VARIADIC_TPARAMS(n)> \
class async_result<std::packaged_task<R(ASIO_VARIADIC_TARGS(n))> > \
{ \
public: \
typedef std::future<R> type; \
\
explicit async_result( \
std::packaged_task<R(ASIO_VARIADIC_TARGS(n))>& h) \
: future_(h.get_future()) \
{ \
} \
\
type get() \
{ \
return std::move(future_); \
} \
\
private: \
type future_; \
}; \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ASYNC_RESULT_DEF)
#undef ASIO_PRIVATE_ASYNC_RESULT_DEF
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Signature, typename Allocator>
class async_result<packaged_handler<Signature, Allocator>>
: public async_result<std::packaged_task<Signature>>
{
public:
explicit async_result(packaged_handler<Signature, Allocator>& h)
: async_result<std::packaged_task<Signature>>(h) {}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_USE_PACKAGE_HPP