//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef SUPPORT_CHARCONV_TEST_HELPERS_H #define SUPPORT_CHARCONV_TEST_HELPERS_H #include #include #include #include #include #include "test_macros.h" #if TEST_STD_VER < 11 #error This file requires C++11 #endif using std::false_type; using std::true_type; template constexpr auto is_non_narrowing(From a) -> decltype(To{a}, true_type()) { return {}; } template constexpr auto is_non_narrowing(...) -> false_type { return {}; } template constexpr bool _fits_in(T, true_type /* non-narrowing*/, ...) { return true; } template > constexpr bool _fits_in(T v, false_type, true_type /* T signed*/, true_type /* X signed */) { return xl::lowest() <= v && v <= (xl::max)(); } template > constexpr bool _fits_in(T v, false_type, true_type /* T signed */, false_type /* X unsigned*/) { return 0 <= v && typename std::make_unsigned::type(v) <= (xl::max)(); } template > constexpr bool _fits_in(T v, false_type, false_type /* T unsigned */, ...) { return v <= typename std::make_unsigned::type((xl::max)()); } template constexpr bool fits_in(T v) { return _fits_in(v, is_non_narrowing(v), std::is_signed(), std::is_signed()); } template struct to_chars_test_base { template void test(T v, char const (&expect)[N], Ts... args) { using std::to_chars; std::to_chars_result r; constexpr size_t len = N - 1; static_assert(len > 0, "expected output won't be empty"); if (!fits_in(v)) return; r = to_chars(buf, buf + len - 1, X(v), args...); assert(r.ptr == buf + len - 1); assert(r.ec == std::errc::value_too_large); r = to_chars(buf, buf + sizeof(buf), X(v), args...); assert(r.ptr == buf + len); assert(r.ec == std::errc{}); assert(memcmp(buf, expect, len) == 0); } template void test_value(X v, Ts... args) { using std::to_chars; std::to_chars_result r; r = to_chars(buf, buf + sizeof(buf), v, args...); assert(r.ec == std::errc{}); *r.ptr = '\0'; auto a = fromchars(buf, r.ptr, args...); assert(v == a); auto ep = r.ptr - 1; r = to_chars(buf, ep, v, args...); assert(r.ptr == ep); assert(r.ec == std::errc::value_too_large); } private: static long long fromchars(char const* p, char const* ep, int base, true_type) { char* last; auto r = strtoll(p, &last, base); assert(last == ep); return r; } static unsigned long long fromchars(char const* p, char const* ep, int base, false_type) { char* last; auto r = strtoull(p, &last, base); assert(last == ep); return r; } static auto fromchars(char const* p, char const* ep, int base = 10) -> decltype(fromchars(p, ep, base, std::is_signed())) { return fromchars(p, ep, base, std::is_signed()); } char buf[100]; }; template struct roundtrip_test_base { template void test(T v, Ts... args) { using std::from_chars; using std::to_chars; std::from_chars_result r2; std::to_chars_result r; X x = 0xc; if (fits_in(v)) { r = to_chars(buf, buf + sizeof(buf), v, args...); assert(r.ec == std::errc{}); r2 = from_chars(buf, r.ptr, x, args...); assert(r2.ptr == r.ptr); assert(x == X(v)); } else { r = to_chars(buf, buf + sizeof(buf), v, args...); assert(r.ec == std::errc{}); r2 = from_chars(buf, r.ptr, x, args...); #ifdef TEST_COMPILER_C1XX #pragma warning(push) #pragma warning(disable: 4127) // conditional expression is constant #endif // TEST_COMPILER_C1XX if (std::is_signed::value && v < 0 && std::is_unsigned::value) { assert(x == 0xc); assert(r2.ptr == buf); assert(r2.ec == std::errc::invalid_argument); } else { assert(x == 0xc); assert(r2.ptr == r.ptr); assert(r2.ec == std::errc::result_out_of_range); } #ifdef TEST_COMPILER_C1XX #pragma warning(pop) #endif // TEST_COMPILER_C1XX } } private: char buf[100]; }; template struct type_list { }; template struct type_concat; template struct type_concat, type_list> { using type = type_list; }; template using concat_t = typename type_concat::type; template constexpr auto concat(L1, L2) -> concat_t { return {}; } auto all_signed = type_list(); auto all_unsigned = type_list(); auto integrals = concat(all_signed, all_unsigned); template