llvm/libcxx/test/std/utilities/charconv/charconv.msvc/test.cpp

// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "test.hpp"

#include <algorithm>
#include <array>
#include <assert.h>
#include <charconv>
#include <chrono>
#include <cmath>
#include <functional>
#include <iterator>
#include <limits>
#include <locale>
#include <optional>
#include <random>
#include <set>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <string_view>
#include <system_error>
#include <type_traits>
#include <utility>
#include <vector>

#include "double_fixed_precision_to_chars_test_cases_1.hpp"
#include "double_fixed_precision_to_chars_test_cases_2.hpp"
#include "double_fixed_precision_to_chars_test_cases_3.hpp"
#include "double_fixed_precision_to_chars_test_cases_4.hpp"
#include "double_from_chars_test_cases.hpp"
#include "double_general_precision_to_chars_test_cases.hpp"
#include "double_hex_precision_to_chars_test_cases.hpp"
#include "double_scientific_precision_to_chars_test_cases_1.hpp"
#include "double_scientific_precision_to_chars_test_cases_2.hpp"
#include "double_scientific_precision_to_chars_test_cases_3.hpp"
#include "double_scientific_precision_to_chars_test_cases_4.hpp"
#include "double_to_chars_test_cases.hpp"
#include "float_fixed_precision_to_chars_test_cases.hpp"
#include "float_from_chars_test_cases.hpp"
#include "float_general_precision_to_chars_test_cases.hpp"
#include "float_hex_precision_to_chars_test_cases.hpp"
#include "float_scientific_precision_to_chars_test_cases.hpp"
#include "float_to_chars_test_cases.hpp"

using namespace std;

void initialize_randomness(mt19937_64& mt64, const int argc, char** const /*argv*/) {
    constexpr std::size_t n = mt19937_64::state_size;
    constexpr std::size_t w = mt19937_64::word_size;
    static_assert(w % 32 == 0);
    constexpr std::size_t k = w / 32;

    vector<std::uint32_t> vec(n * k);

    puts("USAGE:");
    puts("test.exe              : generates seed data from random_device.");

    if (argc == 1) {
        random_device rd;
        generate(vec.begin(), vec.end(), ref(rd));
        puts("Generated seed data.");
    } else {
        puts("ERROR: Too many command-line arguments.");
        abort();
    }

    puts("SEED DATA:");
    for (const auto& elem : vec) {
        printf("%zu ", static_cast<std::size_t>(elem));
    }
    printf("\n");

    seed_seq seq(vec.cbegin(), vec.cend());

    mt64.seed(seq);

    puts("Successfully seeded mt64. First three values:");
    for (int i = 0; i < 3; ++i) {
        // libc++ uses long for 64-bit values.
        printf("0x%016llX\n", static_cast<unsigned long long>(mt64()));
    }
}

static_assert((chars_format::scientific & chars_format::fixed) == chars_format{});
static_assert((chars_format::scientific & chars_format::hex) == chars_format{});
static_assert((chars_format::fixed & chars_format::hex) == chars_format{});
static_assert(chars_format::general == (chars_format::fixed | chars_format::scientific));

template <typename T, typename Optional>
void test_common_to_chars(
    const T value, const Optional opt_arg, const optional<int> opt_precision, const string_view correct) {

    // Important: Test every effective buffer size from 0 through correct.size() and slightly beyond. For the sizes
    // less than correct.size(), this verifies that the too-small buffer is correctly detected, and that we don't
    // attempt to write outside of it, even by a single char. (This exhaustive validation is necessary because the
    // implementation must check whenever it attempts to write. Sometimes we can calculate the total size and perform
    // a single check, but sometimes we need to check when writing each part of the result.) Testing correct.size()
    // verifies that we can succeed without overrunning, and testing slightly larger sizes verifies that we can succeed
    // without attempting to write to extra chars even when they're available. Finally, we also verify that we aren't
    // underrunning the buffer. This is a concern because sometimes we walk backwards when rounding.

    constexpr std::size_t BufferPrefix = 20; // detect buffer underruns (specific value isn't important)

    constexpr std::size_t Space = is_integral_v<T> ? 1 + 64 // worst case: -2^63 in binary
                           : is_same_v<T, float>
                               ? 1 + 151 // worst case: negative min subnormal float, fixed notation
                               : 1 + 1076; // worst case: negative min subnormal double, fixed notation

    constexpr std::size_t BufferSuffix = 30; // detect buffer overruns (specific value isn't important)

    array<char, BufferPrefix + Space + BufferSuffix> buff;

    char* const buff_begin = buff.data();
    char* const first      = buff_begin + BufferPrefix;
    char* const buff_end   = buff_begin + buff.size();

    constexpr std::size_t ExtraChars = 3;
    static_assert(ExtraChars + 10 < BufferSuffix,
        "The specific values aren't important, but there should be plenty of room to detect buffer overruns.");

    for (std::size_t n = 0; n <= correct.size() + ExtraChars; ++n) {
        assert(n <= static_cast<std::size_t>(buff_end - first));
        char* const last = first + n;

        buff.fill('@');
        const auto is_fill_char = [](const char c) { return c == '@'; };

        to_chars_result result{};
        if (opt_precision.has_value()) {
            assert(opt_arg.has_value());

            if constexpr (is_floating_point_v<T>) {
                result = to_chars(first, last, value, opt_arg.value(), opt_precision.value());
            } else {
                abort();
            }
        } else if (opt_arg.has_value()) {
            result = to_chars(first, last, value, opt_arg.value());
        } else {
            result = to_chars(first, last, value);
        }

        if (n < correct.size()) {
            assert(result.ptr == last);
            assert(result.ec == errc::value_too_large);
            assert(all_of(buff_begin, first, is_fill_char));
            // [first, last) is unspecified
            assert(all_of(last, buff_end, is_fill_char));
        } else {
            assert(result.ptr == first + correct.size());
            assert(result.ec == errc{});
            assert(all_of(buff_begin, first, is_fill_char));
            assert(equal(first, result.ptr, correct.begin(), correct.end()));
            assert(all_of(result.ptr, buff_end, is_fill_char));
        }
    }
}

template <typename T>
void test_integer_to_chars(const T value, const optional<int> opt_base, const string_view correct) {

    test_common_to_chars(value, opt_base, nullopt, correct);

    { // Also test successful from_chars() scenarios.
        const char* const correct_first = correct.data();
        const char* const correct_last  = correct_first + correct.size();

        T dest = 0;

        const from_chars_result from_res =
            (opt_base.has_value() ? from_chars(correct_first, correct_last, dest, opt_base.value())
                                  : from_chars(correct_first, correct_last, dest));

        assert(from_res.ptr == correct_last);
        assert(from_res.ec == errc{});
        assert(dest == value);
    }
}

// https://www.wolframalpha.com : Table[BaseForm[n * 2 - 1, n], {n, 2, 36}]
constexpr const char* output_max_digit[] = {"skip0", "skip1", "11", "12", "13", "14", "15", "16", "17", "18", "19",
    "1a", "1b", "1c", "1d", "1e", "1f", "1g", "1h", "1i", "1j", "1k", "1l", "1m", "1n", "1o", "1p", "1q", "1r", "1s",
    "1t", "1u", "1v", "1w", "1x", "1y", "1z"};

