error.hpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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_ERROR_HPP__
  11. #define __ASIO2_ERROR_HPP__
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. #pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. //#if !defined(NDEBUG) && !defined(_DEBUG) && !defined(DEBUG)
  16. //#define NDEBUG
  17. //#endif
  18. #include <asio2/base/detail/push_options.hpp>
  19. #include <cerrno>
  20. #include <cassert>
  21. #include <string>
  22. #include <system_error>
  23. #include <ios>
  24. #include <future>
  25. #include <asio2/external/asio.hpp>
  26. #include <asio2/external/assert.hpp>
  27. namespace asio2
  28. {
  29. // Very important features:
  30. // One Definition Rule : https://en.wikipedia.org/wiki/One_Definition_Rule
  31. // ---- internal linkage ----
  32. // static global variable : static int x;
  33. // static global function, namespace scope or not : static bool test(){...}
  34. // enum definition : enum Boolean { NO,YES };
  35. // class definition : class Point { int d_x; int d_y; ... };
  36. // inline function definition : inline int operator==(const Point& left,const Point&right) { ... }
  37. // union definition
  38. // const variable definition
  39. //
  40. // ---- external linkage ----
  41. // not inlined class member function : Point& Point::operator+=(const Point& right) { ... }
  42. // not inlined not static function : Point operator+(const Point& left, const Point& right) { ... }
  43. // global variable : int x;
  44. // singleton class member function : class st{ static st& get(){static st& s; return s;} }
  45. namespace detail
  46. {
  47. class [[maybe_unused]] external_linkaged_last_error
  48. {
  49. public:
  50. [[maybe_unused]] static error_code & get() noexcept
  51. {
  52. // thread local variable of error_code
  53. thread_local static error_code ec_last{};
  54. return ec_last;
  55. }
  56. };
  57. namespace internal_linkaged_last_error
  58. {
  59. [[maybe_unused]] static error_code & get() noexcept
  60. {
  61. // thread local variable of error_code
  62. thread_local static error_code ec_last{};
  63. return ec_last;
  64. }
  65. }
  66. }
  67. // use anonymous namespace to resolve global function redefinition problem
  68. namespace
  69. {
  70. /**
  71. * thread local variable of error_code
  72. * In vs2017, sometimes the "namespace's thread_local error_code" will cause crash at
  73. * system_category() -> (_Immortalize<_System_error_category>())-> _Execute_once(...),
  74. * and the crash happens before the "main" function.
  75. */
  76. //thread_local static error_code ec_last;
  77. /**
  78. * @brief get last error_code
  79. */
  80. inline error_code & get_last_error() noexcept
  81. {
  82. return detail::external_linkaged_last_error::get();
  83. }
  84. /**
  85. * @brief set last error_code
  86. */
  87. template<class ErrorCodeEnum>
  88. inline void set_last_error(ErrorCodeEnum e) noexcept
  89. {
  90. using type = std::remove_cv_t<std::remove_reference_t<ErrorCodeEnum>>;
  91. if /**/ constexpr (
  92. std::is_same_v<type, asio::error::basic_errors > ||
  93. std::is_same_v<type, asio::error::netdb_errors > ||
  94. std::is_same_v<type, asio::error::addrinfo_errors> ||
  95. std::is_same_v<type, asio::error::misc_errors > )
  96. {
  97. get_last_error() = asio::error::make_error_code(e);
  98. }
  99. else if constexpr (
  100. std::is_same_v<type, std::errc > ||
  101. std::is_same_v<type, std::io_errc > ||
  102. std::is_same_v<type, std::future_errc> )
  103. {
  104. #ifdef ASIO_STANDALONE
  105. get_last_error() = std::make_error_code(e);
  106. #else
  107. get_last_error().assign(static_cast<int>(e), asio::error::get_system_category());
  108. #endif
  109. }
  110. else if constexpr (std::is_integral_v<type>)
  111. {
  112. get_last_error().assign(static_cast<int>(e), asio::error::get_system_category());
  113. }
  114. else if constexpr (std::is_enum_v<type>)
  115. {
  116. get_last_error() = e;
  117. }
  118. else
  119. {
  120. ASIO2_ASSERT(false);
  121. get_last_error().assign(static_cast<int>(e), asio::error::get_system_category());
  122. }
  123. }
  124. /**
  125. * @brief set last error_code
  126. */
  127. template<typename T>
  128. inline void set_last_error(int ec, const T& ecat) noexcept
  129. {
  130. get_last_error().assign(ec, ecat);
  131. }
  132. /**
  133. * @brief set last error_code
  134. */
  135. inline void set_last_error(const error_code & ec) noexcept
  136. {
  137. get_last_error() = ec;
  138. }
  139. /**
  140. * @brief set last error_code
  141. */
  142. inline void set_last_error(const system_error & e) noexcept
  143. {
  144. get_last_error() = e.code();
  145. }
  146. /**
  147. * @brief Replaces the error code and error category with default values.
  148. */
  149. inline void clear_last_error() noexcept
  150. {
  151. get_last_error().clear();
  152. }
  153. /**
  154. * @brief get last error value, same as get_last_error_val
  155. */
  156. inline auto last_error_val() noexcept
  157. {
  158. return get_last_error().value();
  159. }
  160. /**
  161. * @brief get last error value
  162. */
  163. inline auto get_last_error_val() noexcept
  164. {
  165. return get_last_error().value();
  166. }
  167. /**
  168. * @brief get last error message, same as get_last_error_msg
  169. */
  170. inline auto last_error_msg()
  171. {
  172. return get_last_error().message();
  173. }
  174. /**
  175. * @brief get last error message
  176. */
  177. inline auto get_last_error_msg()
  178. {
  179. return get_last_error().message();
  180. }
  181. }
  182. }
  183. #include <asio2/base/detail/pop_options.hpp>
  184. #endif // !__ASIO2_ERROR_HPP__