rdc_invoker.hpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*
  2. * Copyright (c) 2017-2023 zhllxt
  3. *
  4. * author : zhllxt
  5. * email : 37792738@qq.com
  6. *
  7. * Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. */
  10. #ifndef __ASIO2_RDC_INVOKER_HPP__
  11. #define __ASIO2_RDC_INVOKER_HPP__
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. #pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <cstdint>
  16. #include <memory>
  17. #include <functional>
  18. #include <string>
  19. #include <string_view>
  20. #include <tuple>
  21. #include <map>
  22. #include <type_traits>
  23. #include <asio2/base/iopool.hpp>
  24. #include <asio2/base/detail/function_traits.hpp>
  25. #include <asio2/base/detail/util.hpp>
  26. #include <asio2/util/string.hpp>
  27. namespace asio2::detail
  28. {
  29. template<class SendDataT, class RecvDataT>
  30. struct rdc_make_callback_t
  31. {
  32. using self = rdc_make_callback_t<SendDataT, RecvDataT>;
  33. using callback_type = std::function<void(const error_code&, SendDataT, RecvDataT)>;
  34. /**
  35. * @brief bind a rdc function
  36. */
  37. template<class F, class ...C>
  38. static inline callback_type bind(F&& fun, C&&... obj)
  39. {
  40. return self::_bind(std::forward<F>(fun), std::forward<C>(obj)...);
  41. }
  42. protected:
  43. template<class F>
  44. static inline callback_type _bind(F f)
  45. {
  46. return std::bind(&self::template _proxy<F>, std::move(f),
  47. std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
  48. }
  49. template<class F, class C>
  50. static inline callback_type _bind(F f, C& c)
  51. {
  52. return std::bind(&self::template _proxy<F, C>, std::move(f), std::addressof(c),
  53. std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
  54. }
  55. template<class F, class C>
  56. static inline callback_type _bind(F f, C* c)
  57. {
  58. return std::bind(&self::template _proxy<F, C>, std::move(f), c,
  59. std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
  60. }
  61. template<class F>
  62. static inline void _proxy(F& f, const error_code& ec, SendDataT send_data, RecvDataT recv_data)
  63. {
  64. detail::ignore_unused(send_data);
  65. using fun_traits_type = function_traits<F>;
  66. using arg_type = typename std::remove_cv_t<typename fun_traits_type::template args<0>::type>;
  67. set_last_error(ec);
  68. if constexpr (std::is_reference_v<arg_type>)
  69. {
  70. f(recv_data);
  71. }
  72. else
  73. {
  74. if (ec)
  75. {
  76. arg_type result;
  77. f(std::move(result));
  78. return;
  79. }
  80. if /**/ constexpr (has_stream_operator<arg_type, RecvDataT>::value)
  81. {
  82. arg_type result;
  83. result << recv_data;
  84. f(std::move(result));
  85. }
  86. else if constexpr (has_equal_operator<arg_type, RecvDataT>::value)
  87. {
  88. arg_type result;
  89. result = recv_data;
  90. f(std::move(result));
  91. }
  92. else
  93. {
  94. arg_type result{ recv_data };
  95. f(std::move(result));
  96. }
  97. }
  98. }
  99. template<class F, class C>
  100. static inline void _proxy(F& f, C* c, const error_code& ec, SendDataT send_data, RecvDataT recv_data)
  101. {
  102. detail::ignore_unused(send_data);
  103. using fun_traits_type = function_traits<F>;
  104. using arg_type = typename std::remove_cv_t<typename fun_traits_type::template args<0>::type>;
  105. set_last_error(ec);
  106. if constexpr (std::is_reference_v<arg_type>)
  107. {
  108. (c->*f)(recv_data);
  109. }
  110. else
  111. {
  112. if (ec)
  113. {
  114. arg_type result;
  115. (c->*f)(std::move(result));
  116. return;
  117. }
  118. if /**/ constexpr (has_stream_operator<arg_type, RecvDataT>::value)
  119. {
  120. arg_type result;
  121. result << recv_data;
  122. (c->*f)(std::move(result));
  123. }
  124. else if constexpr (has_equal_operator<arg_type, RecvDataT>::value)
  125. {
  126. arg_type result;
  127. result = recv_data;
  128. (c->*f)(std::move(result));
  129. }
  130. else
  131. {
  132. arg_type result{ recv_data };
  133. (c->*f)(std::move(result));
  134. }
  135. }
  136. }
  137. };
  138. template<class IdT, class SendDataT, class RecvDataT>
  139. class rdc_invoker_t
  140. {
  141. public:
  142. using self = rdc_invoker_t<IdT, SendDataT, RecvDataT>;
  143. using callback_type = typename rdc_make_callback_t<SendDataT, RecvDataT>::callback_type;
  144. using value_type = std::tuple<std::shared_ptr<asio::steady_timer>, callback_type>;
  145. using iterator_type = typename std::multimap<IdT, value_type>::iterator;
  146. /**
  147. * @brief constructor
  148. */
  149. rdc_invoker_t() = default;
  150. /**
  151. * @brief destructor
  152. */
  153. ~rdc_invoker_t() = default;
  154. rdc_invoker_t(rdc_invoker_t&&) = default;
  155. rdc_invoker_t(rdc_invoker_t const&) = default;
  156. rdc_invoker_t& operator=(rdc_invoker_t&&) = default;
  157. rdc_invoker_t& operator=(rdc_invoker_t const&) = default;
  158. /**
  159. * @brief find binded rdc function iterator by id
  160. */
  161. inline auto find(IdT const& id)
  162. {
  163. // can't use std::multimap::find
  164. // std::multimap<Key,T,Compare,Allocator>::find
  165. // Finds an element with key equivalent to key. If there are several elements
  166. // with key in the container, any of them may be returned.
  167. auto it = this->rdc_reqs_.lower_bound(id);
  168. if (it == this->rdc_reqs_.end())
  169. return it;
  170. // [20220402] fix bug
  171. // Returns an iterator pointing to the first element that is not less than
  172. // (i.e. greater or equal to) key.
  173. // when multimap has {2,2} {3,3} if you find key 1, the map will return {2,2}
  174. if (it->first == id)
  175. return it;
  176. return this->rdc_reqs_.end();
  177. }
  178. /**
  179. * @brief
  180. */
  181. inline auto emplace(IdT id, std::shared_ptr<asio::steady_timer> timer, callback_type cb)
  182. {
  183. // std::multimap<Key,T,Compare,Allocator>::insert
  184. // inserts value. If the container has elements with equivalent key,
  185. // inserts at the upper bound of that range.(since C++11)
  186. return this->rdc_reqs_.insert(std::pair(std::move(id), std::tuple(std::move(timer), std::move(cb))));
  187. }
  188. /**
  189. * @brief
  190. */
  191. inline auto emplace(IdT key, value_type val)
  192. {
  193. return this->rdc_reqs_.insert(std::pair(std::move(key), std::move(val)));
  194. }
  195. /**
  196. * @brief
  197. */
  198. inline auto end()
  199. {
  200. return this->rdc_reqs_.end();
  201. }
  202. /**
  203. * @brief
  204. */
  205. template<class Iter>
  206. inline auto erase(Iter iter)
  207. {
  208. return this->rdc_reqs_.erase(iter);
  209. }
  210. /**
  211. * @brief
  212. */
  213. inline std::multimap<IdT, value_type>& reqs() noexcept
  214. {
  215. return this->rdc_reqs_;
  216. }
  217. protected:
  218. std::multimap<IdT, value_type> rdc_reqs_;
  219. };
  220. }
  221. #endif // !__ASIO2_RDC_INVOKER_HPP__