// https://www.wolframalpha.com : Table[BaseForm[k, n], {k, {MEOW, MEOW, MEOW}}, {n, 2, 36}]
constexpr std::uint64_t stress_chunks_positive                          = 12000000345000678900ULL;
constexpr pair<std::uint64_t, array<const char*, 37>> output_positive[] = {
    {123U, {{"skip0", "skip1", "1111011", "11120", "1323", "443", "323", "234", "173", "146", "123", "102", "a3", "96",
               "8b", "83", "7b", "74", "6f", "69", "63", "5i", "5d", "58", "53", "4n", "4j", "4f", "4b", "47", "43",
               "3u", "3r", "3o", "3l", "3i", "3f"}}},
    {std::uint64_t{INT8_MAX}, {{"skip0", "skip1", "1111111", "11201", "1333", "1002", "331", "241", "177", "151", "127",
                             "106", "a7", "9a", "91", "87", "7f", "78", "71", "6d", "67", "61", "5h", "5c", "57", "52",
                             "4n", "4j", "4f", "4b", "47", "43", "3v", "3s", "3p", "3m", "3j"}}},
    {161U, {{"skip0", "skip1", "10100001", "12222", "2201", "1121", "425", "320", "241", "188", "161", "137", "115",
               "c5", "b7", "ab", "a1", "98", "8h", "89", "81", "7e", "77", "70", "6h", "6b", "65", "5q", "5l", "5g",
               "5b", "56", "51", "4t", "4p", "4l", "4h"}}},
    {UINT8_MAX, {{"skip0", "skip1", "11111111", "100110", "3333", "2010", "1103", "513", "377", "313", "255", "212",
                    "193", "168", "143", "120", "ff", "f0", "e3", "d8", "cf", "c3", "bd", "b2", "af", "a5", "9l", "9c",
                    "93", "8n", "8f", "87", "7v", "7o", "7h", "7a", "73"}}},
    {1729U, {{"skip0", "skip1", "11011000001", "2101001", "123001", "23404", "12001", "5020", "3301", "2331", "1729",
                "1332", "1001", "a30", "8b7", "7a4", "6c1", "5gc", "561", "4f0", "469", "3j7", "3cd", "364", "301",
                "2j4", "2ed", "2a1", "25l", "21i", "1rj", "1oo", "1m1", "1jd", "1gt", "1ee", "1c1"}}},
    {std::uint64_t{INT16_MAX}, {{"skip0", "skip1", "111111111111111", "1122221121", "13333333", "2022032", "411411",
                              "164350", "77777", "48847", "32767", "22689", "16b67", "11bb7", "bd27", "9a97", "7fff",
                              "6b68", "5b27", "4eeb", "41i7", "3b67", "31f9", "2flf", "28l7", "22ah", "1mc7", "1hpg",
                              "1dm7", "19rq", "16c7", "1330", "vvv", "u2v", "sbp", "qq7", "pa7"}}},
    {57494U, {{"skip0", "skip1", "1110000010010110", "2220212102", "32002112", "3314434", "1122102", "326423", "160226",
                 "86772", "57494", "3a218", "29332", "20228", "16d4a", "1207e", "e096", "bbg0", "9f82", "8750", "73ee",
                 "647h", "58h8", "4gfh", "43je", "3goj", "3718", "2onb", "2h9a", "2aag", "23qe", "1spk", "1o4m", "1jq8",
                 "1fp0", "1bwo", "18d2"}}},
    {UINT16_MAX, {{"skip0", "skip1", "1111111111111111", "10022220020", "33333333", "4044120", "1223223", "362031",
                     "177777", "108806", "65535", "45268", "31b13", "23aa2", "19c51", "14640", "ffff", "d5d0", "b44f",
                     "9aa4", "83gf", "71cf", "638j", "58k8", "4hif", "44la", "3iof", "38o6", "2rgf", "2jqo", "2cof",
                     "2661", "1vvv", "1r5u", "1mnh", "1ihf", "1ekf"}}},
    {71125478U, {{"skip0", "skip1", "100001111010100100111100110", "11221211112210222", "10033110213212",
                    "121202003403", "11020244342", "1522361624", "417244746", "157745728", "71125478", "3716a696",
                    "1b9a06b2", "11973ba8", "9636514", "639e338", "43d49e6", "2g19gfb", "21b9d18", "19dec94", "124addi",
                    "h8f25b", "dhdfa6", "b13hg2", "8m91he", "7720j3", "5pgj58", "4pmelq", "43k17i", "3dg8ek", "2ro898",
                    "2f0et8", "23qif6", "1qw5lh", "1j7l7s", "1cdvli", "16cgrq"}}},
    {std::uint64_t{INT32_MAX},
        {{"skip0", "skip1", "1111111111111111111111111111111", "12112122212110202101", "1333333333333333",
            "13344223434042", "553032005531", "104134211161", "17777777777", "5478773671", "2147483647", "a02220281",
            "4bb2308a7", "282ba4aaa", "1652ca931", "c87e66b7", "7fffffff", "53g7f548", "3928g3h1", "27c57h32",
            "1db1f927", "140h2d91", "ikf5bf1", "ebelf95", "b5gge57", "8jmdnkm", "6oj8ion", "5ehncka", "4clm98f",
            "3hk7987", "2sb6cs7", "2d09uc1", "1vvvvvv", "1lsqtl1", "1d8xqrp", "15v22um", "zik0zj"}}},
    {3522553278ULL,
        {{"skip0", "skip1", "11010001111101011110010110111110", "100002111022020200020", "3101331132112332",
            "24203233201103", "1341312313010", "153202131426", "32175362676", "10074266606", "3522553278", "1548431462",
            "823842766", "441a34c6a", "255b8d486", "1593b4753", "d1f5e5be", "89ffb3b6", "5da3e606", "3hgbfb5i",
            "2f0fj33i", "1k1ac536", "191b46e2", "10i6fmk8", "ia967l6", "eahia63", "baca9ga", "92d86i6", "78iq4i6",
            "5qlc1dc", "4osos2i", "3u1862s", "38vbpdu", "2o0a7ro", "29hx9e6", "1w2dnod", "1m98ji6"}}},
    {UINT32_MAX,
        {{"skip0", "skip1", "11111111111111111111111111111111", "102002022201221111210", "3333333333333333",
            "32244002423140", "1550104015503", "211301422353", "37777777777", "12068657453", "4294967295", "1904440553",
            "9ba461593", "535a79888", "2ca5b7463", "1a20dcd80", "ffffffff", "a7ffda90", "704he7g3", "4f5aff65",
            "3723ai4f", "281d55i3", "1fj8b183", "1606k7ib", "mb994af", "hek2mgk", "dnchbnl", "b28jpdl", "8pfgih3",
            "76beigf", "5qmcpqf", "4q0jto3", "3vvvvvv", "3aokq93", "2qhxjlh", "2br45qa", "1z141z3"}}},
    {545890816626160ULL,
        {{"skip0", "skip1", "1111100000111110000011100001101100000110111110000", "2122120211122121121021010202111",
            "1330013300130031200313300", "1033022333343024014120", "5213002440142255104", "222661211220253465",
            "17407603415406760", "2576748547233674", "545890816626160", "148a34aa4706535", "51285369b87494",
            "1a57a38b045a95", "98b3383b9766c", "4319d1601875a", "1f07c1c360df0", "ffd471f34f13", "88g09ff9dh84",
            "4d0d5e232c53", "2d63h403i580", "1bf5h8185hdj", "kc3g550fkcg", "d41id5k9984", "8ef5n0him4g", "5i2dijfe1la",
            "3me22fm5fhi", "2hfmhgg73kd", "1ngpfabr53c", "18i7220bh11", "rm0lcjngpa", "kk1elesni1", "fgfge3c3fg",
            "bp4q5l6bjg", "8xna46jp0k", "6wejomvji5", "5di2s1qhv4"}}},
    {std::uint64_t{INT64_MAX},
        {{"skip0", "skip1", "111111111111111111111111111111111111111111111111111111111111111",
            "2021110011022210012102010021220101220221", "13333333333333333333333333333333",
            "1104332401304422434310311212", "1540241003031030222122211", "22341010611245052052300",
            "777777777777777777777", "67404283172107811827", "9223372036854775807", "1728002635214590697",
            "41a792678515120367", "10b269549075433c37", "4340724c6c71dc7a7", "160e2ad3246366807", "7fffffffffffffff",
            "33d3d8307b214008", "16agh595df825fa7", "ba643dci0ffeehh", "5cbfjia3fh26ja7", "2heiciiie82dh97",
            "1adaibb21dckfa7", "i6k448cf4192c2", "acd772jnc9l0l7", "64ie1focnn5g77", "3igoecjbmca687", "27c48l5b37oaop",
            "1bk39f3ah3dmq7", "q1se8f0m04isb", "hajppbc1fc207", "bm03i95hia437", "7vvvvvvvvvvvv", "5hg4ck9jd4u37",
            "3tdtk1v8j6tpp", "2pijmikexrxp7", "1y2p0ij32e8e7"}}},
    {stress_chunks_positive,
        {{"skip0", "skip1", "1010011010001000100100001011110000101100010101001001010111110100",
            "2221221122020020011022001202200200202200", "22122020210023300230111021113310",
            "1301130403021123030133211100", "2311004450342244200504500", "30325064311430214266301",
            "1232104413605425112764", "87848206138052620680", "12000000345000678900", "2181782a1686924456a",
            "54aa47a9058877b130", "150593a5b002c87b16", "571cad2b93c7760a8", "1c60d2676d4e53e00", "a68890bc2c5495f4",
            "43499224707a4f4g", "1e052gdga1d26f40", "f06dh4g564c8a91", "769df0d9ace4h50", "3ee7bcj1ajghi4f",
            "1k9agc4gfl0l43a", "10id7dakdlcjd22", "dge08fe0l5hl7c", "8184326d31ib60", "4ljbglf3cpim76",
            "2pph66481kiiki", "1niph2ao132e58", "14qgbgk3c3iffg", "mhc35an1bhb00", "f78o8ur705ln5", "ad24gngm595fk",
            "76e1n5i5v0ivl", "50wu8jsnks82g", "3ja41smfvqb1f", "2j64t3qgq0ut0"}}},
    {14454900944617508688ULL,
        {{"skip0", "skip1", "1100100010011010000111111101001011100011011000101000111101010000",
            "10120022020112011211121221212101012220210", "30202122013331023203120220331100",
            "1432224030234034034040234223", "3014532424232535441404120", "34610451042001242144165",
            "1442320775134330507520", "116266464747855335823", "14454900944617508688", "266642a9a9471339935",
            "662251403263939640", "1895280092bc310481", "68cb9c8292557406c", "23023deab20002893", "c89a1fd2e3628f50",
            "50e7147a7db8ef84", "22a34a05086f78ec", "i1dgef04357g7i1", "8g90b882jcj8be8", "49c1kk35i0k24ic",
            "272a16i54ebkacg", "15fdih7l3m7k8md", "gbj7303eg9nge0", "9hckfdkj3kkdmd", "5lc7hifdkl4nne",
            "3f86e4mgpna5ol", "266pj428na273c", "1bomgjbnlg4m3f", "r5tf1f7f009ji", "iarsig29iqhhm", "ch6gvqbhm53qg",
            "8lwtvcdj6rlqr", "61w23lajggp44", "49p1f3dsqqcdx", "31tkqqkxypopc"}}},
    {UINT64_MAX,
        {{"skip0", "skip1", "1111111111111111111111111111111111111111111111111111111111111111",
            "11112220022122120101211020120210210211220", "33333333333333333333333333333333",
            "2214220303114400424121122430", "3520522010102100444244423", "45012021522523134134601",
            "1777777777777777777777", "145808576354216723756", "18446744073709551615", "335500516a429071284",
            "839365134a2a240713", "219505a9511a867b72", "8681049adb03db171", "2c1d56b648c6cd110", "ffffffffffffffff",
            "67979g60f5428010", "2d3fgb0b9cg4bd2f", "141c8786h1ccaagg", "b53bjh07be4dj0f", "5e8g4ggg7g56dif",
            "2l4lf104353j8kf", "1ddh88h2782i515", "l12ee5fn0ji1if", "c9c336o0mlb7ef", "7b7n2pcniokcgf",
            "4eo8hfam6fllmo", "2nc6j26l66rhof", "1n3rsh11f098rn", "14l9lkmo30o40f", "nd075ib45k86f", "fvvvvvvvvvvvv",
            "b1w8p7j5q9r6f", "7orp63sh4dphh", "5g24a25twkwff", "3w5e11264sgsf"}}},
};

