1d2748964SZhihao Yuan //===----------------------------------------------------------------------===// 2d2748964SZhihao Yuan // 357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6d2748964SZhihao Yuan // 7d2748964SZhihao Yuan //===----------------------------------------------------------------------===// 8d2748964SZhihao Yuan 9d2748964SZhihao Yuan #ifndef SUPPORT_CHARCONV_TEST_HELPERS_H 10d2748964SZhihao Yuan #define SUPPORT_CHARCONV_TEST_HELPERS_H 11d2748964SZhihao Yuan 12a1e13a80SMark de Wever #include <algorithm> 13d2748964SZhihao Yuan #include <cassert> 14eb65912eSNikolas Klauser #include <cerrno> 15eb65912eSNikolas Klauser #include <charconv> 16fb855eb9SMark de Wever #include <cstddef> 17d2748964SZhihao Yuan #include <limits> 189393060fSMark de Wever #include <numeric> 19d2748964SZhihao Yuan #include <string.h> 20d2748964SZhihao Yuan #include <stdlib.h> 21f7efcacaSMark de Wever #include <type_traits> 22d2748964SZhihao Yuan 23d2748964SZhihao Yuan #include "test_macros.h" 24d2748964SZhihao Yuan 25769c2459SMarshall Clow #if TEST_STD_VER < 11 26769c2459SMarshall Clow #error This file requires C++11 27d2748964SZhihao Yuan #endif 28d2748964SZhihao Yuan 29d2748964SZhihao Yuan using std::false_type; 30d2748964SZhihao Yuan using std::true_type; 31d2748964SZhihao Yuan 32d2748964SZhihao Yuan template <typename To, typename From> 33d2748964SZhihao Yuan constexpr auto 34d2748964SZhihao Yuan is_non_narrowing(From a) -> decltype(To{a}, true_type()) 35d2748964SZhihao Yuan { 36d2748964SZhihao Yuan return {}; 37d2748964SZhihao Yuan } 38d2748964SZhihao Yuan 39d2748964SZhihao Yuan template <typename To> 40d2748964SZhihao Yuan constexpr auto 41d2748964SZhihao Yuan is_non_narrowing(...) -> false_type 42d2748964SZhihao Yuan { 43d2748964SZhihao Yuan return {}; 44d2748964SZhihao Yuan } 45d2748964SZhihao Yuan 46d2748964SZhihao Yuan template <typename X, typename T> 47d2748964SZhihao Yuan constexpr bool 48d2748964SZhihao Yuan _fits_in(T, true_type /* non-narrowing*/, ...) 49d2748964SZhihao Yuan { 50d2748964SZhihao Yuan return true; 51d2748964SZhihao Yuan } 52d2748964SZhihao Yuan 53d2748964SZhihao Yuan template <typename X, typename T, typename xl = std::numeric_limits<X>> 54d2748964SZhihao Yuan constexpr bool 55d2748964SZhihao Yuan _fits_in(T v, false_type, true_type /* T signed*/, true_type /* X signed */) 56d2748964SZhihao Yuan { 57d2748964SZhihao Yuan return xl::lowest() <= v && v <= (xl::max)(); 58d2748964SZhihao Yuan } 59d2748964SZhihao Yuan 60d2748964SZhihao Yuan template <typename X, typename T, typename xl = std::numeric_limits<X>> 61d2748964SZhihao Yuan constexpr bool 62d2748964SZhihao Yuan _fits_in(T v, false_type, true_type /* T signed */, false_type /* X unsigned*/) 63d2748964SZhihao Yuan { 64769c2459SMarshall Clow return 0 <= v && typename std::make_unsigned<T>::type(v) <= (xl::max)(); 65d2748964SZhihao Yuan } 66d2748964SZhihao Yuan 67d2748964SZhihao Yuan template <typename X, typename T, typename xl = std::numeric_limits<X>> 68d2748964SZhihao Yuan constexpr bool 69d2748964SZhihao Yuan _fits_in(T v, false_type, false_type /* T unsigned */, ...) 70d2748964SZhihao Yuan { 71769c2459SMarshall Clow return v <= typename std::make_unsigned<X>::type((xl::max)()); 72d2748964SZhihao Yuan } 73d2748964SZhihao Yuan 74d2748964SZhihao Yuan template <typename X, typename T> 75d2748964SZhihao Yuan constexpr bool 76d2748964SZhihao Yuan fits_in(T v) 77d2748964SZhihao Yuan { 783f786833SMark de Wever return _fits_in<X>(v, is_non_narrowing<X>(v), std::is_signed<T>(), std::is_signed<X>()); 79d2748964SZhihao Yuan } 80d2748964SZhihao Yuan 81d2748964SZhihao Yuan template <typename X> 82d2748964SZhihao Yuan struct to_chars_test_base 83d2748964SZhihao Yuan { 84fb855eb9SMark de Wever template <typename T, std::size_t N, typename... Ts> 85a1e13a80SMark de Wever TEST_CONSTEXPR_CXX23 void test(T v, char const (&expect)[N], Ts... args) 86d2748964SZhihao Yuan { 87d2748964SZhihao Yuan std::to_chars_result r; 88d2748964SZhihao Yuan 89fb855eb9SMark de Wever constexpr std::size_t len = N - 1; 90d2748964SZhihao Yuan static_assert(len > 0, "expected output won't be empty"); 91d2748964SZhihao Yuan 92d2748964SZhihao Yuan if (!fits_in<X>(v)) 93d2748964SZhihao Yuan return; 94d2748964SZhihao Yuan 95a1e13a80SMark de Wever r = std::to_chars(buf, buf + len - 1, X(v), args...); 96d2748964SZhihao Yuan assert(r.ptr == buf + len - 1); 97d2748964SZhihao Yuan assert(r.ec == std::errc::value_too_large); 98d2748964SZhihao Yuan 99a1e13a80SMark de Wever r = std::to_chars(buf, buf + sizeof(buf), X(v), args...); 100d2748964SZhihao Yuan assert(r.ptr == buf + len); 101d2748964SZhihao Yuan assert(r.ec == std::errc{}); 102a1e13a80SMark de Wever assert(std::equal(buf, buf + len, expect)); 103d2748964SZhihao Yuan } 104d2748964SZhihao Yuan 105d2748964SZhihao Yuan template <typename... Ts> 106a1e13a80SMark de Wever TEST_CONSTEXPR_CXX23 void test_value(X v, Ts... args) 107d2748964SZhihao Yuan { 108d2748964SZhihao Yuan std::to_chars_result r; 109d2748964SZhihao Yuan 1109393060fSMark de Wever // Poison the buffer for testing whether a successful std::to_chars 111a1e13a80SMark de Wever // doesn't modify data beyond r.ptr. Use unsigned values to avoid 112a1e13a80SMark de Wever // overflowing char when it's signed. 113a1e13a80SMark de Wever std::iota(buf, buf + sizeof(buf), static_cast<unsigned char>(1)); 114a1e13a80SMark de Wever r = std::to_chars(buf, buf + sizeof(buf), v, args...); 115d2748964SZhihao Yuan assert(r.ec == std::errc{}); 116fb855eb9SMark de Wever for (std::size_t i = r.ptr - buf; i < sizeof(buf); ++i) 117a1e13a80SMark de Wever assert(static_cast<unsigned char>(buf[i]) == i + 1); 118d2748964SZhihao Yuan *r.ptr = '\0'; 119d2748964SZhihao Yuan 1203f786833SMark de Wever #ifndef TEST_HAS_NO_INT128 1213f786833SMark de Wever if (sizeof(X) == sizeof(__int128_t)) { 1223f786833SMark de Wever auto a = fromchars128_impl(buf, r.ptr, args...); 123d2748964SZhihao Yuan assert(v == a); 1243f786833SMark de Wever } else 1253f786833SMark de Wever #endif 1263f786833SMark de Wever { 1273f786833SMark de Wever auto a = fromchars_impl(buf, r.ptr, args...); 1283f786833SMark de Wever assert(v == a); 1293f786833SMark de Wever } 130d2748964SZhihao Yuan 131d2748964SZhihao Yuan auto ep = r.ptr - 1; 132a1e13a80SMark de Wever r = std::to_chars(buf, ep, v, args...); 133d2748964SZhihao Yuan assert(r.ptr == ep); 134d2748964SZhihao Yuan assert(r.ec == std::errc::value_too_large); 135d2748964SZhihao Yuan } 136d2748964SZhihao Yuan 137d2748964SZhihao Yuan private: 138a1e13a80SMark de Wever static TEST_CONSTEXPR_CXX23 long long fromchars_impl(char const* p, char const* ep, int base, true_type) 139d2748964SZhihao Yuan { 140d2748964SZhihao Yuan char* last; 141a1e13a80SMark de Wever long long r; 142a1e13a80SMark de Wever if (TEST_IS_CONSTANT_EVALUATED) 143a1e13a80SMark de Wever last = const_cast<char*>(std::from_chars(p, ep, r, base).ptr); 144a1e13a80SMark de Wever else 145a1e13a80SMark de Wever r = strtoll(p, &last, base); 146d2748964SZhihao Yuan assert(last == ep); 147d2748964SZhihao Yuan 148d2748964SZhihao Yuan return r; 149d2748964SZhihao Yuan } 150d2748964SZhihao Yuan 151a1e13a80SMark de Wever static TEST_CONSTEXPR_CXX23 unsigned long long fromchars_impl(char const* p, char const* ep, int base, false_type) 152d2748964SZhihao Yuan { 153d2748964SZhihao Yuan char* last; 154a1e13a80SMark de Wever unsigned long long r; 155a1e13a80SMark de Wever if (TEST_IS_CONSTANT_EVALUATED) 156a1e13a80SMark de Wever last = const_cast<char*>(std::from_chars(p, ep, r, base).ptr); 157a1e13a80SMark de Wever else 158a1e13a80SMark de Wever r = strtoull(p, &last, base); 159d2748964SZhihao Yuan assert(last == ep); 160d2748964SZhihao Yuan 161d2748964SZhihao Yuan return r; 162d2748964SZhihao Yuan } 1633f786833SMark de Wever #ifndef TEST_HAS_NO_INT128 164a1e13a80SMark de Wever static TEST_CONSTEXPR_CXX23 __int128_t fromchars128_impl(char const* p, char const* ep, int base, true_type) 165d2748964SZhihao Yuan { 166a1e13a80SMark de Wever if (!TEST_IS_CONSTANT_EVALUATED) { 1673f786833SMark de Wever char* last; 1683f786833SMark de Wever __int128_t r = strtoll(p, &last, base); 1693f786833SMark de Wever if(errno != ERANGE) { 1703f786833SMark de Wever assert(last == ep); 1713f786833SMark de Wever return r; 172d2748964SZhihao Yuan } 173a1e13a80SMark de Wever } 174d2748964SZhihao Yuan 1753f786833SMark de Wever // When the value doesn't fit in a long long use from_chars. This is 1763f786833SMark de Wever // not ideal since it does a round-trip test instead if using an 1773f786833SMark de Wever // external source. 178a1e13a80SMark de Wever __int128_t r; 1793f786833SMark de Wever std::from_chars_result s = std::from_chars(p, ep, r, base); 1803f786833SMark de Wever assert(s.ec == std::errc{}); 1813f786833SMark de Wever assert(s.ptr == ep); 1823f786833SMark de Wever 1833f786833SMark de Wever return r; 1843f786833SMark de Wever } 1853f786833SMark de Wever 186a1e13a80SMark de Wever static TEST_CONSTEXPR_CXX23 __uint128_t fromchars128_impl(char const* p, char const* ep, int base, false_type) 1873f786833SMark de Wever { 188a1e13a80SMark de Wever if (!TEST_IS_CONSTANT_EVALUATED) { 1893f786833SMark de Wever char* last; 1903f786833SMark de Wever __uint128_t r = strtoull(p, &last, base); 1913f786833SMark de Wever if(errno != ERANGE) { 1923f786833SMark de Wever assert(last == ep); 1933f786833SMark de Wever return r; 1943f786833SMark de Wever } 195a1e13a80SMark de Wever } 1963f786833SMark de Wever 197a1e13a80SMark de Wever __uint128_t r; 1983f786833SMark de Wever std::from_chars_result s = std::from_chars(p, ep, r, base); 1993f786833SMark de Wever assert(s.ec == std::errc{}); 2003f786833SMark de Wever assert(s.ptr == ep); 2013f786833SMark de Wever 2023f786833SMark de Wever return r; 2033f786833SMark de Wever } 2043f786833SMark de Wever 205a1e13a80SMark de Wever static TEST_CONSTEXPR_CXX23 auto fromchars128_impl(char const* p, char const* ep, int base = 10) 2063f786833SMark de Wever -> decltype(fromchars128_impl(p, ep, base, std::is_signed<X>())) 2073f786833SMark de Wever { 2083f786833SMark de Wever return fromchars128_impl(p, ep, base, std::is_signed<X>()); 2093f786833SMark de Wever } 2103f786833SMark de Wever 2113f786833SMark de Wever #endif 2123f786833SMark de Wever 213a1e13a80SMark de Wever static TEST_CONSTEXPR_CXX23 auto fromchars_impl(char const* p, char const* ep, int base = 10) 2143f786833SMark de Wever -> decltype(fromchars_impl(p, ep, base, std::is_signed<X>())) 2153f786833SMark de Wever { 2163f786833SMark de Wever return fromchars_impl(p, ep, base, std::is_signed<X>()); 2173f786833SMark de Wever } 2183f786833SMark de Wever 2193f786833SMark de Wever char buf[150]; 220d2748964SZhihao Yuan }; 221d2748964SZhihao Yuan 222d2748964SZhihao Yuan template <typename X> 223d2748964SZhihao Yuan struct roundtrip_test_base 224d2748964SZhihao Yuan { 225d2748964SZhihao Yuan template <typename T, typename... Ts> 226a1e13a80SMark de Wever TEST_CONSTEXPR_CXX23 void test(T v, Ts... args) 227d2748964SZhihao Yuan { 228d2748964SZhihao Yuan std::from_chars_result r2; 229d2748964SZhihao Yuan std::to_chars_result r; 230d2748964SZhihao Yuan X x = 0xc; 231d2748964SZhihao Yuan 232d2748964SZhihao Yuan if (fits_in<X>(v)) 233d2748964SZhihao Yuan { 234a1e13a80SMark de Wever r = std::to_chars(buf, buf + sizeof(buf), v, args...); 235d2748964SZhihao Yuan assert(r.ec == std::errc{}); 236d2748964SZhihao Yuan 237a1e13a80SMark de Wever r2 = std::from_chars(buf, r.ptr, x, args...); 238d2748964SZhihao Yuan assert(r2.ptr == r.ptr); 239d2748964SZhihao Yuan assert(x == X(v)); 240d2748964SZhihao Yuan } 241d2748964SZhihao Yuan else 242d2748964SZhihao Yuan { 243a1e13a80SMark de Wever r = std::to_chars(buf, buf + sizeof(buf), v, args...); 244d2748964SZhihao Yuan assert(r.ec == std::errc{}); 245d2748964SZhihao Yuan 246a1e13a80SMark de Wever r2 = std::from_chars(buf, r.ptr, x, args...); 247d2748964SZhihao Yuan 24814324fa4SNikolas Klauser TEST_DIAGNOSTIC_PUSH 24914324fa4SNikolas Klauser TEST_MSVC_DIAGNOSTIC_IGNORED(4127) // conditional expression is constant 25014324fa4SNikolas Klauser 251d2748964SZhihao Yuan if (std::is_signed<T>::value && v < 0 && std::is_unsigned<X>::value) 252d2748964SZhihao Yuan { 253d2748964SZhihao Yuan assert(x == 0xc); 254d2748964SZhihao Yuan assert(r2.ptr == buf); 25563ebd3bdSZhihao Yuan assert(r2.ec == std::errc::invalid_argument); 256d2748964SZhihao Yuan } 257d2748964SZhihao Yuan else 258d2748964SZhihao Yuan { 259d2748964SZhihao Yuan assert(x == 0xc); 260d2748964SZhihao Yuan assert(r2.ptr == r.ptr); 261d2748964SZhihao Yuan assert(r2.ec == std::errc::result_out_of_range); 262d2748964SZhihao Yuan } 26314324fa4SNikolas Klauser 26414324fa4SNikolas Klauser TEST_DIAGNOSTIC_POP 265d2748964SZhihao Yuan } 266d2748964SZhihao Yuan } 267d2748964SZhihao Yuan 268d2748964SZhihao Yuan private: 2693f786833SMark de Wever char buf[150]; 270d2748964SZhihao Yuan }; 271d2748964SZhihao Yuan 272d2748964SZhihao Yuan template <typename... T> 273d2748964SZhihao Yuan struct type_list 274d2748964SZhihao Yuan { 275d2748964SZhihao Yuan }; 276d2748964SZhihao Yuan 277d2748964SZhihao Yuan template <typename L1, typename L2> 278d2748964SZhihao Yuan struct type_concat; 279d2748964SZhihao Yuan 280d2748964SZhihao Yuan template <typename... Xs, typename... Ys> 281d2748964SZhihao Yuan struct type_concat<type_list<Xs...>, type_list<Ys...>> 282d2748964SZhihao Yuan { 283d2748964SZhihao Yuan using type = type_list<Xs..., Ys...>; 284d2748964SZhihao Yuan }; 285d2748964SZhihao Yuan 286d2748964SZhihao Yuan template <typename L1, typename L2> 287d2748964SZhihao Yuan using concat_t = typename type_concat<L1, L2>::type; 288d2748964SZhihao Yuan 289d2748964SZhihao Yuan template <typename L1, typename L2> 290d2748964SZhihao Yuan constexpr auto concat(L1, L2) -> concat_t<L1, L2> 291d2748964SZhihao Yuan { 292d2748964SZhihao Yuan return {}; 293d2748964SZhihao Yuan } 294d2748964SZhihao Yuan 2953f786833SMark de Wever auto all_signed = type_list< 2963f786833SMark de Wever char, 2973f786833SMark de Wever signed char, 2983f786833SMark de Wever short, 2993f786833SMark de Wever int, 3003f786833SMark de Wever long, 3013f786833SMark de Wever long long 3023f786833SMark de Wever #ifndef TEST_HAS_NO_INT128 3033f786833SMark de Wever , 3043f786833SMark de Wever __int128_t 3053f786833SMark de Wever #endif 3063f786833SMark de Wever >(); 3073f786833SMark de Wever auto all_unsigned = type_list< 3083f786833SMark de Wever unsigned char, 3093f786833SMark de Wever unsigned short, 3103f786833SMark de Wever unsigned int, 3113f786833SMark de Wever unsigned long, 3123f786833SMark de Wever unsigned long long 3133f786833SMark de Wever #ifndef TEST_HAS_NO_INT128 3143f786833SMark de Wever , 3153f786833SMark de Wever __uint128_t 3163f786833SMark de Wever #endif 3173f786833SMark de Wever >(); 318d2748964SZhihao Yuan auto integrals = concat(all_signed, all_unsigned); 319d2748964SZhihao Yuan 320*6c4267fbSMichael Jones auto all_floats = type_list< float, double >(); //TODO: Add long double 321*6c4267fbSMichael Jones 322d2748964SZhihao Yuan template <template <typename> class Fn, typename... Ts> 323a1e13a80SMark de Wever TEST_CONSTEXPR_CXX23 void 324d2748964SZhihao Yuan run(type_list<Ts...>) 325d2748964SZhihao Yuan { 326d2748964SZhihao Yuan int ls[sizeof...(Ts)] = {(Fn<Ts>{}(), 0)...}; 327d2748964SZhihao Yuan (void)ls; 328d2748964SZhihao Yuan } 329d2748964SZhihao Yuan 330d2748964SZhihao Yuan #endif // SUPPORT_CHARCONV_TEST_HELPERS_H 331