1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef SUPPORT_CHARCONV_TEST_HELPERS_H
10 #define SUPPORT_CHARCONV_TEST_HELPERS_H
21 #include <type_traits>
23 #include "test_macros.h"
26 #error This file requires C++11
29 using std::false_type
;
32 template <typename To
, typename From
>
34 is_non_narrowing(From a
) -> decltype(To
{a
}, true_type())
39 template <typename To
>
41 is_non_narrowing(...) -> false_type
46 template <typename X
, typename T
>
48 _fits_in(T
, true_type
/* non-narrowing*/, ...)
53 template <typename X
, typename T
, typename xl
= std::numeric_limits
<X
>>
55 _fits_in(T v
, false_type
, true_type
/* T signed*/, true_type
/* X signed */)
57 return xl::lowest() <= v
&& v
<= (xl::max
)();
60 template <typename X
, typename T
, typename xl
= std::numeric_limits
<X
>>
62 _fits_in(T v
, false_type
, true_type
/* T signed */, false_type
/* X unsigned*/)
64 return 0 <= v
&& typename
std::make_unsigned
<T
>::type(v
) <= (xl::max
)();
67 template <typename X
, typename T
, typename xl
= std::numeric_limits
<X
>>
69 _fits_in(T v
, false_type
, false_type
/* T unsigned */, ...)
71 return v
<= typename
std::make_unsigned
<X
>::type((xl::max
)());
74 template <typename X
, typename T
>
78 return _fits_in
<X
>(v
, is_non_narrowing
<X
>(v
), std::is_signed
<T
>(), std::is_signed
<X
>());
82 struct to_chars_test_base
84 template <typename T
, std::size_t N
, typename
... Ts
>
85 TEST_CONSTEXPR_CXX23
void test(T v
, char const (&expect
)[N
], Ts
... args
)
87 std::to_chars_result r
;
89 constexpr std::size_t len
= N
- 1;
90 static_assert(len
> 0, "expected output won't be empty");
95 r
= std::to_chars(buf
, buf
+ len
- 1, X(v
), args
...);
96 assert(r
.ptr
== buf
+ len
- 1);
97 assert(r
.ec
== std::errc::value_too_large
);
99 r
= std::to_chars(buf
, buf
+ sizeof(buf
), X(v
), args
...);
100 assert(r
.ptr
== buf
+ len
);
101 assert(r
.ec
== std::errc
{});
102 assert(std::equal(buf
, buf
+ len
, expect
));
105 template <typename
... Ts
>
106 TEST_CONSTEXPR_CXX23
void test_value(X v
, Ts
... args
)
108 std::to_chars_result r
;
110 // Poison the buffer for testing whether a successful std::to_chars
111 // doesn't modify data beyond r.ptr. Use unsigned values to avoid
112 // overflowing char when it's signed.
113 std::iota(buf
, buf
+ sizeof(buf
), static_cast<unsigned char>(1));
114 r
= std::to_chars(buf
, buf
+ sizeof(buf
), v
, args
...);
115 assert(r
.ec
== std::errc
{});
116 for (std::size_t i
= r
.ptr
- buf
; i
< sizeof(buf
); ++i
)
117 assert(static_cast<unsigned char>(buf
[i
]) == i
+ 1);
120 #ifndef TEST_HAS_NO_INT128
121 if (sizeof(X
) == sizeof(__int128_t
)) {
122 auto a
= fromchars128_impl(buf
, r
.ptr
, args
...);
127 auto a
= fromchars_impl(buf
, r
.ptr
, args
...);
132 r
= std::to_chars(buf
, ep
, v
, args
...);
134 assert(r
.ec
== std::errc::value_too_large
);
138 static TEST_CONSTEXPR_CXX23
long long fromchars_impl(char const* p
, char const* ep
, int base
, true_type
)
142 if (TEST_IS_CONSTANT_EVALUATED
)
143 last
= const_cast<char*>(std::from_chars(p
, ep
, r
, base
).ptr
);
145 r
= strtoll(p
, &last
, base
);
151 static TEST_CONSTEXPR_CXX23
unsigned long long fromchars_impl(char const* p
, char const* ep
, int base
, false_type
)
154 unsigned long long r
;
155 if (TEST_IS_CONSTANT_EVALUATED
)
156 last
= const_cast<char*>(std::from_chars(p
, ep
, r
, base
).ptr
);
158 r
= strtoull(p
, &last
, base
);
163 #ifndef TEST_HAS_NO_INT128
164 static TEST_CONSTEXPR_CXX23 __int128_t
fromchars128_impl(char const* p
, char const* ep
, int base
, true_type
)
166 if (!TEST_IS_CONSTANT_EVALUATED
) {
168 __int128_t r
= strtoll(p
, &last
, base
);
169 if(errno
!= ERANGE
) {
175 // When the value doesn't fit in a long long use from_chars. This is
176 // not ideal since it does a round-trip test instead if using an
179 std::from_chars_result s
= std::from_chars(p
, ep
, r
, base
);
180 assert(s
.ec
== std::errc
{});
186 static TEST_CONSTEXPR_CXX23 __uint128_t
fromchars128_impl(char const* p
, char const* ep
, int base
, false_type
)
188 if (!TEST_IS_CONSTANT_EVALUATED
) {
190 __uint128_t r
= strtoull(p
, &last
, base
);
191 if(errno
!= ERANGE
) {
198 std::from_chars_result s
= std::from_chars(p
, ep
, r
, base
);
199 assert(s
.ec
== std::errc
{});
205 static TEST_CONSTEXPR_CXX23
auto fromchars128_impl(char const* p
, char const* ep
, int base
= 10)
206 -> decltype(fromchars128_impl(p
, ep
, base
, std::is_signed
<X
>()))
208 return fromchars128_impl(p
, ep
, base
, std::is_signed
<X
>());
213 static TEST_CONSTEXPR_CXX23
auto fromchars_impl(char const* p
, char const* ep
, int base
= 10)
214 -> decltype(fromchars_impl(p
, ep
, base
, std::is_signed
<X
>()))
216 return fromchars_impl(p
, ep
, base
, std::is_signed
<X
>());
222 template <typename X
>
223 struct roundtrip_test_base
225 template <typename T
, typename
... Ts
>
226 TEST_CONSTEXPR_CXX23
void test(T v
, Ts
... args
)
228 std::from_chars_result r2
;
229 std::to_chars_result r
;
234 r
= std::to_chars(buf
, buf
+ sizeof(buf
), v
, args
...);
235 assert(r
.ec
== std::errc
{});
237 r2
= std::from_chars(buf
, r
.ptr
, x
, args
...);
238 assert(r2
.ptr
== r
.ptr
);
243 r
= std::to_chars(buf
, buf
+ sizeof(buf
), v
, args
...);
244 assert(r
.ec
== std::errc
{});
246 r2
= std::from_chars(buf
, r
.ptr
, x
, args
...);
249 TEST_MSVC_DIAGNOSTIC_IGNORED(4127) // conditional expression is constant
251 if (std::is_signed
<T
>::value
&& v
< 0 && std::is_unsigned
<X
>::value
)
254 assert(r2
.ptr
== buf
);
255 assert(r2
.ec
== std::errc::invalid_argument
);
260 assert(r2
.ptr
== r
.ptr
);
261 assert(r2
.ec
== std::errc::result_out_of_range
);
272 template <typename
... T
>
277 template <typename L1
, typename L2
>
280 template <typename
... Xs
, typename
... Ys
>
281 struct type_concat
<type_list
<Xs
...>, type_list
<Ys
...>>
283 using type
= type_list
<Xs
..., Ys
...>;
286 template <typename L1
, typename L2
>
287 using concat_t
= typename type_concat
<L1
, L2
>::type
;
289 template <typename L1
, typename L2
>
290 constexpr auto concat(L1
, L2
) -> concat_t
<L1
, L2
>
295 auto all_signed
= type_list
<
302 #ifndef TEST_HAS_NO_INT128
307 auto all_unsigned
= type_list
<
313 #ifndef TEST_HAS_NO_INT128
318 auto integrals
= concat(all_signed
, all_unsigned
);
320 auto all_floats
= type_list
< float, double >(); //TODO: Add long double
322 template <template <typename
> class Fn
, typename
... Ts
>
323 TEST_CONSTEXPR_CXX23
void
324 run(type_list
<Ts
...>)
326 int ls
[sizeof...(Ts
)] = {(Fn
<Ts
>{}(), 0)...};
330 #endif // SUPPORT_CHARCONV_TEST_HELPERS_H