// https://www.wolframalpha.com : Table[BaseForm[k, n], {k, {MEOW, MEOW, MEOW}}, {n, 2, 36}]
constexpr std::int64_t stress_chunks_negative                          = -9000876000000054321LL;
constexpr pair<std::int64_t, array<const char*, 37>> output_negative[] = {
    {-85, {{"skip0", "skip1", "-1010101", "-10011", "-1111", "-320", "-221", "-151", "-125", "-104", "-85", "-78",
              "-71", "-67", "-61", "-5a", "-55", "-50", "-4d", "-49", "-45", "-41", "-3j", "-3g", "-3d", "-3a", "-37",
              "-34", "-31", "-2r", "-2p", "-2n", "-2l", "-2j", "-2h", "-2f", "-2d"}}},
    {INT8_MIN, {{"skip0", "skip1", "-10000000", "-11202", "-2000", "-1003", "-332", "-242", "-200", "-152", "-128",
                   "-107", "-a8", "-9b", "-92", "-88", "-80", "-79", "-72", "-6e", "-68", "-62", "-5i", "-5d", "-58",
                   "-53", "-4o", "-4k", "-4g", "-4c", "-48", "-44", "-40", "-3t", "-3q", "-3n", "-3k"}}},
    {-1591, {{"skip0", "skip1", "-11000110111", "-2011221", "-120313", "-22331", "-11211", "-4432", "-3067", "-2157",
                "-1591", "-1217", "-b07", "-955", "-819", "-711", "-637", "-58a", "-4g7", "-47e", "-3jb", "-3cg",
                "-367", "-304", "-2i7", "-2dg", "-295", "-24p", "-20n", "-1pp", "-1n1", "-1ka", "-1hn", "-1f7", "-1cr",
                "-1ag", "-187"}}},
    {INT16_MIN, {{"skip0", "skip1", "-1000000000000000", "-1122221122", "-20000000", "-2022033", "-411412", "-164351",
                    "-100000", "-48848", "-32768", "-2268a", "-16b68", "-11bb8", "-bd28", "-9a98", "-8000", "-6b69",
                    "-5b28", "-4eec", "-41i8", "-3b68", "-31fa", "-2flg", "-28l8", "-22ai", "-1mc8", "-1hph", "-1dm8",
                    "-19rr", "-16c8", "-1331", "-1000", "-u2w", "-sbq", "-qq8", "-pa8"}}},
    {-66748412,
        {{"skip0", "skip1", "-11111110100111111111111100", "-11122121011121102", "-3332213333330", "-114041422122",
            "-10342352232", "-1440231533", "-376477774", "-148534542", "-66748412", "-34750085", "-1a42b678",
            "-10aa0803", "-8c1731a", "-5cd7492", "-3fa7ffc", "-2d03163", "-1h5f3b2", "-17i39c6", "-10h3b0c", "-g749jh",
            "-ckkdkg", "-a8c0ak", "-894afk", "-6klmbc", "-5g1i6g", "-4hg4gb", "-3ogi7o", "-37anqb", "-2mc4r2",
            "-2a8h7i", "-1vkvvs", "-1n9ca5", "-1fw8sk", "-19gshh", "-13qnek"}}},
    {INT32_MIN, {{"skip0", "skip1", "-10000000000000000000000000000000", "-12112122212110202102", "-2000000000000000",
                    "-13344223434043", "-553032005532", "-104134211162", "-20000000000", "-5478773672", "-2147483648",
                    "-a02220282", "-4bb2308a8", "-282ba4aab", "-1652ca932", "-c87e66b8", "-80000000", "-53g7f549",
                    "-3928g3h2", "-27c57h33", "-1db1f928", "-140h2d92", "-ikf5bf2", "-ebelf96", "-b5gge58", "-8jmdnkn",
                    "-6oj8ioo", "-5ehnckb", "-4clm98g", "-3hk7988", "-2sb6cs8", "-2d09uc2", "-2000000", "-1lsqtl2",
                    "-1d8xqrq", "-15v22un", "-zik0zk"}}},
    {-297139747082649553LL,
        {{"skip0", "skip1", "-10000011111101001110000011010010001100000101011111111010001",
            "-1222110012002112101210012211022102101", "-100133221300122101200223333101", "-4443033200104011124241203",
            "-21313431255203203120401", "-350320603201030412545", "-20375160322140537721", "-1873162471705738371",
            "-297139747082649553", "-65150976074a24025", "-173522497b5373101", "-5a60a99bc3b71654", "-1ca51a06cc38ba25",
            "-a2a25babe62241d", "-41fa7069182bfd1", "-1d00134fba1769g", "-e4f799fc5f7e81", "-714ebbh8388188",
            "-3cahb17836b3hd", "-1j8659jf5hbg3j", "-112bbb2jege5c5", "-dcjfmk2kjb4cc", "-836bm4klbgl61",
            "-4ofia1416ee73", "-32ommgjef1l2h", "-1qc52eal5m8ba", "-17n53r05a4r15", "-oa88m2qiqjik", "-gn67qoat5r8d",
            "-blgd6n5s90al", "-87t70q8o5fuh", "-5t09hwaqu9qg", "-47vssihaoa4x", "-32p24fbjye7x", "-299r8zck3841"}}},
    {stress_chunks_negative,
        {{"skip0", "skip1", "-111110011101001100010010000100010000111010101111001010000110001",
            "-2012222010200021010000112111002001111200", "-13303221202100202013111321100301",
            "-1101001100304341000003214241", "-1522150121302454031001413", "-22054250360123016161454",
            "-763514220420725712061", "-65863607100474061450", "-9000876000000054321", "-1689813530958833498",
            "-408258185a67069269", "-106b01597a47ba2948", "-41c02922bc776d49b", "-1584cd10979dc84b6",
            "-7ce9890887579431", "-327cf6cbc67023c3", "-1604b5f6a0de8129", "-b50d3ef02f124a4", "-59h9bfif0006fg1",
            "-2g5d8ekh05d2dfi", "-19i418c38g1chfj", "-hjgf7d0k0gla9a", "-a6b21ncehfa3f9", "-61060fnl003bml",
            "-3g88bakondgf8l", "-25q3i730ed21di", "-1al84glo518iip", "-pcli8ig7pjhbo", "-gs31q8id2jnkl",
            "-bd7kaglgdrbgk", "-7pqc9123lf51h", "-5d2sd1r5ms7su", "-3q833s8kdrun3", "-2n7vmqigfueqb",
            "-1wdu892toj0a9"}}},
    {INT64_MIN, {{"skip0", "skip1", "-1000000000000000000000000000000000000000000000000000000000000000",
                    "-2021110011022210012102010021220101220222", "-20000000000000000000000000000000",
                    "-1104332401304422434310311213", "-1540241003031030222122212", "-22341010611245052052301",
                    "-1000000000000000000000", "-67404283172107811828", "-9223372036854775808", "-1728002635214590698",
                    "-41a792678515120368", "-10b269549075433c38", "-4340724c6c71dc7a8", "-160e2ad3246366808",
                    "-8000000000000000", "-33d3d8307b214009", "-16agh595df825fa8", "-ba643dci0ffeehi",
                    "-5cbfjia3fh26ja8", "-2heiciiie82dh98", "-1adaibb21dckfa8", "-i6k448cf4192c3", "-acd772jnc9l0l8",
                    "-64ie1focnn5g78", "-3igoecjbmca688", "-27c48l5b37oaoq", "-1bk39f3ah3dmq8", "-q1se8f0m04isc",
                    "-hajppbc1fc208", "-bm03i95hia438", "-8000000000000", "-5hg4ck9jd4u38", "-3tdtk1v8j6tpq",
                    "-2pijmikexrxp8", "-1y2p0ij32e8e8"}}},
};

