# Changeset View

Changeset View

# Standalone View

Standalone View

# test/support/charconv_test_helpers.h

- This file was added.

1 | //===----------------------------------------------------------------------===// | ||||
---|---|---|---|---|---|

2 | // | ||||

3 | // The LLVM Compiler Infrastructure | ||||

4 | // | ||||

5 | // This file is dual licensed under the MIT and the University of Illinois Open | ||||

6 | // Source Licenses. See LICENSE.TXT for details. | ||||

7 | // | ||||

8 | //===----------------------------------------------------------------------===// | ||||

9 | | ||||

10 | #ifndef SUPPORT_CHARCONV_TEST_HELPERS_H | ||||

11 | #define SUPPORT_CHARCONV_TEST_HELPERS_H | ||||

12 | | ||||

13 | #include <charconv> | ||||

14 | #include <cassert> | ||||

15 | #include <limits> | ||||

16 | #include <string.h> | ||||

17 | #include <stdlib.h> | ||||

18 | | ||||

19 | #include "test_macros.h" | ||||

20 | | ||||

21 | using std::false_type; | ||||

22 | using std::true_type; | ||||

23 | | ||||

24 | template <typename To, typename From> | ||||

25 | constexpr auto | ||||

mclow.lists: If this is supposed to be a C++17 or later header (and I'm pretty sure it is), you should add a… | |||||

Not Done ReplyI can run it with lichray: I can run it with `--param=std=c++11`. | |||||

26 | is_non_narrowing(From a) -> decltype(To{a}, true_type()) | ||||

27 | { | ||||

28 | return {}; | ||||

29 | } | ||||

30 | | ||||

31 | template <typename To> | ||||

32 | constexpr auto | ||||

33 | is_non_narrowing(...) -> false_type | ||||

34 | { | ||||

35 | return {}; | ||||

36 | } | ||||

37 | | ||||

38 | template <typename X, typename T> | ||||

39 | constexpr bool | ||||

40 | _fits_in(T, true_type /* non-narrowing*/, ...) | ||||

41 | { | ||||

Not Done ReplyWe don't need to use ugly names here in the test suite. mclow.lists: We don't need to use ugly names here in the test suite.
| |||||

Not Done ReplyErr, it's not? Just an impl version of lichray: Err, it's not? Just an impl version of `fits_in` (without the _ prefix). | |||||

42 | return true; | ||||

43 | } | ||||

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*/, true_type /* X signed */) | ||||

48 | { | ||||

49 | return xl::lowest() <= v && v <= (xl::max)(); | ||||

50 | } | ||||

51 | | ||||

52 | template <typename X, typename T, typename xl = std::numeric_limits<X>> | ||||

53 | constexpr bool | ||||

54 | _fits_in(T v, false_type, true_type /* T signed */, false_type /* X unsigned*/) | ||||

55 | { | ||||

56 | return 0 <= v && typename std::make_unsigned<T>::type(v) <= (xl::max)(); | ||||

57 | } | ||||

58 | | ||||

59 | template <typename X, typename T, typename xl = std::numeric_limits<X>> | ||||

60 | constexpr bool | ||||

61 | _fits_in(T v, false_type, false_type /* T unsigned */, ...) | ||||

62 | { | ||||

63 | return v <= typename std::make_unsigned<X>::type((xl::max)()); | ||||

64 | } | ||||

65 | | ||||

66 | template <typename X, typename T> | ||||

67 | constexpr bool | ||||

68 | fits_in(T v) | ||||

69 | { | ||||

70 | return _fits_in<X>(v, is_non_narrowing<X>(v), std::is_signed<T>(), | ||||

71 | std::is_signed<X>()); | ||||

72 | } | ||||

73 | | ||||

74 | template <typename X> | ||||

75 | struct to_chars_test_base | ||||

76 | { | ||||

77 | template <typename T, size_t N, typename... Ts> | ||||

78 | void test(T v, char const (&expect)[N], Ts... args) | ||||

79 | { | ||||

80 | using std::to_chars; | ||||

81 | std::to_chars_result r; | ||||

82 | | ||||

83 | constexpr size_t len = N - 1; | ||||

84 | static_assert(len > 0, "expected output won't be empty"); | ||||

85 | | ||||

86 | if (!fits_in<X>(v)) | ||||

87 | return; | ||||

88 | | ||||

89 | r = to_chars(buf, buf + len - 1, X(v), args...); | ||||

90 | assert(r.ptr == buf + len - 1); | ||||

91 | assert(r.ec == std::errc::value_too_large); | ||||

92 | | ||||

93 | r = to_chars(buf, buf + sizeof(buf), X(v), args...); | ||||

94 | assert(r.ptr == buf + len); | ||||

95 | assert(r.ec == std::errc{}); | ||||

96 | assert(memcmp(buf, expect, len) == 0); | ||||

97 | } | ||||

98 | | ||||

99 | template <typename... Ts> | ||||

100 | void test_value(X v, Ts... args) | ||||

101 | { | ||||

102 | using std::to_chars; | ||||

103 | std::to_chars_result r; | ||||

104 | | ||||

105 | r = to_chars(buf, buf + sizeof(buf), v, args...); | ||||

106 | assert(r.ec == std::errc{}); | ||||

107 | *r.ptr = '\0'; | ||||

108 | | ||||

109 | auto a = fromchars(buf, r.ptr, args...); | ||||

110 | assert(v == a); | ||||

111 | | ||||

112 | auto ep = r.ptr - 1; | ||||

113 | r = to_chars(buf, ep, v, args...); | ||||

114 | assert(r.ptr == ep); | ||||

115 | assert(r.ec == std::errc::value_too_large); | ||||

116 | } | ||||

117 | | ||||

118 | private: | ||||

119 | using max_t = typename std::conditional<std::is_signed<X>::value, long long, | ||||

120 | unsigned long long>::type; | ||||

121 | | ||||

122 | static auto fromchars(char const* p, char const* ep, int base, true_type) | ||||

123 | -> long long | ||||

124 | { | ||||

125 | char* last; | ||||

126 | auto r = strtoll(p, &last, base); | ||||

127 | assert(last == ep); | ||||

128 | | ||||

129 | return r; | ||||

130 | } | ||||

131 | | ||||

132 | static auto fromchars(char const* p, char const* ep, int base, false_type) | ||||

133 | -> unsigned long long | ||||

134 | { | ||||

135 | char* last; | ||||

136 | auto r = strtoull(p, &last, base); | ||||

137 | assert(last == ep); | ||||

138 | | ||||

139 | return r; | ||||

140 | } | ||||

141 | | ||||

142 | static auto fromchars(char const* p, char const* ep, int base = 10) -> max_t | ||||

143 | { | ||||

144 | return fromchars(p, ep, base, std::is_signed<X>()); | ||||

145 | } | ||||

146 | | ||||

147 | char buf[100]; | ||||

148 | }; | ||||

