CppWAMP
C++11 client library for the WAMP protocol
anyhandler.hpp
Go to the documentation of this file.
1 /*------------------------------------------------------------------------------
2  Copyright Butterfly Energy Systems 2022.
3  Distributed under the Boost Software License, Version 1.0.
4  http://www.boost.org/LICENSE_1_0.txt
5 ------------------------------------------------------------------------------*/
6 
7 #ifndef CPPWAMP_ANYHANDLER_HPP
8 #define CPPWAMP_ANYHANDLER_HPP
9 
10 //------------------------------------------------------------------------------
13 //------------------------------------------------------------------------------
14 
15 #include <cassert>
16 #include <cstddef>
17 #include <memory>
18 #include <functional>
19 #include <utility>
20 #include <tuple>
21 #include <type_traits>
22 #include <boost/asio/associated_allocator.hpp>
23 #include <boost/asio/associated_cancellation_slot.hpp>
24 #include <boost/asio/associated_executor.hpp>
25 #include <boost/asio/cancellation_signal.hpp>
26 #include <boost/asio/defer.hpp>
27 #include <boost/asio/dispatch.hpp>
28 #include <boost/asio/post.hpp>
29 
30 #ifdef CPPWAMP_WITHOUT_BUNDLED_ASIO_ANY_COMPLETION_HANDLER
31 #include <boost/asio/any_completion_handler.hpp>
32 #else
33 #include "bundled/boost_asio_any_completion_handler.hpp"
34 #endif
35 
36 namespace wamp
37 {
38 
39 //------------------------------------------------------------------------------
41 //------------------------------------------------------------------------------
42 using AnyCompletionExecutor = boost::asio::any_completion_executor;
43 
44 
45 //------------------------------------------------------------------------------
53 //------------------------------------------------------------------------------
54 template <typename TSignature>
55 using AnyCompletionHandler = boost::asio::any_completion_handler<TSignature>;
56 
57 
58 //------------------------------------------------------------------------------
65 //------------------------------------------------------------------------------
66 template <typename TSignature>
68 {
69 private:
70  using Function = std::function<TSignature>;
71 
72  template <typename F>
73  static constexpr bool fnConstructible() noexcept
74  {
75  using Decayed = typename std::decay<F>::type;
76  return !std::is_same<Decayed, AnyReusableHandler>::value &&
77  !std::is_same<Decayed, std::nullptr_t>::value &&
78  std::is_constructible<Function, F>::value;
79  }
80 
81  template <typename F>
82  static constexpr bool otherConstructible() noexcept
83  {
84  return std::is_constructible<Function, std::function<F>>::value;
85  }
86 
87 public:
90 
92  using CancellationSlot = boost::asio::cancellation_slot;
93 
96 
99 
101  AnyReusableHandler() = default;
102 
104  AnyReusableHandler(const AnyReusableHandler&) = default;
105 
107  AnyReusableHandler(AnyReusableHandler&&) noexcept = default;
108 
114  template <typename S,
115  typename std::enable_if<otherConstructible<S>(), int>::type = 0>
117  : executor_(rhs.executor_),
118  handler_(rhs.handler_)
119  {}
120 
126  template <typename S,
127  typename std::enable_if<otherConstructible<S>(), int>::type = 0>
129  : executor_(std::move(rhs.executor_)),
130  handler_(std::move(rhs.handler_))
131  {}
132 
139  template <typename F,
140  typename std::enable_if<fnConstructible<F>(), int>::type = 0>
141  AnyReusableHandler(F&& handler)
142  : executor_(boost::asio::get_associated_executor(
143  handler, AnyCompletionExecutor{})),
144  cancelSlot_(boost::asio::get_associated_cancellation_slot(handler)),
145  handler_(std::forward<F>(handler))
146  {}
147 
149  AnyReusableHandler(std::nullptr_t) noexcept {}
150 
152  AnyReusableHandler& operator=(std::nullptr_t) noexcept
153  {
154  executor_ = nullptr;
155  handler_ = nullptr;
156  return *this;
157  }
158 
161 
163  AnyReusableHandler& operator=(AnyReusableHandler&&) noexcept = default;
164 
166  void swap(AnyReusableHandler& rhs) noexcept
167  {
168  // boost::asio::executor does not have member swap
169  using std::swap;
170  swap(executor_, rhs.executor_);
171 
172  handler_.swap(rhs.handler_);
173  }
174 
176  explicit operator bool() const noexcept {return bool(handler_);}
177 
179  const Executor& get_executor() const {return executor_;}
180 
182  const CancellationSlot& get_cancellation_slot() const {return cancelSlot_;}
183 
185  template <typename... Ts>
186  auto operator()(Ts&&... args) const
187  -> decltype(std::declval<Function>()(std::forward<Ts>(args)...))
188  {
189  return handler_(std::forward<Ts>(args)...);
190  }
191 
192 private:
193  Executor executor_;
194  CancellationSlot cancelSlot_;
195  Function handler_;
196 };
197 
199 template <typename S>
201 {
202  return a.swap(b);
203 }
204 
206 template <typename S>
207 bool operator==(const AnyReusableHandler<S>& f, std::nullptr_t) noexcept
208 {
209  return !f;
210 }
211 
213 template <typename S>
214 bool operator==(std::nullptr_t, const AnyReusableHandler<S>& f) noexcept
215 {
216  return !f;
217 }
218 
220 template <typename S>
221 bool operator!=(const AnyReusableHandler<S>& f, std::nullptr_t) noexcept
222 {
223  return bool(f);
224 }
225 
227 template <typename S>
228 bool operator!=(std::nullptr_t, const AnyReusableHandler<S>& f) noexcept
229 {
230  return bool(f);
231 }
232 
233 } // namespace wamp
234 
235 
236 namespace boost
237 {
238 namespace asio
239 {
240 
241 // Enable boost::asio::get_associated_executor for AnyReusableHandler.
242 template <typename S, typename E>
243 struct associated_executor<wamp::AnyReusableHandler<S>, E>
244 {
245  using type = typename wamp::AnyReusableHandler<S>::Executor;
246 
247  static type get(const wamp::AnyReusableHandler<S>& f, const E& e = E{})
248  {
249  return f.get_executor() ? f.get_executor() : e;
250  }
251 };
252 
253 // Enable boost::asio::get_associated_cancellation_slot for AnyReusableHandler.
254 template <typename S, typename C>
255 struct associated_cancellation_slot<wamp::AnyReusableHandler<S>, C>
256 {
257  using type = typename wamp::AnyReusableHandler<S>::CancellationSlot;
258 
259  static type get(const wamp::AnyReusableHandler<S>& f, const C& = C{})
260  {
261  return f.get_cancellation_slot();
262  }
263 };
264 
265 // Enable boost::asio::get_associated_allocator for AnyReusableHandler.
266 template <typename S, typename A>
267 struct associated_allocator<wamp::AnyReusableHandler<S>, A>
268 {
269  using type = A;
270 
271  static type get(const wamp::AnyReusableHandler<S>&, const A& a = A{})
272  {
273  // AnyReusableHandler does not use allocators, so always return
274  // the fallback allocator.
275  return a;
276  }
277 };
278 
279 } // namespace asio
280 } // namespace boost
281 
282 
283 namespace wamp
284 {
285 
286 //------------------------------------------------------------------------------
289 //------------------------------------------------------------------------------
290 template <typename F, typename... Ts>
291 void dispatchAny(F&& handler, Ts&&... args)
292 {
293  auto e = boost::asio::get_associated_executor(handler);
294  boost::asio::dispatch(e, std::bind(std::forward<F>(handler),
295  std::forward<Ts>(args)...));
296 }
297 
298 //------------------------------------------------------------------------------
301 //------------------------------------------------------------------------------
302 template<typename F, typename E, typename... Ts>
303 void dispatchVia(const E& fallbackExec, F&& handler, Ts&&... args)
304 {
305  auto e = boost::asio::get_associated_executor(handler, fallbackExec);
306  boost::asio::dispatch(e, std::bind(std::forward<F>(handler),
307  std::forward<Ts>(args)...));
308 }
309 
310 //------------------------------------------------------------------------------
313 //------------------------------------------------------------------------------
314 template<typename F, typename... Ts>
315 void postAny(F&& handler, Ts&&... args)
316 {
317  auto e = boost::asio::get_associated_executor(handler);
318  boost::asio::post(e, std::bind(std::forward<F>(handler),
319  std::forward<Ts>(args)...));
320 }
321 
322 //------------------------------------------------------------------------------
325 //------------------------------------------------------------------------------
326 template<typename F, typename E, typename... Ts>
327 void postVia(const E& fallbackExec, F&& handler, Ts&&... args)
328 {
329  auto e = boost::asio::get_associated_executor(handler, fallbackExec);
330  boost::asio::post(e, std::bind(std::forward<F>(handler),
331  std::forward<Ts>(args)...));
332 }
333 
334 //------------------------------------------------------------------------------
337 //------------------------------------------------------------------------------
338 template<typename F, typename... Ts>
339 void deferAny(F&& handler, Ts&&... args)
340 {
341  auto e = boost::asio::get_associated_executor(handler);
342  boost::asio::defer(e, std::bind(std::forward<F>(handler),
343  std::forward<Ts>(args)...));
344 }
345 
346 //------------------------------------------------------------------------------
349 //------------------------------------------------------------------------------
350 template<typename F, typename E, typename... Ts>
351 void deferVia(const E& fallbackExec, F&& handler, Ts&&... args)
352 {
353  auto e = boost::asio::get_associated_executor(handler, fallbackExec);
354  boost::asio::defer(e, std::bind(std::forward<F>(handler),
355  std::forward<Ts>(args)...));
356 }
357 
358 } // namespace wamp
359 
360 #endif // CPPWAMP_ANYHANDLER_HPP
wamp::deferVia
void deferVia(const E &fallbackExec, F &&handler, Ts &&... args)
Defers the given handler using the given fallback executor, passing the given arguments.
Definition: anyhandler.hpp:351
wamp::dispatchVia
void dispatchVia(const E &fallbackExec, F &&handler, Ts &&... args)
Dispatches the given handler using the given fallback executor, passing the given arguments.
Definition: anyhandler.hpp:303
wamp::AnyReusableHandler::operator()
auto operator()(Ts &&... args) const -> decltype(std::declval< Function >()(std::forward< Ts >(args)...))
Invokes the handler with the given arguments.
Definition: anyhandler.hpp:186
wamp::deferAny
void deferAny(F &&handler, Ts &&... args)
Defers the given handler using its associated executor, passing the given arguments.
Definition: anyhandler.hpp:339
wamp::AnyReusableHandler::get_executor
const Executor & get_executor() const
Obtains the executor associated with this handler.
Definition: anyhandler.hpp:179
wamp::AnyReusableHandler::operator==
bool operator==(std::nullptr_t, const AnyReusableHandler< S > &f) noexcept
Returns true is the given handler is empty.
Definition: anyhandler.hpp:214
wamp::AnyReusableHandler::operator!=
bool operator!=(std::nullptr_t, const AnyReusableHandler< S > &f) noexcept
Returns false is the given handler is empty.
Definition: anyhandler.hpp:228
wamp::AnyReusableHandler
Type-erases a multi-shot, copyable callback handler.
Definition: anyhandler.hpp:67
wamp::AnyReusableHandler< State >::executor_type
Executor executor_type
Asio-conformant type alias.
Definition: anyhandler.hpp:95
wamp::AnyReusableHandler::AnyReusableHandler
AnyReusableHandler(F &&handler)
Constructor taking a callable entity.
Definition: anyhandler.hpp:141
wamp::dispatchAny
void dispatchAny(F &&handler, Ts &&... args)
Dispatches the given handler using its associated executor, passing the given arguments.
Definition: anyhandler.hpp:291
wamp::AnyReusableHandler::operator!=
bool operator!=(const AnyReusableHandler< S > &f, std::nullptr_t) noexcept
Returns false is the given handler is empty.
Definition: anyhandler.hpp:221
wamp::postAny
void postAny(F &&handler, Ts &&... args)
Posts the given handler using its associated executor, passing the given arguments.
Definition: anyhandler.hpp:315
wamp::AnyCompletionExecutor
boost::asio::any_completion_executor AnyCompletionExecutor
Type-erases an executor that is to be used with type-erased handlers.
Definition: anyhandler.hpp:42
wamp::AnyReusableHandler< State >::cancellation_slot_type
CancellationSlot cancellation_slot_type
Asio-conformant type alias.
Definition: anyhandler.hpp:98
wamp
Definition: anyhandler.hpp:36
wamp::AnyReusableHandler::AnyReusableHandler
AnyReusableHandler(std::nullptr_t) noexcept
Constructs an empty AnyReusableHandler.
Definition: anyhandler.hpp:149
wamp::AnyReusableHandler::swap
void swap(AnyReusableHandler &rhs) noexcept
Swaps contents with another AnyReusableHandler.
Definition: anyhandler.hpp:166
wamp::AnyReusableHandler< State >::CancellationSlot
boost::asio::cancellation_slot CancellationSlot
Cancellation slot type used by this handler.
Definition: anyhandler.hpp:92
wamp::AnyReusableHandler::operator==
bool operator==(const AnyReusableHandler< S > &f, std::nullptr_t) noexcept
Returns true is the given handler is empty.
Definition: anyhandler.hpp:207
wamp::AnyReusableHandler::operator=
AnyReusableHandler & operator=(std::nullptr_t) noexcept
Renders an AnyReusableHandler empty.
Definition: anyhandler.hpp:152
wamp::AnyReusableHandler::AnyReusableHandler
AnyReusableHandler(AnyReusableHandler< S > &&rhs) noexcept
Constructor moving another AnyReusableHandler with a different signature.
Definition: anyhandler.hpp:128
wamp::AnyReusableHandler::get_cancellation_slot
const CancellationSlot & get_cancellation_slot() const
Obtains the cancellation slot associated with this handler.
Definition: anyhandler.hpp:182
wamp::AnyReusableHandler< State >::Executor
AnyCompletionExecutor Executor
Polymorphic wrapper around the executor associated with this handler.
Definition: anyhandler.hpp:89
wamp::AnyReusableHandler::AnyReusableHandler
AnyReusableHandler()=default
Default constructor.
wamp::AnyReusableHandler::swap
void swap(AnyReusableHandler< S > &a, AnyReusableHandler< S > &b) noexcept
Non-member swap.
Definition: anyhandler.hpp:200
wamp::postVia
void postVia(const E &fallbackExec, F &&handler, Ts &&... args)
Posts the given handler using the given fallback executor, passing the given arguments.
Definition: anyhandler.hpp:327
wamp::AnyCompletionHandler
boost::asio::any_completion_handler< TSignature > AnyCompletionHandler
Type-erases a one-shot (and possibly move-only) asynchronous completion handler.
Definition: anyhandler.hpp:55