template <typename T>
void test_integer_to_chars() {
    for (int base = 2; base <= 36; ++base) {
        test_integer_to_chars(static_cast<T>(0), base, "0");
        test_integer_to_chars(static_cast<T>(1), base, "1");

        // tests [3, 71]
        test_integer_to_chars(static_cast<T>(base * 2 - 1), base, output_max_digit[base]);

        for (const auto& p : output_positive) {
            if (p.first <= static_cast<std::uint64_t>(numeric_limits<T>::max())) {
                test_integer_to_chars(static_cast<T>(p.first), base, p.second[static_cast<std::size_t>(base)]);
            }
        }

        if constexpr (is_signed_v<T>) {
            test_integer_to_chars(static_cast<T>(-1), base, "-1");

            for (const auto& p : output_negative) {
                if (p.first >= static_cast<std::int64_t>(numeric_limits<T>::min())) {
                    test_integer_to_chars(static_cast<T>(p.first), base, p.second[static_cast<std::size_t>(base)]);
                }
            }
        }
    }

    test_integer_to_chars(static_cast<T>(42), nullopt, "42");
}

enum class TestFromCharsMode { Normal, SignalingNaN };

template <typename T, typename BaseOrFmt>
void test_from_chars(const string_view input, const BaseOrFmt base_or_fmt, const std::size_t correct_idx,
    const errc correct_ec, const optional<T> opt_correct = nullopt,
    const TestFromCharsMode mode = TestFromCharsMode::Normal) {

    if constexpr (is_integral_v<T>) {
        assert(mode == TestFromCharsMode::Normal);
    }

    constexpr T unmodified = 111;

    T dest = unmodified;

    const from_chars_result result = from_chars(input.data(), input.data() + input.size(), dest, base_or_fmt);

    assert(result.ptr == input.data() + correct_idx);
    assert(result.ec == correct_ec);

    if (correct_ec == errc{} || (is_floating_point_v<T> && correct_ec == errc::result_out_of_range)) {
        if constexpr (is_floating_point_v<T>) {
            if (mode == TestFromCharsMode::Normal) {
                using Uint = conditional_t<is_same_v<T, float>, std::uint32_t, std::uint64_t>;
                assert(opt_correct.has_value());
                assert(_Bit_cast<Uint>(dest) == _Bit_cast<Uint>(opt_correct.value()));
            } else {
                assert(mode == TestFromCharsMode::SignalingNaN);
                assert(!opt_correct.has_value());
                assert(isnan(dest));
            }
        } else {
            assert(opt_correct.has_value());
            assert(dest == opt_correct.value());
        }
    } else {
        assert(!opt_correct.has_value());
        assert(dest == unmodified);
    }
}

constexpr errc inv_arg = errc::invalid_argument;
constexpr errc out_ran = errc::result_out_of_range;

template <typename T>
void test_integer_from_chars() {
    for (int base = 2; base <= 36; ++base) {
        test_from_chars<T>("", base, 0, inv_arg); // no characters
        test_from_chars<T>("@1", base, 0, inv_arg); // '@' is bogus
        test_from_chars<T>(".1", base, 0, inv_arg); // '.' is bogus, for integers
        test_from_chars<T>("+1", base, 0, inv_arg); // '+' is bogus, N4713 23.20.3 [charconv.from.chars]/3
                                                    // "a minus sign is the only sign that may appear"
        test_from_chars<T>(" 1", base, 0, inv_arg); // ' ' is bogus, no whitespace in subject sequence

        if constexpr (is_unsigned_v<T>) { // N4713 23.20.3 [charconv.from.chars]/3
            test_from_chars<T>("-1", base, 0, inv_arg); // "and only if value has a signed type"
        }

        // N4713 23.20.3 [charconv.from.chars]/1 "[ Note: If the pattern allows for an optional sign,
        // but the string has no digit characters following the sign, no characters match the pattern. -end note ]"
        test_from_chars<T>("-", base, 0, inv_arg); // '-' followed by no characters
        test_from_chars<T>("-@1", base, 0, inv_arg); // '-' followed by bogus '@'
        test_from_chars<T>("-.1", base, 0, inv_arg); // '-' followed by bogus '.'
        test_from_chars<T>("-+1", base, 0, inv_arg); // '-' followed by bogus '+'
        test_from_chars<T>("- 1", base, 0, inv_arg); // '-' followed by bogus ' '
        test_from_chars<T>("--1", base, 0, inv_arg); // '-' can't be repeated

        vector<char> bogus_digits;

        if (base < 10) {
            bogus_digits = {static_cast<char>('0' + base), 'A', 'a'};
        } else {
            // '[' and '{' are bogus for base 36
            bogus_digits = {static_cast<char>('A' + (base - 10)), static_cast<char>('a' + (base - 10))};
        }

        for (const auto& bogus : bogus_digits) {
            test_from_chars<T>(bogus + "1"s, base, 0, inv_arg); // bogus digit (for this base)
            test_from_chars<T>("-"s + bogus + "1"s, base, 0, inv_arg); // '-' followed by bogus digit
        }

        // Test leading zeroes.
        test_from_chars<T>(string(100, '0'), base, 100, errc{}, static_cast<T>(0));
        test_from_chars<T>(string(100, '0') + "11"s, base, 102, errc{}, static_cast<T>(base + 1));

        // Test negative zero and negative leading zeroes.
        if constexpr (is_signed_v<T>) {
            test_from_chars<T>("-0", base, 2, errc{}, static_cast<T>(0));
            test_from_chars<T>("-"s + string(100, '0'), base, 101, errc{}, static_cast<T>(0));
            test_from_chars<T>("-"s + string(100, '0') + "11"s, base, 103, errc{}, static_cast<T>(-base - 1));
        }

        // N4713 23.20.3 [charconv.from.chars]/1 "The member ptr of the return value points to the
        // first character not matching the pattern, or has the value last if all characters match."
        test_from_chars<T>("11", base, 2, errc{}, static_cast<T>(base + 1));
        test_from_chars<T>("11@@@", base, 2, errc{}, static_cast<T>(base + 1));

        // When overflowing, we need to keep consuming valid digits, in order to return ptr correctly.
        test_from_chars<T>(string(100, '1'), base, 100, out_ran);
        test_from_chars<T>(string(100, '1') + "@@@"s, base, 100, out_ran);

        if constexpr (is_signed_v<T>) {
            test_from_chars<T>("-"s + string(100, '1'), base, 101, out_ran);
            test_from_chars<T>("-"s + string(100, '1') + "@@@"s, base, 101, out_ran);
        }
    }

    // N4713 23.20.3 [charconv.from.chars]/3 "The pattern is the expected form of the subject sequence
    // in the "C" locale for the given nonzero base, as described for strtol"
    // C11 7.22.1.4/3 "The letters from a (or A) through z (or Z) are ascribed the values 10 through 35"
    for (int i = 0; i < 26; ++i) {
        test_from_chars<T>(string(1, static_cast<char>('A' + i)), 36, 1, errc{}, static_cast<T>(10 + i));
        test_from_chars<T>(string(1, static_cast<char>('a' + i)), 36, 1, errc{}, static_cast<T>(10 + i));
    }

    // N4713 23.20.3 [charconv.from.chars]/3 "no "0x" or "0X" prefix shall appear if the value of base is 16"
    test_from_chars<T>("0x1729", 16, 1, errc{}, static_cast<T>(0)); // reads '0', stops at 'x'
    test_from_chars<T>("0X1729", 16, 1, errc{}, static_cast<T>(0)); // reads '0', stops at 'X'

    if constexpr (is_signed_v<T>) {
        test_from_chars<T>("-0x1729", 16, 2, errc{}, static_cast<T>(0)); // reads "-0", stops at 'x'
        test_from_chars<T>("-0X1729", 16, 2, errc{}, static_cast<T>(0)); // reads "-0", stops at 'X'
    }
}

