util.hpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939
  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_UTIL_HPP__
  11. #define __ASIO2_UTIL_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 <cstdarg>
  17. #include <cstdio>
  18. #include <cwchar>
  19. #include <climits>
  20. #include <cctype>
  21. #include <string>
  22. #include <string_view>
  23. #include <type_traits>
  24. #include <memory>
  25. #include <future>
  26. #include <functional>
  27. #include <tuple>
  28. #include <utility>
  29. #include <atomic>
  30. #include <limits>
  31. #include <thread>
  32. #include <mutex>
  33. #include <asio2/base/error.hpp>
  34. #include <asio2/base/detail/filesystem.hpp>
  35. #include <asio2/base/detail/shared_mutex.hpp>
  36. #include <asio2/base/detail/type_traits.hpp>
  37. #include <asio2/util/string.hpp>
  38. //
  39. // you can define this macro before include asio2 files to use custom ssl method.
  40. // eg:
  41. // #define ASIO2_DEFAULT_SSL_METHOD asio::ssl::context::tlsv13
  42. // #include <asio2/asio2.hpp>
  43. //
  44. #ifndef ASIO2_DEFAULT_SSL_METHOD
  45. #define ASIO2_DEFAULT_SSL_METHOD asio::ssl::context::sslv23
  46. #endif
  47. namespace asio2
  48. {
  49. template<typename = void>
  50. inline std::string to_string(const asio::const_buffer& v) noexcept
  51. {
  52. return std::string{ (std::string::pointer)(v.data()), v.size() };
  53. }
  54. template<typename = void>
  55. inline std::string to_string(const asio::mutable_buffer& v) noexcept
  56. {
  57. return std::string{ (std::string::pointer)(v.data()), v.size() };
  58. }
  59. #if !defined(ASIO_NO_DEPRECATED) && !defined(BOOST_ASIO_NO_DEPRECATED)
  60. template<typename = void>
  61. inline std::string to_string(const asio::const_buffers_1& v) noexcept
  62. {
  63. return std::string{ (std::string::pointer)(v.data()), v.size() };
  64. }
  65. template<typename = void>
  66. inline std::string to_string(const asio::mutable_buffers_1& v) noexcept
  67. {
  68. return std::string{ (std::string::pointer)(v.data()), v.size() };
  69. }
  70. #endif
  71. template<typename = void>
  72. inline std::string_view to_string_view(const asio::const_buffer& v) noexcept
  73. {
  74. return std::string_view{ (std::string_view::const_pointer)(v.data()), v.size() };
  75. }
  76. template<typename = void>
  77. inline std::string_view to_string_view(const asio::mutable_buffer& v) noexcept
  78. {
  79. return std::string_view{ (std::string_view::const_pointer)(v.data()), v.size() };
  80. }
  81. #if !defined(ASIO_NO_DEPRECATED) && !defined(BOOST_ASIO_NO_DEPRECATED)
  82. template<typename = void>
  83. inline std::string_view to_string_view(const asio::const_buffers_1& v) noexcept
  84. {
  85. return std::string_view{ (std::string_view::const_pointer)(v.data()), v.size() };
  86. }
  87. template<typename = void>
  88. inline std::string_view to_string_view(const asio::mutable_buffers_1& v) noexcept
  89. {
  90. return std::string_view{ (std::string_view::const_pointer)(v.data()), v.size() };
  91. }
  92. #endif
  93. }
  94. namespace asio2::detail
  95. {
  96. using asio2::to_string;
  97. using asio2::to_string_view;
  98. using asio2::to_numeric;
  99. }
  100. namespace asio2::detail
  101. {
  102. struct tcp_tag { using tl_tag_type = tcp_tag ; }; // transport layer
  103. struct udp_tag { using tl_tag_type = udp_tag ; }; // transport layer
  104. struct cast_tag { using tl_tag_type = cast_tag; };
  105. struct ssl_stream_tag {};
  106. struct ws_stream_tag {};
  107. }
  108. namespace asio2
  109. {
  110. template<typename Protocol, typename String, typename StrOrInt>
  111. inline Protocol to_endpoint(String&& host, StrOrInt&& port)
  112. {
  113. std::string h = detail::to_string(std::forward<String>(host));
  114. std::string p = detail::to_string(std::forward<StrOrInt>(port));
  115. asio::io_context ioc;
  116. // the resolve function is a time-consuming operation
  117. if /**/ constexpr (std::is_same_v<asio::ip::udp::endpoint, Protocol>)
  118. {
  119. error_code ec;
  120. asio::ip::udp::resolver resolver(ioc);
  121. auto rs = resolver.resolve(h, p, asio::ip::resolver_base::flags::address_configured, ec);
  122. if (ec || rs.empty())
  123. {
  124. set_last_error(ec ? ec : asio::error::host_not_found);
  125. return *rs;
  126. }
  127. else
  128. {
  129. clear_last_error();
  130. return asio::ip::udp::endpoint{};
  131. }
  132. }
  133. else if constexpr (std::is_same_v<asio::ip::tcp::endpoint, Protocol>)
  134. {
  135. error_code ec;
  136. asio::ip::tcp::resolver resolver(ioc);
  137. auto rs = resolver.resolve(h, p, asio::ip::resolver_base::flags::address_configured, ec);
  138. if (ec || rs.empty())
  139. {
  140. set_last_error(ec ? ec : asio::error::host_not_found);
  141. return *rs;
  142. }
  143. else
  144. {
  145. clear_last_error();
  146. return asio::ip::tcp::endpoint{};
  147. }
  148. }
  149. else
  150. {
  151. static_assert(detail::always_false_v<Protocol>);
  152. }
  153. }
  154. }
  155. namespace asio2::detail
  156. {
  157. using asio2::to_endpoint;
  158. }
  159. namespace asio2::detail
  160. {
  161. enum class state_t : std::int8_t { stopped, stopping, starting, started };
  162. template<typename = void>
  163. inline constexpr std::string_view to_string(state_t v)
  164. {
  165. using namespace std::string_view_literals;
  166. switch (v)
  167. {
  168. case state_t::stopped : return "stopped";
  169. case state_t::stopping : return "stopping";
  170. case state_t::starting : return "starting";
  171. case state_t::started : return "started";
  172. default : return "none";
  173. }
  174. return "none";
  175. }
  176. // /bho/beast/websocket/stream_base.hpp line 147
  177. // opt.handshake_timeout = std::chrono::seconds(30);
  178. // When there are a lot of connections, there will maybe a lot of COSE_WAIT,LAST_ACK,TIME_WAIT
  179. // and other problems, resulting in the client being unable to connect to the server normally.
  180. // Increasing the connect,handshake,shutdown timeout can effectively alleviate this problem.
  181. static long constexpr tcp_handshake_timeout = 30 * 1000;
  182. static long constexpr udp_handshake_timeout = 30 * 1000;
  183. static long constexpr http_handshake_timeout = 30 * 1000;
  184. static long constexpr tcp_connect_timeout = 30 * 1000;
  185. static long constexpr udp_connect_timeout = 30 * 1000;
  186. static long constexpr http_connect_timeout = 30 * 1000;
  187. static long constexpr tcp_silence_timeout = 60 * 60 * 1000;
  188. static long constexpr udp_silence_timeout = 60 * 1000;
  189. static long constexpr http_silence_timeout = 85 * 1000;
  190. static long constexpr mqtt_silence_timeout = 90 * 1000; // 60 * 1.5
  191. static long constexpr http_execute_timeout = 15 * 1000;
  192. static long constexpr icmp_execute_timeout = 4 * 1000;
  193. static long constexpr ssl_shutdown_timeout = 30 * 1000;
  194. static long constexpr ws_shutdown_timeout = 30 * 1000;
  195. static long constexpr ssl_handshake_timeout = 30 * 1000;
  196. static long constexpr ws_handshake_timeout = 30 * 1000;
  197. /*
  198. * The read buffer has to be at least as large
  199. * as the largest possible control frame including
  200. * the frame header.
  201. * refrenced from beast stream.hpp
  202. */
  203. // udp MTU : https://zhuanlan.zhihu.com/p/301276548
  204. static std::size_t constexpr tcp_frame_size = 1536;
  205. static std::size_t constexpr udp_frame_size = 1024;
  206. static std::size_t constexpr http_frame_size = 1536;
  207. static std::size_t constexpr max_buffer_size = (std::numeric_limits<std::size_t>::max)();
  208. // std::thread::hardware_concurrency() is not constexpr, so use it with function form
  209. // @see: asio::detail::default_thread_pool_size()
  210. template<typename = void>
  211. inline std::size_t default_concurrency() noexcept
  212. {
  213. std::size_t num_threads = std::thread::hardware_concurrency() * 2;
  214. num_threads = num_threads == 0 ? 2 : num_threads;
  215. return num_threads;
  216. }
  217. }
  218. namespace asio2::detail
  219. {
  220. /**
  221. * BKDR Hash Function
  222. */
  223. template<typename = void>
  224. inline std::size_t bkdr_hash(const unsigned char * const p, std::size_t size) noexcept
  225. {
  226. std::size_t v = 0;
  227. for (std::size_t i = 0; i < size; ++i)
  228. {
  229. v = v * 131 + static_cast<std::size_t>(p[i]);
  230. }
  231. return v;
  232. }
  233. /**
  234. * Fnv1a Hash Function
  235. * Reference from Visual c++ implementation, see vc++ std::hash
  236. */
  237. template<typename T>
  238. inline T fnv1a_hash(const unsigned char * const p, const T size) noexcept
  239. {
  240. static_assert(sizeof(T) == 4 || sizeof(T) == 8, "Must be 32 or 64 digits");
  241. T v;
  242. if constexpr (sizeof(T) == 4)
  243. v = 2166136261u;
  244. else
  245. v = 14695981039346656037ull;
  246. for (T i = 0; i < size; ++i)
  247. {
  248. v ^= static_cast<T>(p[i]);
  249. if constexpr (sizeof(T) == 4)
  250. v *= 16777619u;
  251. else
  252. v *= 1099511628211ull;
  253. }
  254. return (v);
  255. }
  256. template<typename T>
  257. inline T fnv1a_hash(T v, const unsigned char * const p, const T size) noexcept
  258. {
  259. static_assert(sizeof(T) == 4 || sizeof(T) == 8, "Must be 32 or 64 digits");
  260. for (T i = 0; i < size; ++i)
  261. {
  262. v ^= static_cast<T>(p[i]);
  263. if constexpr (sizeof(T) == 4)
  264. v *= 16777619u;
  265. else
  266. v *= 1099511628211ull;
  267. }
  268. return (v);
  269. }
  270. template<class T>
  271. class copyable_wrapper
  272. {
  273. public:
  274. using value_type = T;
  275. template<typename ...Args>
  276. copyable_wrapper(Args&&... args) noexcept : raw(std::forward<Args>(args)...) { }
  277. template<typename = void>
  278. copyable_wrapper(T&& o) noexcept : raw(std::move(o)) { }
  279. copyable_wrapper(copyable_wrapper&&) noexcept = default;
  280. copyable_wrapper& operator=(copyable_wrapper&&) noexcept = default;
  281. copyable_wrapper(copyable_wrapper const& r) noexcept : raw(const_cast<T&&>(r.raw)) { }
  282. copyable_wrapper& operator=(copyable_wrapper const& r) noexcept { raw = const_cast<T&&>(r.raw); }
  283. T& operator()() noexcept { return raw; }
  284. protected:
  285. T raw;
  286. };
  287. template<typename, typename = void>
  288. struct is_copyable_wrapper : std::false_type {};
  289. template<typename T>
  290. struct is_copyable_wrapper<T, std::void_t<typename T::value_type,
  291. typename std::enable_if_t<std::is_same_v<T,
  292. copyable_wrapper<typename T::value_type>>>>> : std::true_type {};
  293. template<class T>
  294. inline constexpr bool is_copyable_wrapper_v = is_copyable_wrapper<T>::value;
  295. inline void cancel_timer(asio::steady_timer& timer) noexcept
  296. {
  297. try
  298. {
  299. timer.cancel();
  300. }
  301. catch (system_error const&)
  302. {
  303. }
  304. }
  305. struct safe_timer
  306. {
  307. explicit safe_timer(asio::io_context& ioc) : timer(ioc)
  308. {
  309. canceled.clear();
  310. }
  311. inline void cancel()
  312. {
  313. this->canceled.test_and_set();
  314. detail::cancel_timer(this->timer);
  315. }
  316. /// Timer impl
  317. asio::steady_timer timer;
  318. /// Why use this flag, beacuase the ec param maybe zero when the timer callback is
  319. /// called after the timer cancel function has called already.
  320. /// Before : need reset the "canceled" flag to false, otherwise after "client.stop();"
  321. /// then call client.start(...) again, this reconnect timer will doesn't work .
  322. /// can't put this "clear" code into the timer handle function, beacuse the stop timer
  323. /// maybe called many times. so, when the "canceled" flag is set false in the timer handle
  324. /// and the stop timer is called later, then the "canceled" flag will be set true again .
  325. std::atomic_flag canceled;
  326. };
  327. template<class Rep, class Period, class Fn>
  328. std::shared_ptr<safe_timer> mktimer(asio::io_context& ioc, std::chrono::duration<Rep, Period> duration, Fn&& fn)
  329. {
  330. std::shared_ptr<safe_timer> timer = std::make_shared<safe_timer>(ioc);
  331. auto post = std::make_shared<std::unique_ptr<std::function<void()>>>();
  332. *post = std::make_unique<std::function<void()>>(
  333. [duration, f = std::forward<Fn>(fn), timer, post]() mutable
  334. {
  335. timer->timer.expires_after(duration);
  336. timer->timer.async_wait([&f, &timer, &post](const error_code& ec) mutable
  337. {
  338. if (!timer->canceled.test_and_set())
  339. {
  340. timer->canceled.clear();
  341. if (f(ec))
  342. (**post)();
  343. else
  344. (*post).reset();
  345. }
  346. else
  347. {
  348. (*post).reset();
  349. }
  350. });
  351. });
  352. (**post)();
  353. return timer;
  354. }
  355. template<class T, bool isIntegral = true, bool isUnsigned = true, bool SkipZero = true>
  356. class id_maker
  357. {
  358. public:
  359. id_maker(T init = static_cast<T>(1)) noexcept : id(init)
  360. {
  361. if constexpr (isIntegral)
  362. {
  363. static_assert(std::is_integral_v<T>, "T must be integral");
  364. if constexpr (isUnsigned)
  365. {
  366. static_assert(std::is_unsigned_v<T>, "T must be unsigned integral");
  367. }
  368. else
  369. {
  370. static_assert(true);
  371. }
  372. }
  373. else
  374. {
  375. static_assert(true);
  376. }
  377. }
  378. inline T mkid() noexcept
  379. {
  380. if constexpr (SkipZero)
  381. {
  382. T r = id.fetch_add(static_cast<T>(1));
  383. return (r == 0 ? id.fetch_add(static_cast<T>(1)) : r);
  384. }
  385. else
  386. {
  387. return id.fetch_add(static_cast<T>(1));
  388. }
  389. }
  390. protected:
  391. std::atomic<T> id;
  392. };
  393. // Returns true if the current machine is little endian
  394. template<typename = void>
  395. inline bool is_little_endian() noexcept
  396. {
  397. static std::int32_t test = 1;
  398. return (*reinterpret_cast<std::int8_t*>(std::addressof(test)) == 1);
  399. }
  400. /**
  401. * Swaps the order of bytes for some chunk of memory
  402. * @param data - The data as a uint8_t pointer
  403. * @tparam DataSize - The true size of the data
  404. */
  405. template <std::size_t DataSize>
  406. inline void swap_bytes(std::uint8_t* data) noexcept
  407. {
  408. for (std::size_t i = 0, end = DataSize / 2; i < end; ++i)
  409. std::swap(data[i], data[DataSize - i - 1]);
  410. }
  411. /**
  412. * Swaps the order of bytes for some chunk of memory
  413. * @param v - The variable reference.
  414. */
  415. template <class T>
  416. inline void swap_bytes(T& v) noexcept
  417. {
  418. std::uint8_t* p = reinterpret_cast<std::uint8_t*>(std::addressof(v));
  419. swap_bytes<sizeof(T)>(p);
  420. }
  421. /**
  422. * converts the value from host to TCP/IP network byte order (which is big-endian).
  423. * @param v - The variable reference.
  424. */
  425. template <class T>
  426. inline T host_to_network(T v) noexcept
  427. {
  428. if (is_little_endian())
  429. {
  430. std::uint8_t* p = reinterpret_cast<std::uint8_t*>(std::addressof(v));
  431. swap_bytes<sizeof(T)>(p);
  432. }
  433. return v;
  434. }
  435. /**
  436. * converts the value from TCP/IP network order to host byte order (which is little-endian on Intel processors).
  437. * @param v - The variable reference.
  438. */
  439. template <class T>
  440. inline T network_to_host(T v) noexcept
  441. {
  442. if (is_little_endian())
  443. {
  444. std::uint8_t* p = reinterpret_cast<std::uint8_t*>(std::addressof(v));
  445. swap_bytes<sizeof(T)>(p);
  446. }
  447. return v;
  448. }
  449. template<class T, class Pointer>
  450. inline void write(Pointer& p, T v) noexcept
  451. {
  452. if constexpr (int(sizeof(T)) > 1)
  453. {
  454. // MSDN: The htons function converts a u_short from host to TCP/IP network byte order (which is big-endian).
  455. // ** This mean the network byte order is big-endian **
  456. if (is_little_endian())
  457. {
  458. swap_bytes<sizeof(T)>(reinterpret_cast<std::uint8_t *>(std::addressof(v)));
  459. }
  460. std::memcpy((void*)p, (const void*)&v, sizeof(T));
  461. }
  462. else
  463. {
  464. static_assert(sizeof(T) == std::size_t(1));
  465. *p = std::decay_t<std::remove_pointer_t<detail::remove_cvref_t<Pointer>>>(v);
  466. }
  467. p += sizeof(T);
  468. }
  469. template<class T, class Pointer>
  470. inline T read(Pointer& p) noexcept
  471. {
  472. T v{};
  473. if constexpr (int(sizeof(T)) > 1)
  474. {
  475. std::memcpy((void*)&v, (const void*)p, sizeof(T));
  476. // MSDN: The htons function converts a u_short from host to TCP/IP network byte order (which is big-endian).
  477. // ** This mean the network byte order is big-endian **
  478. if (is_little_endian())
  479. {
  480. swap_bytes<sizeof(T)>(reinterpret_cast<std::uint8_t *>(std::addressof(v)));
  481. }
  482. }
  483. else
  484. {
  485. static_assert(sizeof(T) == std::size_t(1));
  486. v = T(*p);
  487. }
  488. p += sizeof(T);
  489. return v;
  490. }
  491. // C++ SSO : How to programatically find if a std::wstring is allocated with Short String Optimization?
  492. // https://stackoverflow.com/questions/65736613/c-sso-how-to-programatically-find-if-a-stdwstring-is-allocated-with-short
  493. template <class T>
  494. bool is_used_sso(const T& t) noexcept
  495. {
  496. using type = typename detail::remove_cvref_t<T>;
  497. static type st{};
  498. return t.capacity() == st.capacity();
  499. }
  500. template<class T>
  501. std::size_t sso_buffer_size() noexcept
  502. {
  503. using type = typename detail::remove_cvref_t<T>;
  504. static type st{};
  505. return st.capacity();
  506. }
  507. // Disable std:string's SSO
  508. // https://stackoverflow.com/questions/34788789/disable-stdstrings-sso
  509. // std::string str;
  510. // str.reserve(sizeof(str) + 1);
  511. template<class String>
  512. inline void disable_sso(String& str)
  513. {
  514. str.reserve(sso_buffer_size<typename detail::remove_cvref_t<String>>() + 1);
  515. }
  516. template<class Integer>
  517. struct integer_add_sub_guard
  518. {
  519. integer_add_sub_guard(Integer& v) noexcept : v_(v) { ++v_; }
  520. ~integer_add_sub_guard() noexcept { --v_; }
  521. Integer& v_;
  522. };
  523. // C++17 class template argument deduction guides
  524. template<class Integer>
  525. integer_add_sub_guard(Integer&)->integer_add_sub_guard<Integer>;
  526. template<typename = void>
  527. bool is_subpath_of(const std::filesystem::path& base, const std::filesystem::path& p) noexcept
  528. {
  529. assert(std::filesystem::is_directory(base));
  530. auto it_base = base.begin();
  531. auto it_p = p.begin();
  532. while (it_base != base.end() && it_p != p.end())
  533. {
  534. if (*it_base != *it_p)
  535. {
  536. return false;
  537. }
  538. ++it_base;
  539. ++it_p;
  540. }
  541. // If all components of base are matched, and p has more components, then base is a subpath of p
  542. return it_base == base.end() && it_p != p.end();
  543. }
  544. template<typename = void>
  545. std::filesystem::path make_filepath(const std::filesystem::path& base, const std::filesystem::path& p) noexcept
  546. {
  547. std::error_code ec{};
  548. std::filesystem::path b = std::filesystem::canonical(base, ec);
  549. if (ec)
  550. {
  551. return {};
  552. }
  553. assert(std::filesystem::is_directory(b));
  554. std::filesystem::path filepath = b;
  555. filepath += p;
  556. filepath = std::filesystem::canonical(filepath, ec);
  557. if (ec || !is_subpath_of(b, filepath))
  558. {
  559. return {};
  560. }
  561. return filepath;
  562. }
  563. }
  564. namespace asio2
  565. {
  566. enum class net_protocol : std::uint8_t
  567. {
  568. none = 0,
  569. udp = 1,
  570. tcp,
  571. http,
  572. websocket,
  573. rpc,
  574. mqtt,
  575. tcps,
  576. https,
  577. websockets,
  578. rpcs,
  579. mqtts,
  580. icmp,
  581. serialport,
  582. ws = websocket,
  583. wss = websockets
  584. };
  585. enum class response_mode : std::uint8_t
  586. {
  587. automatic = 1,
  588. manual,
  589. };
  590. }
  591. // custom specialization of std::hash can be injected in namespace std
  592. // see : struct hash<asio::ip::basic_endpoint<InternetProtocol>> in /asio/ip/basic_endpoint.hpp
  593. #if !defined(ASIO_HAS_STD_HASH)
  594. namespace std
  595. {
  596. template <>
  597. struct hash<asio::ip::address_v4>
  598. {
  599. std::size_t operator()(const asio::ip::address_v4& addr) const ASIO_NOEXCEPT
  600. {
  601. return std::hash<unsigned int>()(addr.to_uint());
  602. }
  603. };
  604. template <>
  605. struct hash<asio::ip::address_v6>
  606. {
  607. std::size_t operator()(const asio::ip::address_v6& addr) const ASIO_NOEXCEPT
  608. {
  609. const asio::ip::address_v6::bytes_type bytes = addr.to_bytes();
  610. std::size_t result = static_cast<std::size_t>(addr.scope_id());
  611. combine_4_bytes(result, &bytes[0]);
  612. combine_4_bytes(result, &bytes[4]);
  613. combine_4_bytes(result, &bytes[8]);
  614. combine_4_bytes(result, &bytes[12]);
  615. return result;
  616. }
  617. private:
  618. static void combine_4_bytes(std::size_t& seed, const unsigned char* bytes)
  619. {
  620. const std::size_t bytes_hash =
  621. (static_cast<std::size_t>(bytes[0]) << 24) |
  622. (static_cast<std::size_t>(bytes[1]) << 16) |
  623. (static_cast<std::size_t>(bytes[2]) << 8) |
  624. (static_cast<std::size_t>(bytes[3]));
  625. seed ^= bytes_hash + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  626. }
  627. };
  628. template <>
  629. struct hash<asio::ip::address>
  630. {
  631. std::size_t operator()(const asio::ip::address& addr) const ASIO_NOEXCEPT
  632. {
  633. return addr.is_v4()
  634. ? std::hash<asio::ip::address_v4>()(addr.to_v4())
  635. : std::hash<asio::ip::address_v6>()(addr.to_v6());
  636. }
  637. };
  638. template <typename InternetProtocol>
  639. struct hash<asio::ip::basic_endpoint<InternetProtocol>>
  640. {
  641. std::size_t operator()(const asio::ip::basic_endpoint<InternetProtocol>& ep) const ASIO_NOEXCEPT
  642. {
  643. std::size_t hash1 = std::hash<asio::ip::address>()(ep.address());
  644. std::size_t hash2 = std::hash<unsigned short>()(ep.port());
  645. return hash1 ^ (hash2 + 0x9e3779b9 + (hash1 << 6) + (hash1 >> 2));
  646. }
  647. };
  648. }
  649. #endif
  650. namespace asio2
  651. {
  652. namespace detail
  653. {
  654. template<class T>
  655. struct current_object_result_t
  656. {
  657. using type = T&;
  658. };
  659. template<class T>
  660. struct current_object_result_t<std::shared_ptr<T>>
  661. {
  662. using type = std::weak_ptr<T>&;
  663. };
  664. class [[maybe_unused]] external_linkaged_current_object
  665. {
  666. public:
  667. template<class T>
  668. [[maybe_unused]] static typename current_object_result_t<T>::type get() noexcept
  669. {
  670. if constexpr (detail::is_template_instance_of_v<std::shared_ptr, T>)
  671. {
  672. thread_local static std::weak_ptr<typename T::element_type> o{};
  673. return o;
  674. }
  675. else
  676. {
  677. thread_local static T o{};
  678. return o;
  679. }
  680. }
  681. };
  682. namespace internal_linkaged_current_object
  683. {
  684. template<class T>
  685. [[maybe_unused]] static typename current_object_result_t<T>::type get() noexcept
  686. {
  687. if constexpr (detail::is_template_instance_of_v<std::shared_ptr, T>)
  688. {
  689. thread_local static std::weak_ptr<typename T::element_type> o{};
  690. return o;
  691. }
  692. else
  693. {
  694. thread_local static T o{};
  695. return o;
  696. }
  697. }
  698. }
  699. template<class T>
  700. [[maybe_unused]] inline typename current_object_result_t<T>::type get_current_object() noexcept
  701. {
  702. return detail::external_linkaged_current_object::get<T>();
  703. }
  704. }
  705. /**
  706. * @brief Get the current caller object in the current thread.
  707. * @tparam T - If the object is created on the stack such as "asio2::rpc_client client", the T can
  708. * only be asio2::rpc_client& or asio2::rpc_client*
  709. * If the object is created on the heap such as "std::shared_ptr<asio2::rpc_session>",
  710. * the T can only be std::shared_ptr<asio2::rpc_session>
  711. * @return The return type is same as the T.
  712. */
  713. template<class T>
  714. [[maybe_unused]] inline T get_current_caller() noexcept
  715. {
  716. if /**/ constexpr (detail::is_template_instance_of_v<std::shared_ptr, T>)
  717. {
  718. return detail::get_current_object<T>().lock();
  719. }
  720. else if constexpr (std::is_reference_v<T>)
  721. {
  722. return *detail::get_current_object<std::add_pointer_t<typename detail::remove_cvref_t<T>>>();
  723. }
  724. else
  725. {
  726. return detail::get_current_object<T>();
  727. }
  728. }
  729. }
  730. namespace asio2::detail
  731. {
  732. struct wait_timer_op : public asio::coroutine
  733. {
  734. asio::steady_timer& timer_;
  735. wait_timer_op(asio::steady_timer& timer) : timer_(timer)
  736. {
  737. }
  738. template <typename Self>
  739. void operator()(Self& self, error_code ec = {})
  740. {
  741. detail::ignore_unused(ec);
  742. ASIO_CORO_REENTER(*this)
  743. {
  744. ASIO_CORO_YIELD
  745. timer_.async_wait(std::move(self));
  746. self.complete(get_last_error());
  747. }
  748. }
  749. };
  750. class data_filter_before_helper
  751. {
  752. public:
  753. template<class, class = void>
  754. struct has_member_data_filter_before_recv : std::false_type {};
  755. template<class T>
  756. struct has_member_data_filter_before_recv<T, std::void_t<decltype(
  757. std::declval<std::decay_t<T>&>().data_filter_before_recv(std::string_view{}))>> : std::true_type {};
  758. template<class, class = void>
  759. struct has_member_data_filter_before_send : std::false_type {};
  760. template<class T>
  761. struct has_member_data_filter_before_send<T, std::void_t<decltype(
  762. std::declval<std::decay_t<T>&>().data_filter_before_send(std::string_view{}))>> : std::true_type {};
  763. template<class derived_t>
  764. inline static std::string_view call_data_filter_before_recv(derived_t& derive, std::string_view data) noexcept
  765. {
  766. if constexpr (has_member_data_filter_before_recv<derived_t>::value)
  767. return derive.data_filter_before_recv(data);
  768. else
  769. return data;
  770. }
  771. template<class derived_t, class T>
  772. inline static auto call_data_filter_before_send(derived_t& derive, T&& data) noexcept
  773. {
  774. if constexpr (has_member_data_filter_before_send<derived_t>::value)
  775. return derive.data_filter_before_send(std::forward<T>(data));
  776. else
  777. return std::forward<T>(data);
  778. }
  779. };
  780. template<class derived_t>
  781. inline std::string_view call_data_filter_before_recv(derived_t& derive, std::string_view data) noexcept
  782. {
  783. return data_filter_before_helper::call_data_filter_before_recv(derive, data);
  784. }
  785. template<class derived_t, class T>
  786. inline auto call_data_filter_before_send(derived_t& derive, T&& data) noexcept
  787. {
  788. return data_filter_before_helper::call_data_filter_before_send(derive, std::forward<T>(data));
  789. }
  790. template<class, class = void>
  791. struct has_member_insert : std::false_type {};
  792. template<class T>
  793. struct has_member_insert<T, std::void_t<decltype(
  794. std::declval<std::decay_t<T>&>().insert(std::declval<std::decay_t<T>&>().begin(),
  795. std::string_view{}.begin(), std::string_view{}.end()))>> : std::true_type {};
  796. }
  797. namespace asio2
  798. {
  799. // helper type for the visitor #4
  800. template<class... Ts>
  801. struct variant_overloaded : Ts... { using Ts::operator()...; };
  802. // explicit deduction guide (not needed as of C++20)
  803. template<class... Ts>
  804. variant_overloaded(Ts...) -> variant_overloaded<Ts...>;
  805. }
  806. #endif // !__ASIO2_UTIL_HPP__