brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.7 KiB · fcae094 Raw
331 lines · c
1//===----------------------------------------------------------------------===//2//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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef SUPPORT_CHARCONV_TEST_HELPERS_H10#define SUPPORT_CHARCONV_TEST_HELPERS_H11 12#include <algorithm>13#include <cassert>14#include <cerrno>15#include <charconv>16#include <cstddef>17#include <limits>18#include <numeric>19#include <string.h>20#include <stdlib.h>21#include <type_traits>22 23#include "test_macros.h"24 25#if TEST_STD_VER < 1126#error This file requires C++1127#endif28 29using std::false_type;30using std::true_type;31 32template <typename To, typename From>33constexpr auto34is_non_narrowing(From a) -> decltype(To{a}, true_type())35{36    return {};37}38 39template <typename To>40constexpr auto41is_non_narrowing(...) -> false_type42{43    return {};44}45 46template <typename X, typename T>47constexpr bool48_fits_in(T, true_type /* non-narrowing*/, ...)49{50    return true;51}52 53template <typename X, typename T, typename xl = std::numeric_limits<X>>54constexpr bool55_fits_in(T v, false_type, true_type /* T signed*/, true_type /* X signed */)56{57    return xl::lowest() <= v && v <= (xl::max)();58}59 60template <typename X, typename T, typename xl = std::numeric_limits<X>>61constexpr bool62_fits_in(T v, false_type, true_type /* T signed */, false_type /* X unsigned*/)63{64    return 0 <= v && typename std::make_unsigned<T>::type(v) <= (xl::max)();65}66 67template <typename X, typename T, typename xl = std::numeric_limits<X>>68constexpr bool69_fits_in(T v, false_type, false_type /* T unsigned */, ...)70{71    return v <= typename std::make_unsigned<X>::type((xl::max)());72}73 74template <typename X, typename T>75constexpr bool76fits_in(T v)77{78  return _fits_in<X>(v, is_non_narrowing<X>(v), std::is_signed<T>(), std::is_signed<X>());79}80 81template <typename X>82struct to_chars_test_base83{84    template <typename T, std::size_t N, typename... Ts>85    TEST_CONSTEXPR_CXX23 void test(T v, char const (&expect)[N], Ts... args)86    {87        std::to_chars_result r;88 89        constexpr std::size_t len = N - 1;90        static_assert(len > 0, "expected output won't be empty");91 92        if (!fits_in<X>(v))93            return;94 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);98 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));103    }104 105    template <typename... Ts>106    TEST_CONSTEXPR_CXX23 void test_value(X v, Ts... args)107    {108        std::to_chars_result r;109 110        // Poison the buffer for testing whether a successful std::to_chars111        // doesn't modify data beyond r.ptr. Use unsigned values to avoid112        // 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);118        *r.ptr = '\0';119 120#ifndef TEST_HAS_NO_INT128121        if (sizeof(X) == sizeof(__int128_t)) {122            auto a = fromchars128_impl(buf, r.ptr, args...);123            assert(v == a);124        } else125#endif126        {127            auto a = fromchars_impl(buf, r.ptr, args...);128            assert(v == a);129        }130 131        auto ep = r.ptr - 1;132        r = std::to_chars(buf, ep, v, args...);133        assert(r.ptr == ep);134        assert(r.ec == std::errc::value_too_large);135    }136 137private:138    static TEST_CONSTEXPR_CXX23 long long fromchars_impl(char const* p, char const* ep, int base, true_type)139    {140        char* last;141        long long r;142        if (TEST_IS_CONSTANT_EVALUATED)143          last = const_cast<char*>(std::from_chars(p, ep, r, base).ptr);144        else145          r = strtoll(p, &last, base);146        assert(last == ep);147 148        return r;149    }150 151    static TEST_CONSTEXPR_CXX23 unsigned long long fromchars_impl(char const* p, char const* ep, int base, false_type)152    {153        char* last;154        unsigned long long r;155        if (TEST_IS_CONSTANT_EVALUATED)156          last = const_cast<char*>(std::from_chars(p, ep, r, base).ptr);157        else158          r = strtoull(p, &last, base);159        assert(last == ep);160 161        return r;162    }163#ifndef TEST_HAS_NO_INT128164    static TEST_CONSTEXPR_CXX23 __int128_t fromchars128_impl(char const* p, char const* ep, int base, true_type)165    {166        if (!TEST_IS_CONSTANT_EVALUATED) {167            char* last;168            __int128_t r = strtoll(p, &last, base);169            if(errno != ERANGE) {170                assert(last == ep);171                return r;172            }173        }174 175        // When the value doesn't fit in a long long use from_chars. This is176        // not ideal since it does a round-trip test instead if using an177        // external source.178        __int128_t r;179        std::from_chars_result s = std::from_chars(p, ep, r, base);180        assert(s.ec == std::errc{});181        assert(s.ptr == ep);182 183        return r;184    }185 186    static TEST_CONSTEXPR_CXX23 __uint128_t fromchars128_impl(char const* p, char const* ep, int base, false_type)187    {188        if (!TEST_IS_CONSTANT_EVALUATED) {189            char* last;190            __uint128_t r = strtoull(p, &last, base);191            if(errno != ERANGE) {192                assert(last == ep);193                return r;194            }195        }196 197        __uint128_t r;198        std::from_chars_result s = std::from_chars(p, ep, r, base);199        assert(s.ec == std::errc{});200        assert(s.ptr == ep);201 202        return r;203    }204 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>()))207    {208        return fromchars128_impl(p, ep, base, std::is_signed<X>());209    }210 211#endif212 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>()))215    {216        return fromchars_impl(p, ep, base, std::is_signed<X>());217    }218 219    char buf[150];220};221 222template <typename X>223struct roundtrip_test_base224{225    template <typename T, typename... Ts>226    TEST_CONSTEXPR_CXX23 void test(T v, Ts... args)227    {228        std::from_chars_result r2;229        std::to_chars_result r;230        X x = 0xc;231 232        if (fits_in<X>(v))233        {234            r = std::to_chars(buf, buf + sizeof(buf), v, args...);235            assert(r.ec == std::errc{});236 237            r2 = std::from_chars(buf, r.ptr, x, args...);238            assert(r2.ptr == r.ptr);239            assert(x == X(v));240        }241        else242        {243            r = std::to_chars(buf, buf + sizeof(buf), v, args...);244            assert(r.ec == std::errc{});245 246            r2 = std::from_chars(buf, r.ptr, x, args...);247 248            TEST_DIAGNOSTIC_PUSH249            TEST_MSVC_DIAGNOSTIC_IGNORED(4127) // conditional expression is constant250 251            if (std::is_signed<T>::value && v < 0 && std::is_unsigned<X>::value)252            {253                assert(x == 0xc);254                assert(r2.ptr == buf);255                assert(r2.ec == std::errc::invalid_argument);256            }257            else258            {259                assert(x == 0xc);260                assert(r2.ptr == r.ptr);261                assert(r2.ec == std::errc::result_out_of_range);262            }263 264            TEST_DIAGNOSTIC_POP265        }266    }267 268private:269    char buf[150];270};271 272template <typename... T>273struct type_list274{275};276 277template <typename L1, typename L2>278struct type_concat;279 280template <typename... Xs, typename... Ys>281struct type_concat<type_list<Xs...>, type_list<Ys...>>282{283    using type = type_list<Xs..., Ys...>;284};285 286template <typename L1, typename L2>287using concat_t = typename type_concat<L1, L2>::type;288 289template <typename L1, typename L2>290constexpr auto concat(L1, L2) -> concat_t<L1, L2>291{292    return {};293}294 295auto all_signed = type_list<296    char,297    signed char,298    short,299    int,300    long,301    long long302#ifndef TEST_HAS_NO_INT128303    ,304    __int128_t305#endif306    >();307auto all_unsigned = type_list<308    unsigned char,309    unsigned short,310    unsigned int,311    unsigned long,312    unsigned long long313#ifndef TEST_HAS_NO_INT128314    ,315    __uint128_t316#endif317    >();318auto integrals = concat(all_signed, all_unsigned);319 320auto all_floats = type_list< float, double >(); //TODO: Add long double321 322template <template <typename> class Fn, typename... Ts>323TEST_CONSTEXPR_CXX23 void324run(type_list<Ts...>)325{326    int ls[sizeof...(Ts)] = {(Fn<Ts>{}(), 0)...};327    (void)ls;328}329 330#endif // SUPPORT_CHARCONV_TEST_HELPERS_H331