template <typename T>
void test_integer() {
    test_integer_to_chars<T>();
    test_integer_from_chars<T>();
}

void all_integer_tests() {
    test_integer<char>();
    test_integer<signed char>();
    test_integer<unsigned char>();
    test_integer<short>();
    test_integer<unsigned short>();
    test_integer<int>();
    test_integer<unsigned int>();
    test_integer<long>();
    test_integer<unsigned long>();
    test_integer<long long>();
    test_integer<unsigned long long>();

    // Test overflow scenarios.
    test_from_chars<unsigned int>("4294967289", 10, 10, errc{}, 4294967289U); // not risky
    test_from_chars<unsigned int>("4294967294", 10, 10, errc{}, 4294967294U); // risky with good digit
    test_from_chars<unsigned int>("4294967295", 10, 10, errc{}, 4294967295U); // risky with max digit
    test_from_chars<unsigned int>("4294967296", 10, 10, out_ran); // risky with bad digit
    test_from_chars<unsigned int>("4294967300", 10, 10, out_ran); // beyond risky

    test_from_chars<int>("2147483639", 10, 10, errc{}, 2147483639); // not risky
    test_from_chars<int>("2147483646", 10, 10, errc{}, 2147483646); // risky with good digit
    test_from_chars<int>("2147483647", 10, 10, errc{}, 2147483647); // risky with max digit
    test_from_chars<int>("2147483648", 10, 10, out_ran); // risky with bad digit
    test_from_chars<int>("2147483650", 10, 10, out_ran); // beyond risky

    test_from_chars<int>("-2147483639", 10, 11, errc{}, -2147483639); // not risky
    test_from_chars<int>("-2147483647", 10, 11, errc{}, -2147483647); // risky with good digit
    test_from_chars<int>("-2147483648", 10, 11, errc{}, -2147483647 - 1); // risky with max digit
    test_from_chars<int>("-2147483649", 10, 11, out_ran); // risky with bad digit
    test_from_chars<int>("-2147483650", 10, 11, out_ran); // beyond risky
}

void assert_message_bits(const bool b, const char* const msg, const std::uint32_t bits) {
    if (!b) {
        fprintf(stderr, "%s failed for 0x%08zX\n", msg, static_cast<std::size_t>(bits));
        fprintf(stderr, "This is a randomized test.\n");
        fprintf(stderr, "DO NOT IGNORE/RERUN THIS FAILURE.\n");
        fprintf(stderr, "You must report it to the STL maintainers.\n");
        abort();
    }
}

void assert_message_bits(const bool b, const char* const msg, const std::uint64_t bits) {
    if (!b) {
        // libc++ uses long for 64-bit values.
        fprintf(stderr, "%s failed for 0x%016llX\n", msg, static_cast<unsigned long long>(bits));
        fprintf(stderr, "This is a randomized test.\n");
        fprintf(stderr, "DO NOT IGNORE/RERUN THIS FAILURE.\n");
        fprintf(stderr, "You must report it to the STL maintainers.\n");
        abort();
    }
}

constexpr std::uint32_t FractionBits = 10; // Tunable for test coverage vs. performance.
static_assert(FractionBits >= 1, "Must test at least 1 fraction bit.");
static_assert(FractionBits <= 23, "There are only 23 fraction bits in a float.");

constexpr std::uint32_t Fractions = 1U << FractionBits;
constexpr std::uint32_t Mask32    = ~((1U << FractionBits) - 1U);
constexpr std::uint64_t Mask64    = ~((1ULL << FractionBits) - 1ULL);

constexpr std::uint32_t PrefixesToTest = 100; // Tunable for test coverage vs. performance.
static_assert(PrefixesToTest >= 1, "Must test at least 1 prefix.");

constexpr std::uint32_t PrefixLimit = 2 // sign bit
                               * 255 // non-INF/NAN exponents for float
                               * (1U << (23 - FractionBits)); // fraction bits in prefix
static_assert(PrefixesToTest <= PrefixLimit, "Too many prefixes.");

template <bool IsDouble>
void test_floating_prefix(const conditional_t<IsDouble, std::uint64_t, std::uint32_t> prefix) {

    using UIntType     = conditional_t<IsDouble, std::uint64_t, std::uint32_t>;
    using FloatingType = conditional_t<IsDouble, double, float>;

    // "-1.2345678901234567e-100" or "-1.23456789e-10"
    constexpr std::size_t buffer_size = IsDouble ? 24 : 15;
    char buffer[buffer_size];
// TODO Enable once std::from_chars has floating point support.
#if 0
    FloatingType val;
#endif

    // Exact sizes are difficult to prove for fixed notation.
    // This must be at least (IsDouble ? 327 : 48), and I suspect that that's exact.
    // Here's a loose upper bound:
    // 1 character for a negative sign
    // + 325 (for double; 46 for float) characters in the "0.000~~~000" prefix of the min subnormal
    // + 17 (for double; 9 for float) characters for round-trip digits
    constexpr std::size_t fixed_buffer_size = IsDouble ? 1 + 325 + 17 : 1 + 46 + 9;
    char fixed_buffer[fixed_buffer_size];

    // worst case: negative sign + max normal + null terminator
    constexpr std::size_t stdio_buffer_size = 1 + (IsDouble ? 309 : 39) + 1;
    char stdio_buffer[stdio_buffer_size];

    for (std::uint32_t frac = 0; frac < Fractions; ++frac) {
        const UIntType bits      = prefix + frac;
        const FloatingType input = _Bit_cast<FloatingType>(bits);

        {
            const auto to_result = to_chars(buffer, end(buffer), input, chars_format::scientific);
            assert_message_bits(to_result.ec == errc{}, "to_result.ec", bits);
// TODO Enable once std::from_chars has floating point support.
#if 0
            const char* const last = to_result.ptr;

            const auto from_result = from_chars(buffer, last, val);

            assert_message_bits(from_result.ptr == last, "from_result.ptr", bits);
            assert_message_bits(from_result.ec == errc{}, "from_result.ec", bits);
            assert_message_bits(_Bit_cast<UIntType>(val) == bits, "round-trip", bits);
#endif
        }

        {
            // Also verify that to_chars() and sprintf_s() emit the same output for integers in fixed notation.
            const auto fixed_result = to_chars(fixed_buffer, end(fixed_buffer), input, chars_format::fixed);
            assert_message_bits(fixed_result.ec == errc{}, "fixed_result.ec", bits);
            const string_view fixed_sv(fixed_buffer, static_cast<std::size_t>(fixed_result.ptr - fixed_buffer));

            if (find(fixed_sv.begin(), fixed_sv.end(), '.') == fixed_sv.end()) {
                const int stdio_ret = sprintf_s(stdio_buffer, size(stdio_buffer), "%.0f", input);
                assert_message_bits(stdio_ret != -1, "stdio_ret", bits);
                const string_view stdio_sv(stdio_buffer);
                assert_message_bits(fixed_sv == stdio_sv, "fixed_sv", bits);
            }
        }
    }
}

