诸暨麻将添加redis
您不能選擇超過 %s 個話題 話題必須以字母或數字為開頭,可包含連接號 ('-') 且最長為 35 個字
 
 
 
 
 
 

294 行
9.1 KiB

  1. /*
  2. * For conversion between std::chrono::durations without undefined
  3. * behaviour or erroneous results.
  4. * This is a stripped down version of duration_cast, for inclusion in fmt.
  5. * See https://github.com/pauldreik/safe_duration_cast
  6. *
  7. * Copyright Paul Dreik 2019
  8. *
  9. * This file is licensed under the fmt license, see format.h
  10. */
  11. #include <chrono>
  12. #include <cmath>
  13. #include <limits>
  14. #include <type_traits>
  15. #include "format.h"
  16. FMT_BEGIN_NAMESPACE
  17. namespace safe_duration_cast {
  18. template <typename To, typename From,
  19. FMT_ENABLE_IF(!std::is_same<From, To>::value &&
  20. std::numeric_limits<From>::is_signed ==
  21. std::numeric_limits<To>::is_signed)>
  22. FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
  23. ec = 0;
  24. using F = std::numeric_limits<From>;
  25. using T = std::numeric_limits<To>;
  26. static_assert(F::is_integer, "From must be integral");
  27. static_assert(T::is_integer, "To must be integral");
  28. // A and B are both signed, or both unsigned.
  29. if (F::digits <= T::digits) {
  30. // From fits in To without any problem.
  31. } else {
  32. // From does not always fit in To, resort to a dynamic check.
  33. if (from < T::min() || from > T::max()) {
  34. // outside range.
  35. ec = 1;
  36. return {};
  37. }
  38. }
  39. return static_cast<To>(from);
  40. }
  41. /**
  42. * converts From to To, without loss. If the dynamic value of from
  43. * can't be converted to To without loss, ec is set.
  44. */
  45. template <typename To, typename From,
  46. FMT_ENABLE_IF(!std::is_same<From, To>::value &&
  47. std::numeric_limits<From>::is_signed !=
  48. std::numeric_limits<To>::is_signed)>
  49. FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
  50. ec = 0;
  51. using F = std::numeric_limits<From>;
  52. using T = std::numeric_limits<To>;
  53. static_assert(F::is_integer, "From must be integral");
  54. static_assert(T::is_integer, "To must be integral");
  55. if (F::is_signed && !T::is_signed) {
  56. // From may be negative, not allowed!
  57. if (from < 0) {
  58. ec = 1;
  59. return {};
  60. }
  61. // From is positive. Can it always fit in To?
  62. if (F::digits <= T::digits) {
  63. // yes, From always fits in To.
  64. } else {
  65. // from may not fit in To, we have to do a dynamic check
  66. if (from > static_cast<From>(T::max())) {
  67. ec = 1;
  68. return {};
  69. }
  70. }
  71. }
  72. if (!F::is_signed && T::is_signed) {
  73. // can from be held in To?
  74. if (F::digits < T::digits) {
  75. // yes, From always fits in To.
  76. } else {
  77. // from may not fit in To, we have to do a dynamic check
  78. if (from > static_cast<From>(T::max())) {
  79. // outside range.
  80. ec = 1;
  81. return {};
  82. }
  83. }
  84. }
  85. // reaching here means all is ok for lossless conversion.
  86. return static_cast<To>(from);
  87. } // function
  88. template <typename To, typename From,
  89. FMT_ENABLE_IF(std::is_same<From, To>::value)>
  90. FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
  91. ec = 0;
  92. return from;
  93. } // function
  94. // clang-format off
  95. /**
  96. * converts From to To if possible, otherwise ec is set.
  97. *
  98. * input | output
  99. * ---------------------------------|---------------
  100. * NaN | NaN
  101. * Inf | Inf
  102. * normal, fits in output | converted (possibly lossy)
  103. * normal, does not fit in output | ec is set
  104. * subnormal | best effort
  105. * -Inf | -Inf
  106. */
  107. // clang-format on
  108. template <typename To, typename From,
  109. FMT_ENABLE_IF(!std::is_same<From, To>::value)>
  110. FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
  111. ec = 0;
  112. using T = std::numeric_limits<To>;
  113. static_assert(std::is_floating_point<From>::value, "From must be floating");
  114. static_assert(std::is_floating_point<To>::value, "To must be floating");
  115. // catch the only happy case
  116. if (std::isfinite(from)) {
  117. if (from >= T::lowest() && from <= T::max()) {
  118. return static_cast<To>(from);
  119. }
  120. // not within range.
  121. ec = 1;
  122. return {};
  123. }
  124. // nan and inf will be preserved
  125. return static_cast<To>(from);
  126. } // function
  127. template <typename To, typename From,
  128. FMT_ENABLE_IF(std::is_same<From, To>::value)>
  129. FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
  130. ec = 0;
  131. static_assert(std::is_floating_point<From>::value, "From must be floating");
  132. return from;
  133. }
  134. /**
  135. * safe duration cast between integral durations
  136. */
  137. template <typename To, typename FromRep, typename FromPeriod,
  138. FMT_ENABLE_IF(std::is_integral<FromRep>::value),
  139. FMT_ENABLE_IF(std::is_integral<typename To::rep>::value)>
  140. To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
  141. int& ec) {
  142. using From = std::chrono::duration<FromRep, FromPeriod>;
  143. ec = 0;
  144. // the basic idea is that we need to convert from count() in the from type
  145. // to count() in the To type, by multiplying it with this:
  146. using Factor = std::ratio_divide<typename From::period, typename To::period>;
  147. static_assert(Factor::num > 0, "num must be positive");
  148. static_assert(Factor::den > 0, "den must be positive");
  149. // the conversion is like this: multiply from.count() with Factor::num
  150. // /Factor::den and convert it to To::rep, all this without
  151. // overflow/underflow. let's start by finding a suitable type that can hold
  152. // both To, From and Factor::num
  153. using IntermediateRep =
  154. typename std::common_type<typename From::rep, typename To::rep,
  155. decltype(Factor::num)>::type;
  156. // safe conversion to IntermediateRep
  157. IntermediateRep count =
  158. lossless_integral_conversion<IntermediateRep>(from.count(), ec);
  159. if (ec) {
  160. return {};
  161. }
  162. // multiply with Factor::num without overflow or underflow
  163. if (Factor::num != 1) {
  164. constexpr auto max1 =
  165. std::numeric_limits<IntermediateRep>::max() / Factor::num;
  166. if (count > max1) {
  167. ec = 1;
  168. return {};
  169. }
  170. constexpr auto min1 =
  171. std::numeric_limits<IntermediateRep>::min() / Factor::num;
  172. if (count < min1) {
  173. ec = 1;
  174. return {};
  175. }
  176. count *= Factor::num;
  177. }
  178. // this can't go wrong, right? den>0 is checked earlier.
  179. if (Factor::den != 1) {
  180. count /= Factor::den;
  181. }
  182. // convert to the to type, safely
  183. using ToRep = typename To::rep;
  184. const ToRep tocount = lossless_integral_conversion<ToRep>(count, ec);
  185. if (ec) {
  186. return {};
  187. }
  188. return To{tocount};
  189. }
  190. /**
  191. * safe duration_cast between floating point durations
  192. */
  193. template <typename To, typename FromRep, typename FromPeriod,
  194. FMT_ENABLE_IF(std::is_floating_point<FromRep>::value),
  195. FMT_ENABLE_IF(std::is_floating_point<typename To::rep>::value)>
  196. To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
  197. int& ec) {
  198. using From = std::chrono::duration<FromRep, FromPeriod>;
  199. ec = 0;
  200. if (std::isnan(from.count())) {
  201. // nan in, gives nan out. easy.
  202. return To{std::numeric_limits<typename To::rep>::quiet_NaN()};
  203. }
  204. // maybe we should also check if from is denormal, and decide what to do about
  205. // it.
  206. // +-inf should be preserved.
  207. if (std::isinf(from.count())) {
  208. return To{from.count()};
  209. }
  210. // the basic idea is that we need to convert from count() in the from type
  211. // to count() in the To type, by multiplying it with this:
  212. using Factor = std::ratio_divide<typename From::period, typename To::period>;
  213. static_assert(Factor::num > 0, "num must be positive");
  214. static_assert(Factor::den > 0, "den must be positive");
  215. // the conversion is like this: multiply from.count() with Factor::num
  216. // /Factor::den and convert it to To::rep, all this without
  217. // overflow/underflow. let's start by finding a suitable type that can hold
  218. // both To, From and Factor::num
  219. using IntermediateRep =
  220. typename std::common_type<typename From::rep, typename To::rep,
  221. decltype(Factor::num)>::type;
  222. // force conversion of From::rep -> IntermediateRep to be safe,
  223. // even if it will never happen be narrowing in this context.
  224. IntermediateRep count =
  225. safe_float_conversion<IntermediateRep>(from.count(), ec);
  226. if (ec) {
  227. return {};
  228. }
  229. // multiply with Factor::num without overflow or underflow
  230. if (Factor::num != 1) {
  231. constexpr auto max1 = std::numeric_limits<IntermediateRep>::max() /
  232. static_cast<IntermediateRep>(Factor::num);
  233. if (count > max1) {
  234. ec = 1;
  235. return {};
  236. }
  237. constexpr auto min1 = std::numeric_limits<IntermediateRep>::lowest() /
  238. static_cast<IntermediateRep>(Factor::num);
  239. if (count < min1) {
  240. ec = 1;
  241. return {};
  242. }
  243. count *= static_cast<IntermediateRep>(Factor::num);
  244. }
  245. // this can't go wrong, right? den>0 is checked earlier.
  246. if (Factor::den != 1) {
  247. using common_t = typename std::common_type<IntermediateRep, intmax_t>::type;
  248. count /= static_cast<common_t>(Factor::den);
  249. }
  250. // convert to the to type, safely
  251. using ToRep = typename To::rep;
  252. const ToRep tocount = safe_float_conversion<ToRep>(count, ec);
  253. if (ec) {
  254. return {};
  255. }
  256. return To{tocount};
  257. }
  258. } // namespace safe_duration_cast
  259. FMT_END_NAMESPACE