123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- //===----------------------------------------------------------------------===//
- //
- // 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 <charconv>
- #include <cassert>
- #include <limits>
- #include <string.h>
- #include <stdlib.h>
- #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 <typename To, typename From>
- constexpr auto
- is_non_narrowing(From a) -> decltype(To{a}, true_type())
- {
- return {};
- }
- template <typename To>
- constexpr auto
- is_non_narrowing(...) -> false_type
- {
- return {};
- }
- template <typename X, typename T>
- constexpr bool
- _fits_in(T, true_type /* non-narrowing*/, ...)
- {
- return true;
- }
- template <typename X, typename T, typename xl = std::numeric_limits<X>>
- constexpr bool
- _fits_in(T v, false_type, true_type /* T signed*/, true_type /* X signed */)
- {
- return xl::lowest() <= v && v <= (xl::max)();
- }
- template <typename X, typename T, typename xl = std::numeric_limits<X>>
- constexpr bool
- _fits_in(T v, false_type, true_type /* T signed */, false_type /* X unsigned*/)
- {
- return 0 <= v && typename std::make_unsigned<T>::type(v) <= (xl::max)();
- }
- template <typename X, typename T, typename xl = std::numeric_limits<X>>
- constexpr bool
- _fits_in(T v, false_type, false_type /* T unsigned */, ...)
- {
- return v <= typename std::make_unsigned<X>::type((xl::max)());
- }
- template <typename X, typename T>
- constexpr bool
- fits_in(T v)
- {
- return _fits_in<X>(v, is_non_narrowing<X>(v), std::is_signed<T>(),
- std::is_signed<X>());
- }
- template <typename X>
- struct to_chars_test_base
- {
- template <typename T, size_t N, typename... Ts>
- 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<X>(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 <typename... Ts>
- 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<X>()))
- {
- return fromchars(p, ep, base, std::is_signed<X>());
- }
- char buf[100];
- };
- template <typename X>
- struct roundtrip_test_base
- {
- template <typename T, typename... Ts>
- 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<X>(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...);
- if (std::is_signed<T>::value && v < 0 && std::is_unsigned<X>::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);
- }
- }
- }
- private:
- char buf[100];
- };
- template <typename... T>
- struct type_list
- {
- };
- template <typename L1, typename L2>
- struct type_concat;
- template <typename... Xs, typename... Ys>
- struct type_concat<type_list<Xs...>, type_list<Ys...>>
- {
- using type = type_list<Xs..., Ys...>;
- };
- template <typename L1, typename L2>
- using concat_t = typename type_concat<L1, L2>::type;
- template <typename L1, typename L2>
- constexpr auto concat(L1, L2) -> concat_t<L1, L2>
- {
- return {};
- }
- auto all_signed = type_list<char, signed char, short, int, long, long long>();
- auto all_unsigned = type_list<unsigned char, unsigned short, unsigned int,
- unsigned long, unsigned long long>();
- auto integrals = concat(all_signed, all_unsigned);
- template <template <typename> class Fn, typename... Ts>
- void
- run(type_list<Ts...>)
- {
- int ls[sizeof...(Ts)] = {(Fn<Ts>{}(), 0)...};
- (void)ls;
- }
- #endif // SUPPORT_CHARCONV_TEST_HELPERS_H
|