template <bool IsDouble>
void test_floating_hex_prefix(const conditional_t<IsDouble, std::uint64_t, std::uint32_t> prefix) {

    using UIntType     = conditional_t<IsDouble, std::uint64_t, std::uint32_t>;
    using FloatingType = conditional_t<IsDouble, double, float>;

    // The precision is the number of hexits after the decimal point.
    // These hexits correspond to the explicitly stored fraction bits.
    // double explicitly stores 52 fraction bits. 52 / 4 == 13, so we need 13 hexits.
    // float explicitly stores 23 fraction bits. 23 / 4 == 5.75, so we need 6 hexits.

    // "-1.fffffffffffffp+1023" or "-1.fffffep+127"
    constexpr std::size_t buffer_size = IsDouble ? 22 : 14;
    char buffer[buffer_size];
// TODO Enable once std::from_chars has floating point support.
#if 0
    FloatingType val;
#endif

    for (std::uint32_t frac = 0; frac < Fractions; ++frac) {
        const UIntType bits      = prefix + frac;
        const FloatingType input = _Bit_cast<FloatingType>(bits);

        const auto to_result = to_chars(buffer, end(buffer), input, chars_format::hex);
        assert_message_bits(to_result.ec == errc{}, "(hex) to_result.ec", bits);
// TODO Enable once std::from_chars has floating point support.
#if 0
        const char* const last = to_result.ptr;

        const auto from_result = from_chars(buffer, last, val, chars_format::hex);

        assert_message_bits(from_result.ptr == last, "(hex) from_result.ptr", bits);
        assert_message_bits(from_result.ec == errc{}, "(hex) from_result.ec", bits);
        assert_message_bits(_Bit_cast<UIntType>(val) == bits, "(hex) round-trip", bits);
#endif
    }
}

template <bool IsDouble>
void test_floating_precision_prefix(const conditional_t<IsDouble, std::uint64_t, std::uint32_t> prefix) {

    using UIntType     = conditional_t<IsDouble, std::uint64_t, std::uint32_t>;
    using FloatingType = conditional_t<IsDouble, double, float>;

    // Precision for min subnormal in fixed notation. (More than enough for scientific notation.)
    constexpr int precision = IsDouble ? 1074 : 149;

    // Number of digits for max normal in fixed notation.
    constexpr int max_integer_length = IsDouble ? 309 : 39;

    // Size for fixed notation. (More than enough for scientific notation.)
    constexpr std::size_t charconv_buffer_size = 1 // negative sign
                                          + max_integer_length // integer digits
                                          + 1 // decimal point
                                          + precision; // fractional digits
    char charconv_buffer[charconv_buffer_size];

    constexpr std::size_t stdio_buffer_size = charconv_buffer_size + 1; // null terminator
    char stdio_buffer[stdio_buffer_size];

    // 1 character for a negative sign
    // + worst cases: 0x1.fffffffffffffp-1022 and 0x1.fffffep-126f
    constexpr std::size_t general_buffer_size = 1 + (IsDouble ? 773 : 117);
    char general_buffer[general_buffer_size];
    char general_stdio_buffer[general_buffer_size + 1]; // + null terminator

    for (std::uint32_t frac = 0; frac < Fractions; ++frac) {
        const UIntType bits      = prefix + frac;
        const FloatingType input = _Bit_cast<FloatingType>(bits);

        auto result = to_chars(charconv_buffer, end(charconv_buffer), input, chars_format::fixed, precision);
        assert_message_bits(result.ec == errc{}, "to_chars fixed precision", bits);
        string_view charconv_sv(charconv_buffer, static_cast<std::size_t>(result.ptr - charconv_buffer));

        int stdio_ret = sprintf_s(stdio_buffer, size(stdio_buffer), "%.*f", precision, input);
        assert_message_bits(stdio_ret != -1, "sprintf_s fixed precision", bits);
        string_view stdio_sv(stdio_buffer);

        assert_message_bits(charconv_sv == stdio_sv, "fixed precision output", bits);


        result = to_chars(charconv_buffer, end(charconv_buffer), input, chars_format::scientific, precision);
        assert_message_bits(result.ec == errc{}, "to_chars scientific precision", bits);
        charconv_sv = string_view(charconv_buffer, static_cast<std::size_t>(result.ptr - charconv_buffer));

        stdio_ret = sprintf_s(stdio_buffer, size(stdio_buffer), "%.*e", precision, input);
        assert_message_bits(stdio_ret != -1, "sprintf_s scientific precision", bits);
        stdio_sv = stdio_buffer;

        assert_message_bits(charconv_sv == stdio_sv, "scientific precision output", bits);


        result = to_chars(general_buffer, end(general_buffer), input, chars_format::general, 5000);
        assert_message_bits(result.ec == errc{}, "to_chars general precision", bits);
        charconv_sv = string_view(general_buffer, static_cast<std::size_t>(result.ptr - general_buffer));

        stdio_ret = sprintf_s(general_stdio_buffer, size(general_stdio_buffer), "%.5000g", input);
        assert_message_bits(stdio_ret != -1, "sprintf_s general precision", bits);
        stdio_sv = general_stdio_buffer;

        assert_message_bits(charconv_sv == stdio_sv, "general precision output", bits);
    }
}

void test_floating_prefixes(mt19937_64& mt64) {
    {
        set<std::uint64_t> prefixes64;

        while (prefixes64.size() < PrefixesToTest) {
            const std::uint64_t val = mt64();

            if ((val & 0x7FF0000000000000ULL) != 0x7FF0000000000000ULL) { // skip INF/NAN
                prefixes64.insert(val & Mask64);
            }
        }

        for (const auto& prefix : prefixes64) {
            test_floating_prefix<true>(prefix);
            test_floating_precision_prefix<true>(prefix);
        }

        test_floating_hex_prefix<true>(*prefixes64.begin()); // save time by testing fewer hexfloats
    }

    {
        set<std::uint32_t> prefixes32;

        while (prefixes32.size() < PrefixesToTest) {
            const std::uint32_t val = static_cast<std::uint32_t>(mt64());

            if ((val & 0x7F800000U) != 0x7F800000U) { // skip INF/NAN
                prefixes32.insert(val & Mask32);
            }
        }

        for (const auto& prefix : prefixes32) {
            test_floating_prefix<false>(prefix);
            test_floating_precision_prefix<false>(prefix);
        }

        test_floating_hex_prefix<false>(*prefixes32.begin()); // save time by testing fewer hexfloats
    }
}

