/* * Copyright (c) 2017-2023 zhllxt * * author : zhllxt * email : 37792738@qq.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 __ASIO2_RDC_INVOKER_HPP__ #define __ASIO2_RDC_INVOKER_HPP__ #if defined(_MSC_VER) && (_MSC_VER >= 1200) #pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include #include #include #include #include #include #include #include #include #include #include #include namespace asio2::detail { template struct rdc_make_callback_t { using self = rdc_make_callback_t; using callback_type = std::function; /** * @brief bind a rdc function */ template static inline callback_type bind(F&& fun, C&&... obj) { return self::_bind(std::forward(fun), std::forward(obj)...); } protected: template static inline callback_type _bind(F f) { return std::bind(&self::template _proxy, std::move(f), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); } template static inline callback_type _bind(F f, C& c) { return std::bind(&self::template _proxy, std::move(f), std::addressof(c), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); } template static inline callback_type _bind(F f, C* c) { return std::bind(&self::template _proxy, std::move(f), c, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); } template static inline void _proxy(F& f, const error_code& ec, SendDataT send_data, RecvDataT recv_data) { detail::ignore_unused(send_data); using fun_traits_type = function_traits; using arg_type = typename std::remove_cv_t::type>; set_last_error(ec); if constexpr (std::is_reference_v) { f(recv_data); } else { if (ec) { arg_type result; f(std::move(result)); return; } if /**/ constexpr (has_stream_operator::value) { arg_type result; result << recv_data; f(std::move(result)); } else if constexpr (has_equal_operator::value) { arg_type result; result = recv_data; f(std::move(result)); } else { arg_type result{ recv_data }; f(std::move(result)); } } } template static inline void _proxy(F& f, C* c, const error_code& ec, SendDataT send_data, RecvDataT recv_data) { detail::ignore_unused(send_data); using fun_traits_type = function_traits; using arg_type = typename std::remove_cv_t::type>; set_last_error(ec); if constexpr (std::is_reference_v) { (c->*f)(recv_data); } else { if (ec) { arg_type result; (c->*f)(std::move(result)); return; } if /**/ constexpr (has_stream_operator::value) { arg_type result; result << recv_data; (c->*f)(std::move(result)); } else if constexpr (has_equal_operator::value) { arg_type result; result = recv_data; (c->*f)(std::move(result)); } else { arg_type result{ recv_data }; (c->*f)(std::move(result)); } } } }; template class rdc_invoker_t { public: using self = rdc_invoker_t; using callback_type = typename rdc_make_callback_t::callback_type; using value_type = std::tuple, callback_type>; using iterator_type = typename std::multimap::iterator; /** * @brief constructor */ rdc_invoker_t() = default; /** * @brief destructor */ ~rdc_invoker_t() = default; rdc_invoker_t(rdc_invoker_t&&) = default; rdc_invoker_t(rdc_invoker_t const&) = default; rdc_invoker_t& operator=(rdc_invoker_t&&) = default; rdc_invoker_t& operator=(rdc_invoker_t const&) = default; /** * @brief find binded rdc function iterator by id */ inline auto find(IdT const& id) { // can't use std::multimap::find // std::multimap::find // Finds an element with key equivalent to key. If there are several elements // with key in the container, any of them may be returned. auto it = this->rdc_reqs_.lower_bound(id); if (it == this->rdc_reqs_.end()) return it; // [20220402] fix bug // Returns an iterator pointing to the first element that is not less than // (i.e. greater or equal to) key. // when multimap has {2,2} {3,3} if you find key 1, the map will return {2,2} if (it->first == id) return it; return this->rdc_reqs_.end(); } /** * @brief */ inline auto emplace(IdT id, std::shared_ptr timer, callback_type cb) { // std::multimap::insert // inserts value. If the container has elements with equivalent key, // inserts at the upper bound of that range.(since C++11) return this->rdc_reqs_.insert(std::pair(std::move(id), std::tuple(std::move(timer), std::move(cb)))); } /** * @brief */ inline auto emplace(IdT key, value_type val) { return this->rdc_reqs_.insert(std::pair(std::move(key), std::move(val))); } /** * @brief */ inline auto end() { return this->rdc_reqs_.end(); } /** * @brief */ template inline auto erase(Iter iter) { return this->rdc_reqs_.erase(iter); } /** * @brief */ inline std::multimap& reqs() noexcept { return this->rdc_reqs_; } protected: std::multimap rdc_reqs_; }; } #endif // !__ASIO2_RDC_INVOKER_HPP__