1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
* Ceph - scalable distributed file system
*
* Copyright (C) 2018 Red Hat
*
* This is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software
* Foundation. See file COPYING.
*
*/
#ifndef CEPH_ASYNC_BIND_HANDLER_H
#define CEPH_ASYNC_BIND_HANDLER_H
#include <tuple>
#include <boost/asio.hpp>
namespace ceph::async {
/**
* A bound completion handler for use with boost::asio.
*
* A completion handler wrapper that allows a tuple of arguments to be forwarded
* to the original Handler. This is intended for use with boost::asio functions
* like defer(), dispatch() and post() which expect handlers which are callable
* with no arguments.
*
* The original Handler's associated allocator and executor are maintained.
*
* @see bind_handler
*/
template <typename Handler, typename Tuple>
struct CompletionHandler {
Handler handler;
Tuple args;
CompletionHandler(Handler&& handler, Tuple&& args)
: handler(std::move(handler)),
args(std::move(args))
{}
void operator()() & {
std::apply(handler, args);
}
void operator()() const & {
std::apply(handler, args);
}
void operator()() && {
std::apply(std::move(handler), std::move(args));
}
using allocator_type = boost::asio::associated_allocator_t<Handler>;
allocator_type get_allocator() const noexcept {
return boost::asio::get_associated_allocator(handler);
}
};
} // namespace ceph::async
namespace boost::asio {
// specialize boost::asio::associated_executor<> for CompletionHandler
template <typename Handler, typename Tuple, typename Executor>
struct associated_executor<ceph::async::CompletionHandler<Handler, Tuple>, Executor> {
using type = boost::asio::associated_executor_t<Handler, Executor>;
static type get(const ceph::async::CompletionHandler<Handler, Tuple>& handler,
const Executor& ex = Executor()) noexcept {
return boost::asio::get_associated_executor(handler.handler, ex);
}
};
} // namespace boost::asio
namespace ceph::async {
/**
* Returns a wrapped completion handler with bound arguments.
*
* Binds the given arguments to a handler, and returns a CompletionHandler that
* is callable with no arguments. This is similar to std::bind(), except that
* all arguments must be provided. Move-only argument types are supported as
* long as the CompletionHandler's 'operator() &&' overload is used, i.e.
* std::move(handler)().
*
* Example use:
*
* // bind the arguments (5, "hello") to a callback lambda:
* auto callback = [] (int a, std::string b) {};
* auto handler = bind_handler(callback, 5, "hello");
*
* // execute the bound handler on an io_context:
* boost::asio::io_context context;
* boost::asio::post(context, std::move(handler));
* context.run();
*
* @see CompletionHandler
*/
template <typename Handler, typename ...Args>
auto bind_handler(Handler&& h, Args&& ...args)
{
return CompletionHandler{std::forward<Handler>(h),
std::make_tuple(std::forward<Args>(args)...)};
}
} // namespace ceph::async
#endif // CEPH_ASYNC_BIND_HANDLER_H
|