// TODO Enable once std::from_chars has floating point support.
#if 0
template <typename T>
void test_floating_from_chars(const chars_format fmt) {
    test_from_chars<T>("", fmt, 0, inv_arg); // no characters
    test_from_chars<T>("@1", fmt, 0, inv_arg); // '@' is bogus
    test_from_chars<T>("z1", fmt, 0, inv_arg); // 'z' is bogus
    test_from_chars<T>(".", fmt, 0, inv_arg); // '.' without digits is bogus
    test_from_chars<T>("+1", fmt, 0, inv_arg); // '+' is bogus
    test_from_chars<T>(" 1", fmt, 0, inv_arg); // ' ' is bogus
    test_from_chars<T>("p5", fmt, 0, inv_arg); // binary-exponent-part without digits is bogus
    test_from_chars<T>("in", fmt, 0, inv_arg); // incomplete inf is bogus
    test_from_chars<T>("na", fmt, 0, inv_arg); // incomplete nan is bogus

    test_from_chars<T>("-", fmt, 0, inv_arg); // '-' followed by no characters
    test_from_chars<T>("-@1", fmt, 0, inv_arg); // '-' followed by bogus '@'
    test_from_chars<T>("-z1", fmt, 0, inv_arg); // '-' followed by bogus 'z'
    test_from_chars<T>("-.", fmt, 0, inv_arg); // '-' followed by bogus '.'
    test_from_chars<T>("-+1", fmt, 0, inv_arg); // '-' followed by bogus '+'
    test_from_chars<T>("- 1", fmt, 0, inv_arg); // '-' followed by bogus ' '
    test_from_chars<T>("-p5", fmt, 0, inv_arg); // '-' followed by bogus binary-exponent-part
    test_from_chars<T>("-in", fmt, 0, inv_arg); // '-' followed by bogus incomplete inf
    test_from_chars<T>("-na", fmt, 0, inv_arg); // '-' followed by bogus incomplete nan
    test_from_chars<T>("--1", fmt, 0, inv_arg); // '-' can't be repeated

    if (fmt != chars_format::hex) { // "e5" are valid hexits
        test_from_chars<T>("e5", fmt, 0, inv_arg); // exponent-part without digits is bogus
        test_from_chars<T>("-e5", fmt, 0, inv_arg); // '-' followed by bogus exponent-part
    }

    constexpr T inf  = numeric_limits<T>::infinity();
    constexpr T qnan = numeric_limits<T>::quiet_NaN();

    test_from_chars<T>("InF", fmt, 3, errc{}, inf);
    test_from_chars<T>("infinite", fmt, 3, errc{}, inf);
    test_from_chars<T>("iNfInItY", fmt, 8, errc{}, inf);
    test_from_chars<T>("InfinityMeow", fmt, 8, errc{}, inf);

    test_from_chars<T>("-InF", fmt, 4, errc{}, -inf);
    test_from_chars<T>("-infinite", fmt, 4, errc{}, -inf);
    test_from_chars<T>("-iNfInItY", fmt, 9, errc{}, -inf);
    test_from_chars<T>("-InfinityMeow", fmt, 9, errc{}, -inf);

    test_from_chars<T>("NaN", fmt, 3, errc{}, qnan);
    test_from_chars<T>("nanotech", fmt, 3, errc{}, qnan);
    test_from_chars<T>("nan(", fmt, 3, errc{}, qnan);
    test_from_chars<T>("nan(@)", fmt, 3, errc{}, qnan);
    test_from_chars<T>("nan(()", fmt, 3, errc{}, qnan);
    test_from_chars<T>("nan(abc", fmt, 3, errc{}, qnan);
    test_from_chars<T>("nan()", fmt, 5, errc{}, qnan);
    test_from_chars<T>("nan(abc)def", fmt, 8, errc{}, qnan);
    test_from_chars<T>("nan(_09AZaz)", fmt, 12, errc{}, qnan);
    test_from_chars<T>("nan(int)", fmt, 8, errc{}, qnan);
    test_from_chars<T>("nan(snap)", fmt, 9, errc{}, qnan);

    test_from_chars<T>("-NaN", fmt, 4, errc{}, -qnan);
    test_from_chars<T>("-nanotech", fmt, 4, errc{}, -qnan);
    test_from_chars<T>("-nan(", fmt, 4, errc{}, -qnan);
    test_from_chars<T>("-nan(@)", fmt, 4, errc{}, -qnan);
    test_from_chars<T>("-nan(()", fmt, 4, errc{}, -qnan);
    test_from_chars<T>("-nan(abc", fmt, 4, errc{}, -qnan);
    test_from_chars<T>("-nan()", fmt, 6, errc{}, -qnan);
    test_from_chars<T>("-nan(abc)def", fmt, 9, errc{}, -qnan);
    test_from_chars<T>("-nan(_09AZaz)", fmt, 13, errc{}, -qnan);
    test_from_chars<T>("-nan(int)", fmt, 9, errc{}, -qnan);
    test_from_chars<T>("-nan(snap)", fmt, 10, errc{}, -qnan);

    // The UCRT considers indeterminate NaN to be negative quiet NaN with no payload bits set.
    // It parses "nan(ind)" and "-nan(ind)" identically.
    test_from_chars<T>("nan(InD)", fmt, 8, errc{}, -qnan);
    test_from_chars<T>("-nan(InD)", fmt, 9, errc{}, -qnan);

    test_from_chars<T>("nan(SnAn)", fmt, 9, errc{}, nullopt, TestFromCharsMode::SignalingNaN);
    test_from_chars<T>("-nan(SnAn)", fmt, 10, errc{}, nullopt, TestFromCharsMode::SignalingNaN);

    switch (fmt) {
    case chars_format::general:
        test_from_chars<T>("1729", fmt, 4, errc{}, T{1729});
        test_from_chars<T>("1729e3", fmt, 6, errc{}, T{1729000});
        test_from_chars<T>("10", fmt, 2, errc{}, T{10});
        test_from_chars<T>("11.", fmt, 3, errc{}, T{11});
        test_from_chars<T>("12.13", fmt, 5, errc{}, static_cast<T>(12.13)); // avoid truncation warning
        test_from_chars<T>(".14", fmt, 3, errc{}, static_cast<T>(.14)); // avoid truncation warning
        test_from_chars<T>("20e5", fmt, 4, errc{}, T{2000000});
        test_from_chars<T>("21.e5", fmt, 5, errc{}, T{2100000});
        test_from_chars<T>("22.23e5", fmt, 7, errc{}, T{2223000});
        test_from_chars<T>(".24e5", fmt, 5, errc{}, T{24000});
        test_from_chars<T>("33e+5", fmt, 5, errc{}, T{3300000});
        test_from_chars<T>("33e-5", fmt, 5, errc{}, static_cast<T>(.00033)); // avoid truncation warning
        test_from_chars<T>("4E7", fmt, 3, errc{}, T{40000000});
        test_from_chars<T>("-00123abc", fmt, 6, errc{}, T{-123});
        test_from_chars<T>(".0045000", fmt, 8, errc{}, static_cast<T>(.0045)); // avoid truncation warning
        test_from_chars<T>("000", fmt, 3, errc{}, T{0});
        test_from_chars<T>("0e9999", fmt, 6, errc{}, T{0});
        test_from_chars<T>("0e-9999", fmt, 7, errc{}, T{0});
        test_from_chars<T>("-000", fmt, 4, errc{}, T{-0.0});
        test_from_chars<T>("-0e9999", fmt, 7, errc{}, T{-0.0});
        test_from_chars<T>("-0e-9999", fmt, 8, errc{}, T{-0.0});
        test_from_chars<T>("1e9999", fmt, 6, errc::result_out_of_range, inf);
        test_from_chars<T>("-1e9999", fmt, 7, errc::result_out_of_range, -inf);
        test_from_chars<T>("1e-9999", fmt, 7, errc::result_out_of_range, T{0});
        test_from_chars<T>("-1e-9999", fmt, 8, errc::result_out_of_range, T{-0.0});
        test_from_chars<T>("1" + string(6000, '0'), fmt, 6001, errc::result_out_of_range, inf);
        test_from_chars<T>("-1" + string(6000, '0'), fmt, 6002, errc::result_out_of_range, -inf);
        test_from_chars<T>("." + string(6000, '0') + "1", fmt, 6002, errc::result_out_of_range, T{0});
        test_from_chars<T>("-." + string(6000, '0') + "1", fmt, 6003, errc::result_out_of_range, T{-0.0});
        test_from_chars<T>("1" + string(500, '0'), fmt, 501, errc::result_out_of_range, inf);
        test_from_chars<T>("-1" + string(500, '0'), fmt, 502, errc::result_out_of_range, -inf);
        test_from_chars<T>("." + string(500, '0') + "1", fmt, 502, errc::result_out_of_range, T{0});
        test_from_chars<T>("-." + string(500, '0') + "1", fmt, 503, errc::result_out_of_range, T{-0.0});
        break;
    case chars_format::scientific:
        test_from_chars<T>("1729", fmt, 0, inv_arg);
        test_from_chars<T>("1729e3", fmt, 6, errc{}, T{1729000});
        break;
    case chars_format::fixed:
        test_from_chars<T>("1729", fmt, 4, errc{}, T{1729});
        test_from_chars<T>("1729e3", fmt, 4, errc{}, T{1729});
        break;
    case chars_format::hex:
        test_from_chars<T>("0x123", fmt, 1, errc{}, T{0});
        test_from_chars<T>("a0", fmt, 2, errc{}, T{160});
        test_from_chars<T>("a1.", fmt, 3, errc{}, T{161});
        test_from_chars<T>("a2.a3", fmt, 5, errc{}, T{162.63671875});
        test_from_chars<T>(".a4", fmt, 3, errc{}, T{0.640625});
        test_from_chars<T>("a0p5", fmt, 4, errc{}, T{5120});
        test_from_chars<T>("a1.p5", fmt, 5, errc{}, T{5152});
        test_from_chars<T>("a2.a3p5", fmt, 7, errc{}, T{5204.375});
        test_from_chars<T>(".a4p5", fmt, 5, errc{}, T{20.5});
        test_from_chars<T>("a0p+5", fmt, 5, errc{}, T{5120});
        test_from_chars<T>("a0p-5", fmt, 5, errc{}, T{5});
        test_from_chars<T>("ABCDEFP3", fmt, 8, errc{}, T{90075000});
        test_from_chars<T>("-00cdrom", fmt, 5, errc{}, T{-205});
        test_from_chars<T>(".00ef000", fmt, 8, errc{}, T{0.0036468505859375});
        test_from_chars<T>("000", fmt, 3, errc{}, T{0});
        test_from_chars<T>("0p9999", fmt, 6, errc{}, T{0});
        test_from_chars<T>("0p-9999", fmt, 7, errc{}, T{0});
        test_from_chars<T>("-000", fmt, 4, errc{}, T{-0.0});
        test_from_chars<T>("-0p9999", fmt, 7, errc{}, T{-0.0});
        test_from_chars<T>("-0p-9999", fmt, 8, errc{}, T{-0.0});
        test_from_chars<T>("1p9999", fmt, 6, errc::result_out_of_range, inf);
        test_from_chars<T>("-1p9999", fmt, 7, errc::result_out_of_range, -inf);
        test_from_chars<T>("1p-9999", fmt, 7, errc::result_out_of_range, T{0});
        test_from_chars<T>("-1p-9999", fmt, 8, errc::result_out_of_range, T{-0.0});
        test_from_chars<T>("1" + string(2000, '0'), fmt, 2001, errc::result_out_of_range, inf);
        test_from_chars<T>("-1" + string(2000, '0'), fmt, 2002, errc::result_out_of_range, -inf);
        test_from_chars<T>("." + string(2000, '0') + "1", fmt, 2002, errc::result_out_of_range, T{0});
        test_from_chars<T>("-." + string(2000, '0') + "1", fmt, 2003, errc::result_out_of_range, T{-0.0});
        test_from_chars<T>("1" + string(300, '0'), fmt, 301, errc::result_out_of_range, inf);
        test_from_chars<T>("-1" + string(300, '0'), fmt, 302, errc::result_out_of_range, -inf);
        test_from_chars<T>("." + string(300, '0') + "1", fmt, 302, errc::result_out_of_range, T{0});
        test_from_chars<T>("-." + string(300, '0') + "1", fmt, 303, errc::result_out_of_range, T{-0.0});
        break;
    }
}
#endif

