charconv_test_helpers.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. //===----------------------------------------------------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #ifndef SUPPORT_CHARCONV_TEST_HELPERS_H
  9. #define SUPPORT_CHARCONV_TEST_HELPERS_H
  10. #include <charconv>
  11. #include <cassert>
  12. #include <limits>
  13. #include <string.h>
  14. #include <stdlib.h>
  15. #include "test_macros.h"
  16. #if TEST_STD_VER < 11
  17. #error This file requires C++11
  18. #endif
  19. using std::false_type;
  20. using std::true_type;
  21. template <typename To, typename From>
  22. constexpr auto
  23. is_non_narrowing(From a) -> decltype(To{a}, true_type())
  24. {
  25. return {};
  26. }
  27. template <typename To>
  28. constexpr auto
  29. is_non_narrowing(...) -> false_type
  30. {
  31. return {};
  32. }
  33. template <typename X, typename T>
  34. constexpr bool
  35. _fits_in(T, true_type /* non-narrowing*/, ...)
  36. {
  37. return true;
  38. }
  39. template <typename X, typename T, typename xl = std::numeric_limits<X>>
  40. constexpr bool
  41. _fits_in(T v, false_type, true_type /* T signed*/, true_type /* X signed */)
  42. {
  43. return xl::lowest() <= v && v <= (xl::max)();
  44. }
  45. template <typename X, typename T, typename xl = std::numeric_limits<X>>
  46. constexpr bool
  47. _fits_in(T v, false_type, true_type /* T signed */, false_type /* X unsigned*/)
  48. {
  49. return 0 <= v && typename std::make_unsigned<T>::type(v) <= (xl::max)();
  50. }
  51. template <typename X, typename T, typename xl = std::numeric_limits<X>>
  52. constexpr bool
  53. _fits_in(T v, false_type, false_type /* T unsigned */, ...)
  54. {
  55. return v <= typename std::make_unsigned<X>::type((xl::max)());
  56. }
  57. template <typename X, typename T>
  58. constexpr bool
  59. fits_in(T v)
  60. {
  61. return _fits_in<X>(v, is_non_narrowing<X>(v), std::is_signed<T>(),
  62. std::is_signed<X>());
  63. }
  64. template <typename X>
  65. struct to_chars_test_base
  66. {
  67. template <typename T, size_t N, typename... Ts>
  68. void test(T v, char const (&expect)[N], Ts... args)
  69. {
  70. using std::to_chars;
  71. std::to_chars_result r;
  72. constexpr size_t len = N - 1;
  73. static_assert(len > 0, "expected output won't be empty");
  74. if (!fits_in<X>(v))
  75. return;
  76. r = to_chars(buf, buf + len - 1, X(v), args...);
  77. assert(r.ptr == buf + len - 1);
  78. assert(r.ec == std::errc::value_too_large);
  79. r = to_chars(buf, buf + sizeof(buf), X(v), args...);
  80. assert(r.ptr == buf + len);
  81. assert(r.ec == std::errc{});
  82. assert(memcmp(buf, expect, len) == 0);
  83. }
  84. template <typename... Ts>
  85. void test_value(X v, Ts... args)
  86. {
  87. using std::to_chars;
  88. std::to_chars_result r;
  89. r = to_chars(buf, buf + sizeof(buf), v, args...);
  90. assert(r.ec == std::errc{});
  91. *r.ptr = '\0';
  92. auto a = fromchars(buf, r.ptr, args...);
  93. assert(v == a);
  94. auto ep = r.ptr - 1;
  95. r = to_chars(buf, ep, v, args...);
  96. assert(r.ptr == ep);
  97. assert(r.ec == std::errc::value_too_large);
  98. }
  99. private:
  100. static long long fromchars(char const* p, char const* ep, int base, true_type)
  101. {
  102. char* last;
  103. auto r = strtoll(p, &last, base);
  104. assert(last == ep);
  105. return r;
  106. }
  107. static unsigned long long fromchars(char const* p, char const* ep, int base, false_type)
  108. {
  109. char* last;
  110. auto r = strtoull(p, &last, base);
  111. assert(last == ep);
  112. return r;
  113. }
  114. static auto fromchars(char const* p, char const* ep, int base = 10)
  115. -> decltype(fromchars(p, ep, base, std::is_signed<X>()))
  116. {
  117. return fromchars(p, ep, base, std::is_signed<X>());
  118. }
  119. char buf[100];
  120. };
  121. template <typename X>
  122. struct roundtrip_test_base
  123. {
  124. template <typename T, typename... Ts>
  125. void test(T v, Ts... args)
  126. {
  127. using std::from_chars;
  128. using std::to_chars;
  129. std::from_chars_result r2;
  130. std::to_chars_result r;
  131. X x = 0xc;
  132. if (fits_in<X>(v))
  133. {
  134. r = to_chars(buf, buf + sizeof(buf), v, args...);
  135. assert(r.ec == std::errc{});
  136. r2 = from_chars(buf, r.ptr, x, args...);
  137. assert(r2.ptr == r.ptr);
  138. assert(x == X(v));
  139. }
  140. else
  141. {
  142. r = to_chars(buf, buf + sizeof(buf), v, args...);
  143. assert(r.ec == std::errc{});
  144. r2 = from_chars(buf, r.ptr, x, args...);
  145. if (std::is_signed<T>::value && v < 0 && std::is_unsigned<X>::value)
  146. {
  147. assert(x == 0xc);
  148. assert(r2.ptr == buf);
  149. assert(r2.ec == std::errc::invalid_argument);
  150. }
  151. else
  152. {
  153. assert(x == 0xc);
  154. assert(r2.ptr == r.ptr);
  155. assert(r2.ec == std::errc::result_out_of_range);
  156. }
  157. }
  158. }
  159. private:
  160. char buf[100];
  161. };
  162. template <typename... T>
  163. struct type_list
  164. {
  165. };
  166. template <typename L1, typename L2>
  167. struct type_concat;
  168. template <typename... Xs, typename... Ys>
  169. struct type_concat<type_list<Xs...>, type_list<Ys...>>
  170. {
  171. using type = type_list<Xs..., Ys...>;
  172. };
  173. template <typename L1, typename L2>
  174. using concat_t = typename type_concat<L1, L2>::type;
  175. template <typename L1, typename L2>
  176. constexpr auto concat(L1, L2) -> concat_t<L1, L2>
  177. {
  178. return {};
  179. }
  180. auto all_signed = type_list<char, signed char, short, int, long, long long>();
  181. auto all_unsigned = type_list<unsigned char, unsigned short, unsigned int,
  182. unsigned long, unsigned long long>();
  183. auto integrals = concat(all_signed, all_unsigned);
  184. template <template <typename> class Fn, typename... Ts>
  185. void
  186. run(type_list<Ts...>)
  187. {
  188. int ls[sizeof...(Ts)] = {(Fn<Ts>{}(), 0)...};
  189. (void)ls;
  190. }
  191. #endif // SUPPORT_CHARCONV_TEST_HELPERS_H