149 | | ||||

150 | template <typename X> | ||||

151 | struct roundtrip_test_base | ||||

152 | { | ||||

153 | template <typename T, typename... Ts> | ||||

154 | void test(T v, Ts... args) | ||||

155 | { | ||||

156 | using std::from_chars; | ||||

157 | using std::to_chars; | ||||

158 | std::from_chars_result r2; | ||||

159 | std::to_chars_result r; | ||||

160 | X x = 0xc; | ||||

161 | | ||||

162 | if (fits_in<X>(v)) | ||||

163 | { | ||||

164 | r = to_chars(buf, buf + sizeof(buf), v, args...); | ||||

165 | assert(r.ec == std::errc{}); | ||||

166 | | ||||

167 | r2 = from_chars(buf, r.ptr, x, args...); | ||||

168 | assert(r2.ptr == r.ptr); | ||||

169 | assert(x == X(v)); | ||||

170 | } | ||||

171 | else | ||||

172 | { | ||||

173 | r = to_chars(buf, buf + sizeof(buf), v, args...); | ||||

174 | assert(r.ec == std::errc{}); | ||||

175 | | ||||

176 | r2 = from_chars(buf, r.ptr, x, args...); | ||||

177 | | ||||

178 | if (std::is_signed<T>::value && v < 0 && std::is_unsigned<X>::value) | ||||

179 | { | ||||

180 | assert(x == 0xc); | ||||

181 | assert(r2.ptr == buf); | ||||

182 | assert(r.ec == std::errc::invalid_argument); | ||||

183 | } | ||||

184 | else | ||||

185 | { | ||||

186 | assert(x == 0xc); | ||||

187 | assert(r2.ptr == r.ptr); | ||||

188 | assert(r2.ec == std::errc::result_out_of_range); | ||||

189 | } | ||||

190 | } | ||||

191 | } | ||||

192 | | ||||

193 | private: | ||||

194 | char buf[100]; | ||||

195 | }; | ||||

196 | | ||||

197 | template <typename... T> | ||||

198 | struct type_list | ||||

199 | { | ||||

200 | }; | ||||

201 | | ||||

202 | template <typename L1, typename L2> | ||||

203 | struct type_concat; | ||||

204 | | ||||

205 | template <typename... Xs, typename... Ys> | ||||

206 | struct type_concat<type_list<Xs...>, type_list<Ys...>> | ||||

207 | { | ||||

208 | using type = type_list<Xs..., Ys...>; | ||||

209 | }; | ||||

210 | | ||||

211 | template <typename L1, typename L2> | ||||

212 | using concat_t = typename type_concat<L1, L2>::type; | ||||

213 | | ||||

214 | template <typename L1, typename L2> | ||||

215 | constexpr auto concat(L1, L2) -> concat_t<L1, L2> | ||||

216 | { | ||||

217 | return {}; | ||||

218 | } | ||||

219 | | ||||

220 | auto all_signed = type_list<char, signed char, short, int, long, long long>(); | ||||

221 | auto all_unsigned = type_list<unsigned char, unsigned short, unsigned int, | ||||

222 | unsigned long, unsigned long long>(); | ||||

223 | auto integrals = concat(all_signed, all_unsigned); | ||||

224 | | ||||

225 | template <template <typename> class Fn, typename... Ts> | ||||

226 | void | ||||

227 | run(type_list<Ts...>) | ||||

Not Done ReplyThis name On the other hand, it's in a test, so we can change it whenever we want. mclow.lists: This name `run` concerns me. I'd feel better if it was `run_integral_tests` or something a bit… | |||||

Not Done ReplyThe callsites look like run<test_signed>(all_signed); That's why I named it "run". Not an issue for now I think. lichray: The callsites look like
```
run<test_signed>(all_signed);
```
That's why I named it "run". Not… | |||||

228 | { | ||||

229 | int ls[sizeof...(Ts)] = {(Fn<Ts>{}(), 0)...}; | ||||

230 | (void)ls; | ||||

231 | } | ||||

232 | | ||||

233 | #endif // SUPPORT_CHARCONV_TEST_HELPERS_H |

If this is supposed to be a C++17 or later header (and I'm pretty sure it is), you should add a

static_assert(TEST_STD_VER > 14, "");to this header.