template <typename T>
void test_floating_to_chars(
    const T value, const optional<chars_format> opt_fmt, const optional<int> opt_precision, const string_view correct) {

    test_common_to_chars(value, opt_fmt, opt_precision, correct);
}

void all_floating_tests(mt19937_64& mt64) {
    test_floating_prefixes(mt64);

// TODO Enable once std::from_chars has floating point support.
#if 0
    for (const auto& fmt : {chars_format::general, chars_format::scientific, chars_format::fixed, chars_format::hex}) {
        test_floating_from_chars<float>(fmt);
        test_floating_from_chars<double>(fmt);
    }

    // Test rounding.

    // See float_from_chars_test_cases.hpp in this directory.
    for (const auto& t : float_from_chars_test_cases) {
        test_from_chars<float>(t.input, t.fmt, t.correct_idx, t.correct_ec, t.correct_value);
    }

    // See double_from_chars_test_cases.hpp in this directory.
    for (const auto& t : double_from_chars_test_cases) {
        test_from_chars<double>(t.input, t.fmt, t.correct_idx, t.correct_ec, t.correct_value);
    }

    {
        // See LWG-2403. This number (exactly 0x1.fffffd00000004 in infinite precision) behaves differently
        // when parsed as double and converted to float, versus being parsed as float directly.
        const char* const lwg_2403          = "1.999999821186065729339276231257827021181583404541015625";
        constexpr float correct_float       = 0x1.fffffep0f;
        constexpr double correct_double     = 0x1.fffffdp0;
        constexpr float twice_rounded_float = 0x1.fffffcp0f;

        test_from_chars<float>(lwg_2403, chars_format::general, 56, errc{}, correct_float);
        test_from_chars<double>(lwg_2403, chars_format::general, 56, errc{}, correct_double);
        static_assert(static_cast<float>(correct_double) == twice_rounded_float);
    }

    // See floating_point_test_cases.hpp.
    for (const auto& p : floating_point_test_cases_float) {
        test_from_chars<float>(p.first, chars_format::general, strlen(p.first), errc{}, _Bit_cast<float>(p.second));
    }

    for (const auto& p : floating_point_test_cases_double) {
        test_from_chars<double>(p.first, chars_format::general, strlen(p.first), errc{}, _Bit_cast<double>(p.second));
    }
#endif
    // See float_to_chars_test_cases.hpp in this directory.
    for (const auto& t : float_to_chars_test_cases) {
        if (t.fmt == chars_format{}) {
            test_floating_to_chars(t.value, nullopt, nullopt, t.correct);
        } else {
            test_floating_to_chars(t.value, t.fmt, nullopt, t.correct);
        }
    }

    // See double_to_chars_test_cases.hpp in this directory.
    for (const auto& t : double_to_chars_test_cases) {
        if (t.fmt == chars_format{}) {
            test_floating_to_chars(t.value, nullopt, nullopt, t.correct);
        } else {
            test_floating_to_chars(t.value, t.fmt, nullopt, t.correct);
        }
    }

    // See corresponding headers in this directory.
    for (const auto& t : float_hex_precision_to_chars_test_cases) {
        test_floating_to_chars(t.value, t.fmt, t.precision, t.correct);
    }
    for (const auto& t : float_fixed_precision_to_chars_test_cases) {
        test_floating_to_chars(t.value, t.fmt, t.precision, t.correct);
    }
    for (const auto& t : float_scientific_precision_to_chars_test_cases) {
        test_floating_to_chars(t.value, t.fmt, t.precision, t.correct);
    }
    for (const auto& t : float_general_precision_to_chars_test_cases) {
        test_floating_to_chars(t.value, t.fmt, t.precision, t.correct);
    }
    for (const auto& t : double_hex_precision_to_chars_test_cases) {
        test_floating_to_chars(t.value, t.fmt, t.precision, t.correct);
    }
    for (const auto& t : double_fixed_precision_to_chars_test_cases_1) {
        test_floating_to_chars(t.value, t.fmt, t.precision, t.correct);
    }
    for (const auto& t : double_fixed_precision_to_chars_test_cases_2) {
        test_floating_to_chars(t.value, t.fmt, t.precision, t.correct);
    }
    for (const auto& t : double_fixed_precision_to_chars_test_cases_3) {
        test_floating_to_chars(t.value, t.fmt, t.precision, t.correct);
    }
    for (const auto& t : double_fixed_precision_to_chars_test_cases_4) {
        test_floating_to_chars(t.value, t.fmt, t.precision, t.correct);
    }
    for (const auto& t : double_scientific_precision_to_chars_test_cases_1) {
        test_floating_to_chars(t.value, t.fmt, t.precision, t.correct);
    }
    for (const auto& t : double_scientific_precision_to_chars_test_cases_2) {
        test_floating_to_chars(t.value, t.fmt, t.precision, t.correct);
    }
    for (const auto& t : double_scientific_precision_to_chars_test_cases_3) {
        test_floating_to_chars(t.value, t.fmt, t.precision, t.correct);
    }
    for (const auto& t : double_scientific_precision_to_chars_test_cases_4) {
        test_floating_to_chars(t.value, t.fmt, t.precision, t.correct);
    }
    for (const auto& t : double_general_precision_to_chars_test_cases) {
        test_floating_to_chars(t.value, t.fmt, t.precision, t.correct);
    }
}

int main(int argc, char** argv) {
    const auto start = chrono::steady_clock::now();

    mt19937_64 mt64;

    initialize_randomness(mt64, argc, argv);

    all_integer_tests();

    all_floating_tests(mt64);

    const auto finish  = chrono::steady_clock::now();
    const long long ms = chrono::duration_cast<chrono::milliseconds>(finish - start).count();

    puts("PASS");
    printf("Randomized test cases: %zu\n", static_cast<std::size_t>(PrefixesToTest * Fractions));
    printf("Total time: %lld ms\n", ms);

    if (ms < 3'000) {
        puts("That was fast. Consider tuning PrefixesToTest and FractionBits to test more cases.");
    } else if (ms > 30'000) {
        puts("That was slow. Consider tuning PrefixesToTest and FractionBits to test fewer cases.");
    }
}