1// Copyright (c) Microsoft Corporation.
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3
4#include "test.hpp"
5
6#include <algorithm>
7#include <array>
8#include <assert.h>
9#include <charconv>
10#include <chrono>
11#include <cmath>
12#include <functional>
13#include <iterator>
14#include <limits>
15#include <locale>
16#include <optional>
17#include <random>
18#include <set>
19#include <stdint.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <string>
24#include <string_view>
25#include <system_error>
26#include <type_traits>
27#include <utility>
28#include <vector>
29
30#include "double_fixed_precision_to_chars_test_cases_1.hpp"
31#include "double_fixed_precision_to_chars_test_cases_2.hpp"
32#include "double_fixed_precision_to_chars_test_cases_3.hpp"
33#include "double_fixed_precision_to_chars_test_cases_4.hpp"
34#include "double_from_chars_test_cases.hpp"
35#include "double_general_precision_to_chars_test_cases.hpp"
36#include "double_hex_precision_to_chars_test_cases.hpp"
37#include "double_scientific_precision_to_chars_test_cases_1.hpp"
38#include "double_scientific_precision_to_chars_test_cases_2.hpp"
39#include "double_scientific_precision_to_chars_test_cases_3.hpp"
40#include "double_scientific_precision_to_chars_test_cases_4.hpp"
41#include "double_to_chars_test_cases.hpp"
42#include "float_fixed_precision_to_chars_test_cases.hpp"
43#include "float_from_chars_test_cases.hpp"
44#include "float_general_precision_to_chars_test_cases.hpp"
45#include "float_hex_precision_to_chars_test_cases.hpp"
46#include "float_scientific_precision_to_chars_test_cases.hpp"
47#include "float_to_chars_test_cases.hpp"
48
49using namespace std;
50
51void initialize_randomness(mt19937_64& mt64, const int argc, char** const /*argv*/) {
52 constexpr std::size_t n = mt19937_64::state_size;
53 constexpr std::size_t w = mt19937_64::word_size;
54 static_assert(w % 32 == 0);
55 constexpr std::size_t k = w / 32;
56
57 vector<std::uint32_t> vec(n * k);
58
59 puts(s: "USAGE:");
60 puts(s: "test.exe : generates seed data from random_device.");
61
62 if (argc == 1) {
63 random_device rd;
64 generate(first: vec.begin(), last: vec.end(), gen: ref(t&: rd));
65 puts(s: "Generated seed data.");
66 } else {
67 puts(s: "ERROR: Too many command-line arguments.");
68 abort();
69 }
70
71 puts(s: "SEED DATA:");
72 for (const auto& elem : vec) {
73 printf(format: "%zu ", static_cast<std::size_t>(elem));
74 }
75 printf(format: "\n");
76
77 seed_seq seq(vec.cbegin(), vec.cend());
78
79 mt64.seed(q&: seq);
80
81 puts(s: "Successfully seeded mt64. First three values:");
82 for (int i = 0; i < 3; ++i) {
83 // libc++ uses long for 64-bit values.
84 printf(format: "0x%016llX\n", static_cast<unsigned long long>(mt64()));
85 }
86}
87
88static_assert((chars_format::scientific & chars_format::fixed) == chars_format{});
89static_assert((chars_format::scientific & chars_format::hex) == chars_format{});
90static_assert((chars_format::fixed & chars_format::hex) == chars_format{});
91static_assert(chars_format::general == (chars_format::fixed | chars_format::scientific));
92
93template <typename T, typename Optional>
94void test_common_to_chars(
95 const T value, const Optional opt_arg, const optional<int> opt_precision, const string_view correct) {
96
97 // Important: Test every effective buffer size from 0 through correct.size() and slightly beyond. For the sizes
98 // less than correct.size(), this verifies that the too-small buffer is correctly detected, and that we don't
99 // attempt to write outside of it, even by a single char. (This exhaustive validation is necessary because the
100 // implementation must check whenever it attempts to write. Sometimes we can calculate the total size and perform
101 // a single check, but sometimes we need to check when writing each part of the result.) Testing correct.size()
102 // verifies that we can succeed without overrunning, and testing slightly larger sizes verifies that we can succeed
103 // without attempting to write to extra chars even when they're available. Finally, we also verify that we aren't
104 // underrunning the buffer. This is a concern because sometimes we walk backwards when rounding.
105
106 constexpr std::size_t BufferPrefix = 20; // detect buffer underruns (specific value isn't important)
107
108 constexpr std::size_t Space = is_integral_v<T> ? 1 + 64 // worst case: -2^63 in binary
109 : is_same_v<T, float>
110 ? 1 + 151 // worst case: negative min subnormal float, fixed notation
111 : 1 + 1076; // worst case: negative min subnormal double, fixed notation
112
113 constexpr std::size_t BufferSuffix = 30; // detect buffer overruns (specific value isn't important)
114
115 array<char, BufferPrefix + Space + BufferSuffix> buff;
116
117 char* const buff_begin = buff.data();
118 char* const first = buff_begin + BufferPrefix;
119 char* const buff_end = buff_begin + buff.size();
120
121 constexpr std::size_t ExtraChars = 3;
122 static_assert(ExtraChars + 10 < BufferSuffix,
123 "The specific values aren't important, but there should be plenty of room to detect buffer overruns.");
124
125 for (std::size_t n = 0; n <= correct.size() + ExtraChars; ++n) {
126 assert(n <= static_cast<std::size_t>(buff_end - first));
127 char* const last = first + n;
128
129 buff.fill('@');
130 const auto is_fill_char = [](const char c) { return c == '@'; };
131
132 to_chars_result result{};
133 if (opt_precision.has_value()) {
134 assert(opt_arg.has_value());
135
136 if constexpr (is_floating_point_v<T>) {
137 result = to_chars(first, last, value, opt_arg.value(), opt_precision.value());
138 } else {
139 abort();
140 }
141 } else if (opt_arg.has_value()) {
142 result = to_chars(first, last, value, opt_arg.value());
143 } else {
144 result = to_chars(first, last, value);
145 }
146
147 if (n < correct.size()) {
148 assert(result.ptr == last);
149 assert(result.ec == errc::value_too_large);
150 assert(all_of(buff_begin, first, is_fill_char));
151 // [first, last) is unspecified
152 assert(all_of(last, buff_end, is_fill_char));
153 } else {
154 assert(result.ptr == first + correct.size());
155 assert(result.ec == errc{});
156 assert(all_of(buff_begin, first, is_fill_char));
157 assert(equal(first, result.ptr, correct.begin(), correct.end()));
158 assert(all_of(result.ptr, buff_end, is_fill_char));
159 }
160 }
161}
162
163template <typename T>
164void test_integer_to_chars(const T value, const optional<int> opt_base, const string_view correct) {
165
166 test_common_to_chars(value, opt_base, nullopt, correct);
167
168 { // Also test successful from_chars() scenarios.
169 const char* const correct_first = correct.data();
170 const char* const correct_last = correct_first + correct.size();
171
172 T dest = 0;
173
174 const from_chars_result from_res =
175 (opt_base.has_value() ? from_chars(correct_first, correct_last, dest, opt_base.value())
176 : from_chars(correct_first, correct_last, dest));
177
178 assert(from_res.ptr == correct_last);
179 assert(from_res.ec == errc{});
180 assert(dest == value);
181 }
182}
183
184// https://www.wolframalpha.com : Table[BaseForm[n * 2 - 1, n], {n, 2, 36}]
185constexpr const char* output_max_digit[] = {"skip0", "skip1", "11", "12", "13", "14", "15", "16", "17", "18", "19",
186 "1a", "1b", "1c", "1d", "1e", "1f", "1g", "1h", "1i", "1j", "1k", "1l", "1m", "1n", "1o", "1p", "1q", "1r", "1s",
187 "1t", "1u", "1v", "1w", "1x", "1y", "1z"};
188
189// https://www.wolframalpha.com : Table[BaseForm[k, n], {k, {MEOW, MEOW, MEOW}}, {n, 2, 36}]
190constexpr std::uint64_t stress_chunks_positive = 12000000345000678900ULL;
191constexpr pair<std::uint64_t, array<const char*, 37>> output_positive[] = {
192 {123U, {._M_elems: {"skip0", "skip1", "1111011", "11120", "1323", "443", "323", "234", "173", "146", "123", "102", "a3", "96",
193 "8b", "83", "7b", "74", "6f", "69", "63", "5i", "5d", "58", "53", "4n", "4j", "4f", "4b", "47", "43",
194 "3u", "3r", "3o", "3l", "3i", "3f"}}},
195 {std::uint64_t{INT8_MAX}, {._M_elems: {"skip0", "skip1", "1111111", "11201", "1333", "1002", "331", "241", "177", "151", "127",
196 "106", "a7", "9a", "91", "87", "7f", "78", "71", "6d", "67", "61", "5h", "5c", "57", "52",
197 "4n", "4j", "4f", "4b", "47", "43", "3v", "3s", "3p", "3m", "3j"}}},
198 {161U, {._M_elems: {"skip0", "skip1", "10100001", "12222", "2201", "1121", "425", "320", "241", "188", "161", "137", "115",
199 "c5", "b7", "ab", "a1", "98", "8h", "89", "81", "7e", "77", "70", "6h", "6b", "65", "5q", "5l", "5g",
200 "5b", "56", "51", "4t", "4p", "4l", "4h"}}},
201 {UINT8_MAX, {._M_elems: {"skip0", "skip1", "11111111", "100110", "3333", "2010", "1103", "513", "377", "313", "255", "212",
202 "193", "168", "143", "120", "ff", "f0", "e3", "d8", "cf", "c3", "bd", "b2", "af", "a5", "9l", "9c",
203 "93", "8n", "8f", "87", "7v", "7o", "7h", "7a", "73"}}},
204 {1729U, {._M_elems: {"skip0", "skip1", "11011000001", "2101001", "123001", "23404", "12001", "5020", "3301", "2331", "1729",
205 "1332", "1001", "a30", "8b7", "7a4", "6c1", "5gc", "561", "4f0", "469", "3j7", "3cd", "364", "301",
206 "2j4", "2ed", "2a1", "25l", "21i", "1rj", "1oo", "1m1", "1jd", "1gt", "1ee", "1c1"}}},
207 {std::uint64_t{INT16_MAX}, {._M_elems: {"skip0", "skip1", "111111111111111", "1122221121", "13333333", "2022032", "411411",
208 "164350", "77777", "48847", "32767", "22689", "16b67", "11bb7", "bd27", "9a97", "7fff",
209 "6b68", "5b27", "4eeb", "41i7", "3b67", "31f9", "2flf", "28l7", "22ah", "1mc7", "1hpg",
210 "1dm7", "19rq", "16c7", "1330", "vvv", "u2v", "sbp", "qq7", "pa7"}}},
211 {57494U, {._M_elems: {"skip0", "skip1", "1110000010010110", "2220212102", "32002112", "3314434", "1122102", "326423", "160226",
212 "86772", "57494", "3a218", "29332", "20228", "16d4a", "1207e", "e096", "bbg0", "9f82", "8750", "73ee",
213 "647h", "58h8", "4gfh", "43je", "3goj", "3718", "2onb", "2h9a", "2aag", "23qe", "1spk", "1o4m", "1jq8",
214 "1fp0", "1bwo", "18d2"}}},
215 {UINT16_MAX, {._M_elems: {"skip0", "skip1", "1111111111111111", "10022220020", "33333333", "4044120", "1223223", "362031",
216 "177777", "108806", "65535", "45268", "31b13", "23aa2", "19c51", "14640", "ffff", "d5d0", "b44f",
217 "9aa4", "83gf", "71cf", "638j", "58k8", "4hif", "44la", "3iof", "38o6", "2rgf", "2jqo", "2cof",
218 "2661", "1vvv", "1r5u", "1mnh", "1ihf", "1ekf"}}},
219 {71125478U, {._M_elems: {"skip0", "skip1", "100001111010100100111100110", "11221211112210222", "10033110213212",
220 "121202003403", "11020244342", "1522361624", "417244746", "157745728", "71125478", "3716a696",
221 "1b9a06b2", "11973ba8", "9636514", "639e338", "43d49e6", "2g19gfb", "21b9d18", "19dec94", "124addi",
222 "h8f25b", "dhdfa6", "b13hg2", "8m91he", "7720j3", "5pgj58", "4pmelq", "43k17i", "3dg8ek", "2ro898",
223 "2f0et8", "23qif6", "1qw5lh", "1j7l7s", "1cdvli", "16cgrq"}}},
224 {std::uint64_t{INT32_MAX},
225 {._M_elems: {"skip0", "skip1", "1111111111111111111111111111111", "12112122212110202101", "1333333333333333",
226 "13344223434042", "553032005531", "104134211161", "17777777777", "5478773671", "2147483647", "a02220281",
227 "4bb2308a7", "282ba4aaa", "1652ca931", "c87e66b7", "7fffffff", "53g7f548", "3928g3h1", "27c57h32",
228 "1db1f927", "140h2d91", "ikf5bf1", "ebelf95", "b5gge57", "8jmdnkm", "6oj8ion", "5ehncka", "4clm98f",
229 "3hk7987", "2sb6cs7", "2d09uc1", "1vvvvvv", "1lsqtl1", "1d8xqrp", "15v22um", "zik0zj"}}},
230 {3522553278ULL,
231 {._M_elems: {"skip0", "skip1", "11010001111101011110010110111110", "100002111022020200020", "3101331132112332",
232 "24203233201103", "1341312313010", "153202131426", "32175362676", "10074266606", "3522553278", "1548431462",
233 "823842766", "441a34c6a", "255b8d486", "1593b4753", "d1f5e5be", "89ffb3b6", "5da3e606", "3hgbfb5i",
234 "2f0fj33i", "1k1ac536", "191b46e2", "10i6fmk8", "ia967l6", "eahia63", "baca9ga", "92d86i6", "78iq4i6",
235 "5qlc1dc", "4osos2i", "3u1862s", "38vbpdu", "2o0a7ro", "29hx9e6", "1w2dnod", "1m98ji6"}}},
236 {UINT32_MAX,
237 {._M_elems: {"skip0", "skip1", "11111111111111111111111111111111", "102002022201221111210", "3333333333333333",
238 "32244002423140", "1550104015503", "211301422353", "37777777777", "12068657453", "4294967295", "1904440553",
239 "9ba461593", "535a79888", "2ca5b7463", "1a20dcd80", "ffffffff", "a7ffda90", "704he7g3", "4f5aff65",
240 "3723ai4f", "281d55i3", "1fj8b183", "1606k7ib", "mb994af", "hek2mgk", "dnchbnl", "b28jpdl", "8pfgih3",
241 "76beigf", "5qmcpqf", "4q0jto3", "3vvvvvv", "3aokq93", "2qhxjlh", "2br45qa", "1z141z3"}}},
242 {545890816626160ULL,
243 {._M_elems: {"skip0", "skip1", "1111100000111110000011100001101100000110111110000", "2122120211122121121021010202111",
244 "1330013300130031200313300", "1033022333343024014120", "5213002440142255104", "222661211220253465",
245 "17407603415406760", "2576748547233674", "545890816626160", "148a34aa4706535", "51285369b87494",
246 "1a57a38b045a95", "98b3383b9766c", "4319d1601875a", "1f07c1c360df0", "ffd471f34f13", "88g09ff9dh84",
247 "4d0d5e232c53", "2d63h403i580", "1bf5h8185hdj", "kc3g550fkcg", "d41id5k9984", "8ef5n0him4g", "5i2dijfe1la",
248 "3me22fm5fhi", "2hfmhgg73kd", "1ngpfabr53c", "18i7220bh11", "rm0lcjngpa", "kk1elesni1", "fgfge3c3fg",
249 "bp4q5l6bjg", "8xna46jp0k", "6wejomvji5", "5di2s1qhv4"}}},
250 {std::uint64_t{INT64_MAX},
251 {._M_elems: {"skip0", "skip1", "111111111111111111111111111111111111111111111111111111111111111",
252 "2021110011022210012102010021220101220221", "13333333333333333333333333333333",
253 "1104332401304422434310311212", "1540241003031030222122211", "22341010611245052052300",
254 "777777777777777777777", "67404283172107811827", "9223372036854775807", "1728002635214590697",
255 "41a792678515120367", "10b269549075433c37", "4340724c6c71dc7a7", "160e2ad3246366807", "7fffffffffffffff",
256 "33d3d8307b214008", "16agh595df825fa7", "ba643dci0ffeehh", "5cbfjia3fh26ja7", "2heiciiie82dh97",
257 "1adaibb21dckfa7", "i6k448cf4192c2", "acd772jnc9l0l7", "64ie1focnn5g77", "3igoecjbmca687", "27c48l5b37oaop",
258 "1bk39f3ah3dmq7", "q1se8f0m04isb", "hajppbc1fc207", "bm03i95hia437", "7vvvvvvvvvvvv", "5hg4ck9jd4u37",
259 "3tdtk1v8j6tpp", "2pijmikexrxp7", "1y2p0ij32e8e7"}}},
260 {stress_chunks_positive,
261 {._M_elems: {"skip0", "skip1", "1010011010001000100100001011110000101100010101001001010111110100",
262 "2221221122020020011022001202200200202200", "22122020210023300230111021113310",
263 "1301130403021123030133211100", "2311004450342244200504500", "30325064311430214266301",
264 "1232104413605425112764", "87848206138052620680", "12000000345000678900", "2181782a1686924456a",
265 "54aa47a9058877b130", "150593a5b002c87b16", "571cad2b93c7760a8", "1c60d2676d4e53e00", "a68890bc2c5495f4",
266 "43499224707a4f4g", "1e052gdga1d26f40", "f06dh4g564c8a91", "769df0d9ace4h50", "3ee7bcj1ajghi4f",
267 "1k9agc4gfl0l43a", "10id7dakdlcjd22", "dge08fe0l5hl7c", "8184326d31ib60", "4ljbglf3cpim76",
268 "2pph66481kiiki", "1niph2ao132e58", "14qgbgk3c3iffg", "mhc35an1bhb00", "f78o8ur705ln5", "ad24gngm595fk",
269 "76e1n5i5v0ivl", "50wu8jsnks82g", "3ja41smfvqb1f", "2j64t3qgq0ut0"}}},
270 {14454900944617508688ULL,
271 {._M_elems: {"skip0", "skip1", "1100100010011010000111111101001011100011011000101000111101010000",
272 "10120022020112011211121221212101012220210", "30202122013331023203120220331100",
273 "1432224030234034034040234223", "3014532424232535441404120", "34610451042001242144165",
274 "1442320775134330507520", "116266464747855335823", "14454900944617508688", "266642a9a9471339935",
275 "662251403263939640", "1895280092bc310481", "68cb9c8292557406c", "23023deab20002893", "c89a1fd2e3628f50",
276 "50e7147a7db8ef84", "22a34a05086f78ec", "i1dgef04357g7i1", "8g90b882jcj8be8", "49c1kk35i0k24ic",
277 "272a16i54ebkacg", "15fdih7l3m7k8md", "gbj7303eg9nge0", "9hckfdkj3kkdmd", "5lc7hifdkl4nne",
278 "3f86e4mgpna5ol", "266pj428na273c", "1bomgjbnlg4m3f", "r5tf1f7f009ji", "iarsig29iqhhm", "ch6gvqbhm53qg",
279 "8lwtvcdj6rlqr", "61w23lajggp44", "49p1f3dsqqcdx", "31tkqqkxypopc"}}},
280 {UINT64_MAX,
281 {._M_elems: {"skip0", "skip1", "1111111111111111111111111111111111111111111111111111111111111111",
282 "11112220022122120101211020120210210211220", "33333333333333333333333333333333",
283 "2214220303114400424121122430", "3520522010102100444244423", "45012021522523134134601",
284 "1777777777777777777777", "145808576354216723756", "18446744073709551615", "335500516a429071284",
285 "839365134a2a240713", "219505a9511a867b72", "8681049adb03db171", "2c1d56b648c6cd110", "ffffffffffffffff",
286 "67979g60f5428010", "2d3fgb0b9cg4bd2f", "141c8786h1ccaagg", "b53bjh07be4dj0f", "5e8g4ggg7g56dif",
287 "2l4lf104353j8kf", "1ddh88h2782i515", "l12ee5fn0ji1if", "c9c336o0mlb7ef", "7b7n2pcniokcgf",
288 "4eo8hfam6fllmo", "2nc6j26l66rhof", "1n3rsh11f098rn", "14l9lkmo30o40f", "nd075ib45k86f", "fvvvvvvvvvvvv",
289 "b1w8p7j5q9r6f", "7orp63sh4dphh", "5g24a25twkwff", "3w5e11264sgsf"}}},
290};
291
292// https://www.wolframalpha.com : Table[BaseForm[k, n], {k, {MEOW, MEOW, MEOW}}, {n, 2, 36}]
293constexpr std::int64_t stress_chunks_negative = -9000876000000054321LL;
294constexpr pair<std::int64_t, array<const char*, 37>> output_negative[] = {
295 {-85, {._M_elems: {"skip0", "skip1", "-1010101", "-10011", "-1111", "-320", "-221", "-151", "-125", "-104", "-85", "-78",
296 "-71", "-67", "-61", "-5a", "-55", "-50", "-4d", "-49", "-45", "-41", "-3j", "-3g", "-3d", "-3a", "-37",
297 "-34", "-31", "-2r", "-2p", "-2n", "-2l", "-2j", "-2h", "-2f", "-2d"}}},
298 {INT8_MIN, {._M_elems: {"skip0", "skip1", "-10000000", "-11202", "-2000", "-1003", "-332", "-242", "-200", "-152", "-128",
299 "-107", "-a8", "-9b", "-92", "-88", "-80", "-79", "-72", "-6e", "-68", "-62", "-5i", "-5d", "-58",
300 "-53", "-4o", "-4k", "-4g", "-4c", "-48", "-44", "-40", "-3t", "-3q", "-3n", "-3k"}}},
301 {-1591, {._M_elems: {"skip0", "skip1", "-11000110111", "-2011221", "-120313", "-22331", "-11211", "-4432", "-3067", "-2157",
302 "-1591", "-1217", "-b07", "-955", "-819", "-711", "-637", "-58a", "-4g7", "-47e", "-3jb", "-3cg",
303 "-367", "-304", "-2i7", "-2dg", "-295", "-24p", "-20n", "-1pp", "-1n1", "-1ka", "-1hn", "-1f7", "-1cr",
304 "-1ag", "-187"}}},
305 {INT16_MIN, {._M_elems: {"skip0", "skip1", "-1000000000000000", "-1122221122", "-20000000", "-2022033", "-411412", "-164351",
306 "-100000", "-48848", "-32768", "-2268a", "-16b68", "-11bb8", "-bd28", "-9a98", "-8000", "-6b69",
307 "-5b28", "-4eec", "-41i8", "-3b68", "-31fa", "-2flg", "-28l8", "-22ai", "-1mc8", "-1hph", "-1dm8",
308 "-19rr", "-16c8", "-1331", "-1000", "-u2w", "-sbq", "-qq8", "-pa8"}}},
309 {-66748412,
310 {._M_elems: {"skip0", "skip1", "-11111110100111111111111100", "-11122121011121102", "-3332213333330", "-114041422122",
311 "-10342352232", "-1440231533", "-376477774", "-148534542", "-66748412", "-34750085", "-1a42b678",
312 "-10aa0803", "-8c1731a", "-5cd7492", "-3fa7ffc", "-2d03163", "-1h5f3b2", "-17i39c6", "-10h3b0c", "-g749jh",
313 "-ckkdkg", "-a8c0ak", "-894afk", "-6klmbc", "-5g1i6g", "-4hg4gb", "-3ogi7o", "-37anqb", "-2mc4r2",
314 "-2a8h7i", "-1vkvvs", "-1n9ca5", "-1fw8sk", "-19gshh", "-13qnek"}}},
315 {INT32_MIN, {._M_elems: {"skip0", "skip1", "-10000000000000000000000000000000", "-12112122212110202102", "-2000000000000000",
316 "-13344223434043", "-553032005532", "-104134211162", "-20000000000", "-5478773672", "-2147483648",
317 "-a02220282", "-4bb2308a8", "-282ba4aab", "-1652ca932", "-c87e66b8", "-80000000", "-53g7f549",
318 "-3928g3h2", "-27c57h33", "-1db1f928", "-140h2d92", "-ikf5bf2", "-ebelf96", "-b5gge58", "-8jmdnkn",
319 "-6oj8ioo", "-5ehnckb", "-4clm98g", "-3hk7988", "-2sb6cs8", "-2d09uc2", "-2000000", "-1lsqtl2",
320 "-1d8xqrq", "-15v22un", "-zik0zk"}}},
321 {-297139747082649553LL,
322 {._M_elems: {"skip0", "skip1", "-10000011111101001110000011010010001100000101011111111010001",
323 "-1222110012002112101210012211022102101", "-100133221300122101200223333101", "-4443033200104011124241203",
324 "-21313431255203203120401", "-350320603201030412545", "-20375160322140537721", "-1873162471705738371",
325 "-297139747082649553", "-65150976074a24025", "-173522497b5373101", "-5a60a99bc3b71654", "-1ca51a06cc38ba25",
326 "-a2a25babe62241d", "-41fa7069182bfd1", "-1d00134fba1769g", "-e4f799fc5f7e81", "-714ebbh8388188",
327 "-3cahb17836b3hd", "-1j8659jf5hbg3j", "-112bbb2jege5c5", "-dcjfmk2kjb4cc", "-836bm4klbgl61",
328 "-4ofia1416ee73", "-32ommgjef1l2h", "-1qc52eal5m8ba", "-17n53r05a4r15", "-oa88m2qiqjik", "-gn67qoat5r8d",
329 "-blgd6n5s90al", "-87t70q8o5fuh", "-5t09hwaqu9qg", "-47vssihaoa4x", "-32p24fbjye7x", "-299r8zck3841"}}},
330 {stress_chunks_negative,
331 {._M_elems: {"skip0", "skip1", "-111110011101001100010010000100010000111010101111001010000110001",
332 "-2012222010200021010000112111002001111200", "-13303221202100202013111321100301",
333 "-1101001100304341000003214241", "-1522150121302454031001413", "-22054250360123016161454",
334 "-763514220420725712061", "-65863607100474061450", "-9000876000000054321", "-1689813530958833498",
335 "-408258185a67069269", "-106b01597a47ba2948", "-41c02922bc776d49b", "-1584cd10979dc84b6",
336 "-7ce9890887579431", "-327cf6cbc67023c3", "-1604b5f6a0de8129", "-b50d3ef02f124a4", "-59h9bfif0006fg1",
337 "-2g5d8ekh05d2dfi", "-19i418c38g1chfj", "-hjgf7d0k0gla9a", "-a6b21ncehfa3f9", "-61060fnl003bml",
338 "-3g88bakondgf8l", "-25q3i730ed21di", "-1al84glo518iip", "-pcli8ig7pjhbo", "-gs31q8id2jnkl",
339 "-bd7kaglgdrbgk", "-7pqc9123lf51h", "-5d2sd1r5ms7su", "-3q833s8kdrun3", "-2n7vmqigfueqb",
340 "-1wdu892toj0a9"}}},
341 {INT64_MIN, {._M_elems: {"skip0", "skip1", "-1000000000000000000000000000000000000000000000000000000000000000",
342 "-2021110011022210012102010021220101220222", "-20000000000000000000000000000000",
343 "-1104332401304422434310311213", "-1540241003031030222122212", "-22341010611245052052301",
344 "-1000000000000000000000", "-67404283172107811828", "-9223372036854775808", "-1728002635214590698",
345 "-41a792678515120368", "-10b269549075433c38", "-4340724c6c71dc7a8", "-160e2ad3246366808",
346 "-8000000000000000", "-33d3d8307b214009", "-16agh595df825fa8", "-ba643dci0ffeehi",
347 "-5cbfjia3fh26ja8", "-2heiciiie82dh98", "-1adaibb21dckfa8", "-i6k448cf4192c3", "-acd772jnc9l0l8",
348 "-64ie1focnn5g78", "-3igoecjbmca688", "-27c48l5b37oaoq", "-1bk39f3ah3dmq8", "-q1se8f0m04isc",
349 "-hajppbc1fc208", "-bm03i95hia438", "-8000000000000", "-5hg4ck9jd4u38", "-3tdtk1v8j6tpq",
350 "-2pijmikexrxp8", "-1y2p0ij32e8e8"}}},
351};
352
353template <typename T>
354void test_integer_to_chars() {
355 for (int base = 2; base <= 36; ++base) {
356 test_integer_to_chars(static_cast<T>(0), base, "0");
357 test_integer_to_chars(static_cast<T>(1), base, "1");
358
359 // tests [3, 71]
360 test_integer_to_chars(static_cast<T>(base * 2 - 1), base, output_max_digit[base]);
361
362 for (const auto& p : output_positive) {
363 if (p.first <= static_cast<std::uint64_t>(numeric_limits<T>::max())) {
364 test_integer_to_chars(static_cast<T>(p.first), base, p.second[static_cast<std::size_t>(base)]);
365 }
366 }
367
368 if constexpr (is_signed_v<T>) {
369 test_integer_to_chars(static_cast<T>(-1), base, "-1");
370
371 for (const auto& p : output_negative) {
372 if (p.first >= static_cast<std::int64_t>(numeric_limits<T>::min())) {
373 test_integer_to_chars(static_cast<T>(p.first), base, p.second[static_cast<std::size_t>(base)]);
374 }
375 }
376 }
377 }
378
379 test_integer_to_chars(static_cast<T>(42), nullopt, "42");
380}
381
382enum class TestFromCharsMode { Normal, SignalingNaN };
383
384template <typename T, typename BaseOrFmt>
385void test_from_chars(const string_view input, const BaseOrFmt base_or_fmt, const std::size_t correct_idx,
386 const errc correct_ec, const optional<T> opt_correct = nullopt,
387 const TestFromCharsMode mode = TestFromCharsMode::Normal) {
388
389 if constexpr (is_integral_v<T>) {
390 assert(mode == TestFromCharsMode::Normal);
391 }
392
393 constexpr T unmodified = 111;
394
395 T dest = unmodified;
396
397 const from_chars_result result = from_chars(input.data(), input.data() + input.size(), dest, base_or_fmt);
398
399 assert(result.ptr == input.data() + correct_idx);
400 assert(result.ec == correct_ec);
401
402 if (correct_ec == errc{} || (is_floating_point_v<T> && correct_ec == errc::result_out_of_range)) {
403 if constexpr (is_floating_point_v<T>) {
404 if (mode == TestFromCharsMode::Normal) {
405 using Uint = conditional_t<is_same_v<T, float>, std::uint32_t, std::uint64_t>;
406 assert(opt_correct.has_value());
407 assert(_Bit_cast<Uint>(dest) == _Bit_cast<Uint>(opt_correct.value()));
408 } else {
409 assert(mode == TestFromCharsMode::SignalingNaN);
410 assert(!opt_correct.has_value());
411 assert(isnan(dest));
412 }
413 } else {
414 assert(opt_correct.has_value());
415 assert(dest == opt_correct.value());
416 }
417 } else {
418 assert(!opt_correct.has_value());
419 assert(dest == unmodified);
420 }
421}
422
423constexpr errc inv_arg = errc::invalid_argument;
424constexpr errc out_ran = errc::result_out_of_range;
425
426template <typename T>
427void test_integer_from_chars() {
428 for (int base = 2; base <= 36; ++base) {
429 test_from_chars<T>("", base, 0, inv_arg); // no characters
430 test_from_chars<T>("@1", base, 0, inv_arg); // '@' is bogus
431 test_from_chars<T>(".1", base, 0, inv_arg); // '.' is bogus, for integers
432 test_from_chars<T>("+1", base, 0, inv_arg); // '+' is bogus, N4713 23.20.3 [charconv.from.chars]/3
433 // "a minus sign is the only sign that may appear"
434 test_from_chars<T>(" 1", base, 0, inv_arg); // ' ' is bogus, no whitespace in subject sequence
435
436 if constexpr (is_unsigned_v<T>) { // N4713 23.20.3 [charconv.from.chars]/3
437 test_from_chars<T>("-1", base, 0, inv_arg); // "and only if value has a signed type"
438 }
439
440 // N4713 23.20.3 [charconv.from.chars]/1 "[ Note: If the pattern allows for an optional sign,
441 // but the string has no digit characters following the sign, no characters match the pattern. -end note ]"
442 test_from_chars<T>("-", base, 0, inv_arg); // '-' followed by no characters
443 test_from_chars<T>("-@1", base, 0, inv_arg); // '-' followed by bogus '@'
444 test_from_chars<T>("-.1", base, 0, inv_arg); // '-' followed by bogus '.'
445 test_from_chars<T>("-+1", base, 0, inv_arg); // '-' followed by bogus '+'
446 test_from_chars<T>("- 1", base, 0, inv_arg); // '-' followed by bogus ' '
447 test_from_chars<T>("--1", base, 0, inv_arg); // '-' can't be repeated
448
449 vector<char> bogus_digits;
450
451 if (base < 10) {
452 bogus_digits = {static_cast<char>('0' + base), 'A', 'a'};
453 } else {
454 // '[' and '{' are bogus for base 36
455 bogus_digits = {static_cast<char>('A' + (base - 10)), static_cast<char>('a' + (base - 10))};
456 }
457
458 for (const auto& bogus : bogus_digits) {
459 test_from_chars<T>(bogus + "1"s, base, 0, inv_arg); // bogus digit (for this base)
460 test_from_chars<T>("-"s + bogus + "1"s, base, 0, inv_arg); // '-' followed by bogus digit
461 }
462
463 // Test leading zeroes.
464 test_from_chars<T>(string(100, '0'), base, 100, errc{}, static_cast<T>(0));
465 test_from_chars<T>(string(100, '0') + "11"s, base, 102, errc{}, static_cast<T>(base + 1));
466
467 // Test negative zero and negative leading zeroes.
468 if constexpr (is_signed_v<T>) {
469 test_from_chars<T>("-0", base, 2, errc{}, static_cast<T>(0));
470 test_from_chars<T>("-"s + string(100, '0'), base, 101, errc{}, static_cast<T>(0));
471 test_from_chars<T>("-"s + string(100, '0') + "11"s, base, 103, errc{}, static_cast<T>(-base - 1));
472 }
473
474 // N4713 23.20.3 [charconv.from.chars]/1 "The member ptr of the return value points to the
475 // first character not matching the pattern, or has the value last if all characters match."
476 test_from_chars<T>("11", base, 2, errc{}, static_cast<T>(base + 1));
477 test_from_chars<T>("11@@@", base, 2, errc{}, static_cast<T>(base + 1));
478
479 // When overflowing, we need to keep consuming valid digits, in order to return ptr correctly.
480 test_from_chars<T>(string(100, '1'), base, 100, out_ran);
481 test_from_chars<T>(string(100, '1') + "@@@"s, base, 100, out_ran);
482
483 if constexpr (is_signed_v<T>) {
484 test_from_chars<T>("-"s + string(100, '1'), base, 101, out_ran);
485 test_from_chars<T>("-"s + string(100, '1') + "@@@"s, base, 101, out_ran);
486 }
487 }
488
489 // N4713 23.20.3 [charconv.from.chars]/3 "The pattern is the expected form of the subject sequence
490 // in the "C" locale for the given nonzero base, as described for strtol"
491 // C11 7.22.1.4/3 "The letters from a (or A) through z (or Z) are ascribed the values 10 through 35"
492 for (int i = 0; i < 26; ++i) {
493 test_from_chars<T>(string(1, static_cast<char>('A' + i)), 36, 1, errc{}, static_cast<T>(10 + i));
494 test_from_chars<T>(string(1, static_cast<char>('a' + i)), 36, 1, errc{}, static_cast<T>(10 + i));
495 }
496
497 // N4713 23.20.3 [charconv.from.chars]/3 "no "0x" or "0X" prefix shall appear if the value of base is 16"
498 test_from_chars<T>("0x1729", 16, 1, errc{}, static_cast<T>(0)); // reads '0', stops at 'x'
499 test_from_chars<T>("0X1729", 16, 1, errc{}, static_cast<T>(0)); // reads '0', stops at 'X'
500
501 if constexpr (is_signed_v<T>) {
502 test_from_chars<T>("-0x1729", 16, 2, errc{}, static_cast<T>(0)); // reads "-0", stops at 'x'
503 test_from_chars<T>("-0X1729", 16, 2, errc{}, static_cast<T>(0)); // reads "-0", stops at 'X'
504 }
505}
506
507template <typename T>
508void test_integer() {
509 test_integer_to_chars<T>();
510 test_integer_from_chars<T>();
511}
512
513void all_integer_tests() {
514 test_integer<char>();
515 test_integer<signed char>();
516 test_integer<unsigned char>();
517 test_integer<short>();
518 test_integer<unsigned short>();
519 test_integer<int>();
520 test_integer<unsigned int>();
521 test_integer<long>();
522 test_integer<unsigned long>();
523 test_integer<long long>();
524 test_integer<unsigned long long>();
525
526 // Test overflow scenarios.
527 test_from_chars<unsigned int>(input: "4294967289", base_or_fmt: 10, correct_idx: 10, correct_ec: errc{}, opt_correct: 4294967289U); // not risky
528 test_from_chars<unsigned int>(input: "4294967294", base_or_fmt: 10, correct_idx: 10, correct_ec: errc{}, opt_correct: 4294967294U); // risky with good digit
529 test_from_chars<unsigned int>(input: "4294967295", base_or_fmt: 10, correct_idx: 10, correct_ec: errc{}, opt_correct: 4294967295U); // risky with max digit
530 test_from_chars<unsigned int>(input: "4294967296", base_or_fmt: 10, correct_idx: 10, correct_ec: out_ran); // risky with bad digit
531 test_from_chars<unsigned int>(input: "4294967300", base_or_fmt: 10, correct_idx: 10, correct_ec: out_ran); // beyond risky
532
533 test_from_chars<int>(input: "2147483639", base_or_fmt: 10, correct_idx: 10, correct_ec: errc{}, opt_correct: 2147483639); // not risky
534 test_from_chars<int>(input: "2147483646", base_or_fmt: 10, correct_idx: 10, correct_ec: errc{}, opt_correct: 2147483646); // risky with good digit
535 test_from_chars<int>(input: "2147483647", base_or_fmt: 10, correct_idx: 10, correct_ec: errc{}, opt_correct: 2147483647); // risky with max digit
536 test_from_chars<int>(input: "2147483648", base_or_fmt: 10, correct_idx: 10, correct_ec: out_ran); // risky with bad digit
537 test_from_chars<int>(input: "2147483650", base_or_fmt: 10, correct_idx: 10, correct_ec: out_ran); // beyond risky
538
539 test_from_chars<int>(input: "-2147483639", base_or_fmt: 10, correct_idx: 11, correct_ec: errc{}, opt_correct: -2147483639); // not risky
540 test_from_chars<int>(input: "-2147483647", base_or_fmt: 10, correct_idx: 11, correct_ec: errc{}, opt_correct: -2147483647); // risky with good digit
541 test_from_chars<int>(input: "-2147483648", base_or_fmt: 10, correct_idx: 11, correct_ec: errc{}, opt_correct: -2147483647 - 1); // risky with max digit
542 test_from_chars<int>(input: "-2147483649", base_or_fmt: 10, correct_idx: 11, correct_ec: out_ran); // risky with bad digit
543 test_from_chars<int>(input: "-2147483650", base_or_fmt: 10, correct_idx: 11, correct_ec: out_ran); // beyond risky
544}
545
546void assert_message_bits(const bool b, const char* const msg, const std::uint32_t bits) {
547 if (!b) {
548 fprintf(stderr, format: "%s failed for 0x%08zX\n", msg, static_cast<std::size_t>(bits));
549 fprintf(stderr, format: "This is a randomized test.\n");
550 fprintf(stderr, format: "DO NOT IGNORE/RERUN THIS FAILURE.\n");
551 fprintf(stderr, format: "You must report it to the STL maintainers.\n");
552 abort();
553 }
554}
555
556void assert_message_bits(const bool b, const char* const msg, const std::uint64_t bits) {
557 if (!b) {
558 // libc++ uses long for 64-bit values.
559 fprintf(stderr, format: "%s failed for 0x%016llX\n", msg, static_cast<unsigned long long>(bits));
560 fprintf(stderr, format: "This is a randomized test.\n");
561 fprintf(stderr, format: "DO NOT IGNORE/RERUN THIS FAILURE.\n");
562 fprintf(stderr, format: "You must report it to the STL maintainers.\n");
563 abort();
564 }
565}
566
567constexpr std::uint32_t FractionBits = 10; // Tunable for test coverage vs. performance.
568static_assert(FractionBits >= 1, "Must test at least 1 fraction bit.");
569static_assert(FractionBits <= 23, "There are only 23 fraction bits in a float.");
570
571constexpr std::uint32_t Fractions = 1U << FractionBits;
572constexpr std::uint32_t Mask32 = ~((1U << FractionBits) - 1U);
573constexpr std::uint64_t Mask64 = ~((1ULL << FractionBits) - 1ULL);
574
575constexpr std::uint32_t PrefixesToTest = 100; // Tunable for test coverage vs. performance.
576static_assert(PrefixesToTest >= 1, "Must test at least 1 prefix.");
577
578constexpr std::uint32_t PrefixLimit = 2 // sign bit
579 * 255 // non-INF/NAN exponents for float
580 * (1U << (23 - FractionBits)); // fraction bits in prefix
581static_assert(PrefixesToTest <= PrefixLimit, "Too many prefixes.");
582
583template <bool IsDouble>
584void test_floating_prefix(const conditional_t<IsDouble, std::uint64_t, std::uint32_t> prefix) {
585
586 using UIntType = conditional_t<IsDouble, std::uint64_t, std::uint32_t>;
587 using FloatingType = conditional_t<IsDouble, double, float>;
588
589 // "-1.2345678901234567e-100" or "-1.23456789e-10"
590 constexpr std::size_t buffer_size = IsDouble ? 24 : 15;
591 char buffer[buffer_size];
592// TODO Enable once std::from_chars has floating point support.
593#if 0
594 FloatingType val;
595#endif
596
597 // Exact sizes are difficult to prove for fixed notation.
598 // This must be at least (IsDouble ? 327 : 48), and I suspect that that's exact.
599 // Here's a loose upper bound:
600 // 1 character for a negative sign
601 // + 325 (for double; 46 for float) characters in the "0.000~~~000" prefix of the min subnormal
602 // + 17 (for double; 9 for float) characters for round-trip digits
603 constexpr std::size_t fixed_buffer_size = IsDouble ? 1 + 325 + 17 : 1 + 46 + 9;
604 char fixed_buffer[fixed_buffer_size];
605
606 // worst case: negative sign + max normal + null terminator
607 constexpr std::size_t stdio_buffer_size = 1 + (IsDouble ? 309 : 39) + 1;
608 char stdio_buffer[stdio_buffer_size];
609
610 for (std::uint32_t frac = 0; frac < Fractions; ++frac) {
611 const UIntType bits = prefix + frac;
612 const FloatingType input = _Bit_cast<FloatingType>(bits);
613
614 {
615 const auto to_result = to_chars(buffer, end(buffer), input, chars_format::scientific);
616 assert_message_bits(to_result.ec == errc{}, "to_result.ec", bits);
617// TODO Enable once std::from_chars has floating point support.
618#if 0
619 const char* const last = to_result.ptr;
620
621 const auto from_result = from_chars(buffer, last, val);
622
623 assert_message_bits(from_result.ptr == last, "from_result.ptr", bits);
624 assert_message_bits(from_result.ec == errc{}, "from_result.ec", bits);
625 assert_message_bits(_Bit_cast<UIntType>(val) == bits, "round-trip", bits);
626#endif
627 }
628
629 {
630 // Also verify that to_chars() and sprintf_s() emit the same output for integers in fixed notation.
631 const auto fixed_result = to_chars(fixed_buffer, end(fixed_buffer), input, chars_format::fixed);
632 assert_message_bits(fixed_result.ec == errc{}, "fixed_result.ec", bits);
633 const string_view fixed_sv(fixed_buffer, static_cast<std::size_t>(fixed_result.ptr - fixed_buffer));
634
635 if (find(first: fixed_sv.begin(), last: fixed_sv.end(), val: '.') == fixed_sv.end()) {
636 const int stdio_ret = sprintf_s(stdio_buffer, size(stdio_buffer), "%.0f", input);
637 assert_message_bits(stdio_ret != -1, "stdio_ret", bits);
638 const string_view stdio_sv(stdio_buffer);
639 assert_message_bits(fixed_sv == stdio_sv, "fixed_sv", bits);
640 }
641 }
642 }
643}
644
645template <bool IsDouble>
646void test_floating_hex_prefix(const conditional_t<IsDouble, std::uint64_t, std::uint32_t> prefix) {
647
648 using UIntType = conditional_t<IsDouble, std::uint64_t, std::uint32_t>;
649 using FloatingType = conditional_t<IsDouble, double, float>;
650
651 // The precision is the number of hexits after the decimal point.
652 // These hexits correspond to the explicitly stored fraction bits.
653 // double explicitly stores 52 fraction bits. 52 / 4 == 13, so we need 13 hexits.
654 // float explicitly stores 23 fraction bits. 23 / 4 == 5.75, so we need 6 hexits.
655
656 // "-1.fffffffffffffp+1023" or "-1.fffffep+127"
657 constexpr std::size_t buffer_size = IsDouble ? 22 : 14;
658 char buffer[buffer_size];
659// TODO Enable once std::from_chars has floating point support.
660#if 0
661 FloatingType val;
662#endif
663
664 for (std::uint32_t frac = 0; frac < Fractions; ++frac) {
665 const UIntType bits = prefix + frac;
666 const FloatingType input = _Bit_cast<FloatingType>(bits);
667
668 const auto to_result = to_chars(buffer, end(buffer), input, chars_format::hex);
669 assert_message_bits(to_result.ec == errc{}, "(hex) to_result.ec", bits);
670// TODO Enable once std::from_chars has floating point support.
671#if 0
672 const char* const last = to_result.ptr;
673
674 const auto from_result = from_chars(buffer, last, val, chars_format::hex);
675
676 assert_message_bits(from_result.ptr == last, "(hex) from_result.ptr", bits);
677 assert_message_bits(from_result.ec == errc{}, "(hex) from_result.ec", bits);
678 assert_message_bits(_Bit_cast<UIntType>(val) == bits, "(hex) round-trip", bits);
679#endif
680 }
681}
682
683template <bool IsDouble>
684void test_floating_precision_prefix(const conditional_t<IsDouble, std::uint64_t, std::uint32_t> prefix) {
685
686 using UIntType = conditional_t<IsDouble, std::uint64_t, std::uint32_t>;
687 using FloatingType = conditional_t<IsDouble, double, float>;
688
689 // Precision for min subnormal in fixed notation. (More than enough for scientific notation.)
690 constexpr int precision = IsDouble ? 1074 : 149;
691
692 // Number of digits for max normal in fixed notation.
693 constexpr int max_integer_length = IsDouble ? 309 : 39;
694
695 // Size for fixed notation. (More than enough for scientific notation.)
696 constexpr std::size_t charconv_buffer_size = 1 // negative sign
697 + max_integer_length // integer digits
698 + 1 // decimal point
699 + precision; // fractional digits
700 char charconv_buffer[charconv_buffer_size];
701
702 constexpr std::size_t stdio_buffer_size = charconv_buffer_size + 1; // null terminator
703 char stdio_buffer[stdio_buffer_size];
704
705 // 1 character for a negative sign
706 // + worst cases: 0x1.fffffffffffffp-1022 and 0x1.fffffep-126f
707 constexpr std::size_t general_buffer_size = 1 + (IsDouble ? 773 : 117);
708 char general_buffer[general_buffer_size];
709 char general_stdio_buffer[general_buffer_size + 1]; // + null terminator
710
711 for (std::uint32_t frac = 0; frac < Fractions; ++frac) {
712 const UIntType bits = prefix + frac;
713 const FloatingType input = _Bit_cast<FloatingType>(bits);
714
715 auto result = to_chars(charconv_buffer, end(charconv_buffer), input, chars_format::fixed, precision);
716 assert_message_bits(result.ec == errc{}, "to_chars fixed precision", bits);
717 string_view charconv_sv(charconv_buffer, static_cast<std::size_t>(result.ptr - charconv_buffer));
718
719 int stdio_ret = sprintf_s(stdio_buffer, size(stdio_buffer), "%.*f", precision, input);
720 assert_message_bits(stdio_ret != -1, "sprintf_s fixed precision", bits);
721 string_view stdio_sv(stdio_buffer);
722
723 assert_message_bits(charconv_sv == stdio_sv, "fixed precision output", bits);
724
725
726 result = to_chars(charconv_buffer, end(charconv_buffer), input, chars_format::scientific, precision);
727 assert_message_bits(result.ec == errc{}, "to_chars scientific precision", bits);
728 charconv_sv = string_view(charconv_buffer, static_cast<std::size_t>(result.ptr - charconv_buffer));
729
730 stdio_ret = sprintf_s(stdio_buffer, size(stdio_buffer), "%.*e", precision, input);
731 assert_message_bits(stdio_ret != -1, "sprintf_s scientific precision", bits);
732 stdio_sv = stdio_buffer;
733
734 assert_message_bits(charconv_sv == stdio_sv, "scientific precision output", bits);
735
736
737 result = to_chars(general_buffer, end(general_buffer), input, chars_format::general, 5000);
738 assert_message_bits(result.ec == errc{}, "to_chars general precision", bits);
739 charconv_sv = string_view(general_buffer, static_cast<std::size_t>(result.ptr - general_buffer));
740
741 stdio_ret = sprintf_s(general_stdio_buffer, size(general_stdio_buffer), "%.5000g", input);
742 assert_message_bits(stdio_ret != -1, "sprintf_s general precision", bits);
743 stdio_sv = general_stdio_buffer;
744
745 assert_message_bits(charconv_sv == stdio_sv, "general precision output", bits);
746 }
747}
748
749void test_floating_prefixes(mt19937_64& mt64) {
750 {
751 set<std::uint64_t> prefixes64;
752
753 while (prefixes64.size() < PrefixesToTest) {
754 const std::uint64_t val = mt64();
755
756 if ((val & 0x7FF0000000000000ULL) != 0x7FF0000000000000ULL) { // skip INF/NAN
757 prefixes64.insert(x: val & Mask64);
758 }
759 }
760
761 for (const auto& prefix : prefixes64) {
762 test_floating_prefix<true>(prefix);
763 test_floating_precision_prefix<true>(prefix);
764 }
765
766 test_floating_hex_prefix<true>(prefix: *prefixes64.begin()); // save time by testing fewer hexfloats
767 }
768
769 {
770 set<std::uint32_t> prefixes32;
771
772 while (prefixes32.size() < PrefixesToTest) {
773 const std::uint32_t val = static_cast<std::uint32_t>(mt64());
774
775 if ((val & 0x7F800000U) != 0x7F800000U) { // skip INF/NAN
776 prefixes32.insert(x: val & Mask32);
777 }
778 }
779
780 for (const auto& prefix : prefixes32) {
781 test_floating_prefix<false>(prefix);
782 test_floating_precision_prefix<false>(prefix);
783 }
784
785 test_floating_hex_prefix<false>(prefix: *prefixes32.begin()); // save time by testing fewer hexfloats
786 }
787}
788
789// TODO Enable once std::from_chars has floating point support.
790#if 0
791template <typename T>
792void test_floating_from_chars(const chars_format fmt) {
793 test_from_chars<T>("", fmt, 0, inv_arg); // no characters
794 test_from_chars<T>("@1", fmt, 0, inv_arg); // '@' is bogus
795 test_from_chars<T>("z1", fmt, 0, inv_arg); // 'z' is bogus
796 test_from_chars<T>(".", fmt, 0, inv_arg); // '.' without digits is bogus
797 test_from_chars<T>("+1", fmt, 0, inv_arg); // '+' is bogus
798 test_from_chars<T>(" 1", fmt, 0, inv_arg); // ' ' is bogus
799 test_from_chars<T>("p5", fmt, 0, inv_arg); // binary-exponent-part without digits is bogus
800 test_from_chars<T>("in", fmt, 0, inv_arg); // incomplete inf is bogus
801 test_from_chars<T>("na", fmt, 0, inv_arg); // incomplete nan is bogus
802
803 test_from_chars<T>("-", fmt, 0, inv_arg); // '-' followed by no characters
804 test_from_chars<T>("-@1", fmt, 0, inv_arg); // '-' followed by bogus '@'
805 test_from_chars<T>("-z1", fmt, 0, inv_arg); // '-' followed by bogus 'z'
806 test_from_chars<T>("-.", fmt, 0, inv_arg); // '-' followed by bogus '.'
807 test_from_chars<T>("-+1", fmt, 0, inv_arg); // '-' followed by bogus '+'
808 test_from_chars<T>("- 1", fmt, 0, inv_arg); // '-' followed by bogus ' '
809 test_from_chars<T>("-p5", fmt, 0, inv_arg); // '-' followed by bogus binary-exponent-part
810 test_from_chars<T>("-in", fmt, 0, inv_arg); // '-' followed by bogus incomplete inf
811 test_from_chars<T>("-na", fmt, 0, inv_arg); // '-' followed by bogus incomplete nan
812 test_from_chars<T>("--1", fmt, 0, inv_arg); // '-' can't be repeated
813
814 if (fmt != chars_format::hex) { // "e5" are valid hexits
815 test_from_chars<T>("e5", fmt, 0, inv_arg); // exponent-part without digits is bogus
816 test_from_chars<T>("-e5", fmt, 0, inv_arg); // '-' followed by bogus exponent-part
817 }
818
819 constexpr T inf = numeric_limits<T>::infinity();
820 constexpr T qnan = numeric_limits<T>::quiet_NaN();
821
822 test_from_chars<T>("InF", fmt, 3, errc{}, inf);
823 test_from_chars<T>("infinite", fmt, 3, errc{}, inf);
824 test_from_chars<T>("iNfInItY", fmt, 8, errc{}, inf);
825 test_from_chars<T>("InfinityMeow", fmt, 8, errc{}, inf);
826
827 test_from_chars<T>("-InF", fmt, 4, errc{}, -inf);
828 test_from_chars<T>("-infinite", fmt, 4, errc{}, -inf);
829 test_from_chars<T>("-iNfInItY", fmt, 9, errc{}, -inf);
830 test_from_chars<T>("-InfinityMeow", fmt, 9, errc{}, -inf);
831
832 test_from_chars<T>("NaN", fmt, 3, errc{}, qnan);
833 test_from_chars<T>("nanotech", fmt, 3, errc{}, qnan);
834 test_from_chars<T>("nan(", fmt, 3, errc{}, qnan);
835 test_from_chars<T>("nan(@)", fmt, 3, errc{}, qnan);
836 test_from_chars<T>("nan(()", fmt, 3, errc{}, qnan);
837 test_from_chars<T>("nan(abc", fmt, 3, errc{}, qnan);
838 test_from_chars<T>("nan()", fmt, 5, errc{}, qnan);
839 test_from_chars<T>("nan(abc)def", fmt, 8, errc{}, qnan);
840 test_from_chars<T>("nan(_09AZaz)", fmt, 12, errc{}, qnan);
841 test_from_chars<T>("nan(int)", fmt, 8, errc{}, qnan);
842 test_from_chars<T>("nan(snap)", fmt, 9, errc{}, qnan);
843
844 test_from_chars<T>("-NaN", fmt, 4, errc{}, -qnan);
845 test_from_chars<T>("-nanotech", fmt, 4, errc{}, -qnan);
846 test_from_chars<T>("-nan(", fmt, 4, errc{}, -qnan);
847 test_from_chars<T>("-nan(@)", fmt, 4, errc{}, -qnan);
848 test_from_chars<T>("-nan(()", fmt, 4, errc{}, -qnan);
849 test_from_chars<T>("-nan(abc", fmt, 4, errc{}, -qnan);
850 test_from_chars<T>("-nan()", fmt, 6, errc{}, -qnan);
851 test_from_chars<T>("-nan(abc)def", fmt, 9, errc{}, -qnan);
852 test_from_chars<T>("-nan(_09AZaz)", fmt, 13, errc{}, -qnan);
853 test_from_chars<T>("-nan(int)", fmt, 9, errc{}, -qnan);
854 test_from_chars<T>("-nan(snap)", fmt, 10, errc{}, -qnan);
855
856 // The UCRT considers indeterminate NaN to be negative quiet NaN with no payload bits set.
857 // It parses "nan(ind)" and "-nan(ind)" identically.
858 test_from_chars<T>("nan(InD)", fmt, 8, errc{}, -qnan);
859 test_from_chars<T>("-nan(InD)", fmt, 9, errc{}, -qnan);
860
861 test_from_chars<T>("nan(SnAn)", fmt, 9, errc{}, nullopt, TestFromCharsMode::SignalingNaN);
862 test_from_chars<T>("-nan(SnAn)", fmt, 10, errc{}, nullopt, TestFromCharsMode::SignalingNaN);
863
864 switch (fmt) {
865 case chars_format::general:
866 test_from_chars<T>("1729", fmt, 4, errc{}, T{1729});
867 test_from_chars<T>("1729e3", fmt, 6, errc{}, T{1729000});
868 test_from_chars<T>("10", fmt, 2, errc{}, T{10});
869 test_from_chars<T>("11.", fmt, 3, errc{}, T{11});
870 test_from_chars<T>("12.13", fmt, 5, errc{}, static_cast<T>(12.13)); // avoid truncation warning
871 test_from_chars<T>(".14", fmt, 3, errc{}, static_cast<T>(.14)); // avoid truncation warning
872 test_from_chars<T>("20e5", fmt, 4, errc{}, T{2000000});
873 test_from_chars<T>("21.e5", fmt, 5, errc{}, T{2100000});
874 test_from_chars<T>("22.23e5", fmt, 7, errc{}, T{2223000});
875 test_from_chars<T>(".24e5", fmt, 5, errc{}, T{24000});
876 test_from_chars<T>("33e+5", fmt, 5, errc{}, T{3300000});
877 test_from_chars<T>("33e-5", fmt, 5, errc{}, static_cast<T>(.00033)); // avoid truncation warning
878 test_from_chars<T>("4E7", fmt, 3, errc{}, T{40000000});
879 test_from_chars<T>("-00123abc", fmt, 6, errc{}, T{-123});
880 test_from_chars<T>(".0045000", fmt, 8, errc{}, static_cast<T>(.0045)); // avoid truncation warning
881 test_from_chars<T>("000", fmt, 3, errc{}, T{0});
882 test_from_chars<T>("0e9999", fmt, 6, errc{}, T{0});
883 test_from_chars<T>("0e-9999", fmt, 7, errc{}, T{0});
884 test_from_chars<T>("-000", fmt, 4, errc{}, T{-0.0});
885 test_from_chars<T>("-0e9999", fmt, 7, errc{}, T{-0.0});
886 test_from_chars<T>("-0e-9999", fmt, 8, errc{}, T{-0.0});
887 test_from_chars<T>("1e9999", fmt, 6, errc::result_out_of_range, inf);
888 test_from_chars<T>("-1e9999", fmt, 7, errc::result_out_of_range, -inf);
889 test_from_chars<T>("1e-9999", fmt, 7, errc::result_out_of_range, T{0});
890 test_from_chars<T>("-1e-9999", fmt, 8, errc::result_out_of_range, T{-0.0});
891 test_from_chars<T>("1" + string(6000, '0'), fmt, 6001, errc::result_out_of_range, inf);
892 test_from_chars<T>("-1" + string(6000, '0'), fmt, 6002, errc::result_out_of_range, -inf);
893 test_from_chars<T>("." + string(6000, '0') + "1", fmt, 6002, errc::result_out_of_range, T{0});
894 test_from_chars<T>("-." + string(6000, '0') + "1", fmt, 6003, errc::result_out_of_range, T{-0.0});
895 test_from_chars<T>("1" + string(500, '0'), fmt, 501, errc::result_out_of_range, inf);
896 test_from_chars<T>("-1" + string(500, '0'), fmt, 502, errc::result_out_of_range, -inf);
897 test_from_chars<T>("." + string(500, '0') + "1", fmt, 502, errc::result_out_of_range, T{0});
898 test_from_chars<T>("-." + string(500, '0') + "1", fmt, 503, errc::result_out_of_range, T{-0.0});
899 break;
900 case chars_format::scientific:
901 test_from_chars<T>("1729", fmt, 0, inv_arg);
902 test_from_chars<T>("1729e3", fmt, 6, errc{}, T{1729000});
903 break;
904 case chars_format::fixed:
905 test_from_chars<T>("1729", fmt, 4, errc{}, T{1729});
906 test_from_chars<T>("1729e3", fmt, 4, errc{}, T{1729});
907 break;
908 case chars_format::hex:
909 test_from_chars<T>("0x123", fmt, 1, errc{}, T{0});
910 test_from_chars<T>("a0", fmt, 2, errc{}, T{160});
911 test_from_chars<T>("a1.", fmt, 3, errc{}, T{161});
912 test_from_chars<T>("a2.a3", fmt, 5, errc{}, T{162.63671875});
913 test_from_chars<T>(".a4", fmt, 3, errc{}, T{0.640625});
914 test_from_chars<T>("a0p5", fmt, 4, errc{}, T{5120});
915 test_from_chars<T>("a1.p5", fmt, 5, errc{}, T{5152});
916 test_from_chars<T>("a2.a3p5", fmt, 7, errc{}, T{5204.375});
917 test_from_chars<T>(".a4p5", fmt, 5, errc{}, T{20.5});
918 test_from_chars<T>("a0p+5", fmt, 5, errc{}, T{5120});
919 test_from_chars<T>("a0p-5", fmt, 5, errc{}, T{5});
920 test_from_chars<T>("ABCDEFP3", fmt, 8, errc{}, T{90075000});
921 test_from_chars<T>("-00cdrom", fmt, 5, errc{}, T{-205});
922 test_from_chars<T>(".00ef000", fmt, 8, errc{}, T{0.0036468505859375});
923 test_from_chars<T>("000", fmt, 3, errc{}, T{0});
924 test_from_chars<T>("0p9999", fmt, 6, errc{}, T{0});
925 test_from_chars<T>("0p-9999", fmt, 7, errc{}, T{0});
926 test_from_chars<T>("-000", fmt, 4, errc{}, T{-0.0});
927 test_from_chars<T>("-0p9999", fmt, 7, errc{}, T{-0.0});
928 test_from_chars<T>("-0p-9999", fmt, 8, errc{}, T{-0.0});
929 test_from_chars<T>("1p9999", fmt, 6, errc::result_out_of_range, inf);
930 test_from_chars<T>("-1p9999", fmt, 7, errc::result_out_of_range, -inf);
931 test_from_chars<T>("1p-9999", fmt, 7, errc::result_out_of_range, T{0});
932 test_from_chars<T>("-1p-9999", fmt, 8, errc::result_out_of_range, T{-0.0});
933 test_from_chars<T>("1" + string(2000, '0'), fmt, 2001, errc::result_out_of_range, inf);
934 test_from_chars<T>("-1" + string(2000, '0'), fmt, 2002, errc::result_out_of_range, -inf);
935 test_from_chars<T>("." + string(2000, '0') + "1", fmt, 2002, errc::result_out_of_range, T{0});
936 test_from_chars<T>("-." + string(2000, '0') + "1", fmt, 2003, errc::result_out_of_range, T{-0.0});
937 test_from_chars<T>("1" + string(300, '0'), fmt, 301, errc::result_out_of_range, inf);
938 test_from_chars<T>("-1" + string(300, '0'), fmt, 302, errc::result_out_of_range, -inf);
939 test_from_chars<T>("." + string(300, '0') + "1", fmt, 302, errc::result_out_of_range, T{0});
940 test_from_chars<T>("-." + string(300, '0') + "1", fmt, 303, errc::result_out_of_range, T{-0.0});
941 break;
942 }
943}
944#endif
945
946template <typename T>
947void test_floating_to_chars(
948 const T value, const optional<chars_format> opt_fmt, const optional<int> opt_precision, const string_view correct) {
949
950 test_common_to_chars(value, opt_fmt, opt_precision, correct);
951}
952
953void all_floating_tests(mt19937_64& mt64) {
954 test_floating_prefixes(mt64);
955
956// TODO Enable once std::from_chars has floating point support.
957#if 0
958 for (const auto& fmt : {chars_format::general, chars_format::scientific, chars_format::fixed, chars_format::hex}) {
959 test_floating_from_chars<float>(fmt);
960 test_floating_from_chars<double>(fmt);
961 }
962
963 // Test rounding.
964
965 // See float_from_chars_test_cases.hpp in this directory.
966 for (const auto& t : float_from_chars_test_cases) {
967 test_from_chars<float>(t.input, t.fmt, t.correct_idx, t.correct_ec, t.correct_value);
968 }
969
970 // See double_from_chars_test_cases.hpp in this directory.
971 for (const auto& t : double_from_chars_test_cases) {
972 test_from_chars<double>(t.input, t.fmt, t.correct_idx, t.correct_ec, t.correct_value);
973 }
974
975 {
976 // See LWG-2403. This number (exactly 0x1.fffffd00000004 in infinite precision) behaves differently
977 // when parsed as double and converted to float, versus being parsed as float directly.
978 const char* const lwg_2403 = "1.999999821186065729339276231257827021181583404541015625";
979 constexpr float correct_float = 0x1.fffffep0f;
980 constexpr double correct_double = 0x1.fffffdp0;
981 constexpr float twice_rounded_float = 0x1.fffffcp0f;
982
983 test_from_chars<float>(lwg_2403, chars_format::general, 56, errc{}, correct_float);
984 test_from_chars<double>(lwg_2403, chars_format::general, 56, errc{}, correct_double);
985 static_assert(static_cast<float>(correct_double) == twice_rounded_float);
986 }
987
988 // See floating_point_test_cases.hpp.
989 for (const auto& p : floating_point_test_cases_float) {
990 test_from_chars<float>(p.first, chars_format::general, strlen(p.first), errc{}, _Bit_cast<float>(p.second));
991 }
992
993 for (const auto& p : floating_point_test_cases_double) {
994 test_from_chars<double>(p.first, chars_format::general, strlen(p.first), errc{}, _Bit_cast<double>(p.second));
995 }
996#endif
997 // See float_to_chars_test_cases.hpp in this directory.
998 for (const auto& t : float_to_chars_test_cases) {
999 if (t.fmt == chars_format{}) {
1000 test_floating_to_chars(value: t.value, opt_fmt: nullopt, opt_precision: nullopt, correct: t.correct);
1001 } else {
1002 test_floating_to_chars(value: t.value, opt_fmt: t.fmt, opt_precision: nullopt, correct: t.correct);
1003 }
1004 }
1005
1006 // See double_to_chars_test_cases.hpp in this directory.
1007 for (const auto& t : double_to_chars_test_cases) {
1008 if (t.fmt == chars_format{}) {
1009 test_floating_to_chars(value: t.value, opt_fmt: nullopt, opt_precision: nullopt, correct: t.correct);
1010 } else {
1011 test_floating_to_chars(value: t.value, opt_fmt: t.fmt, opt_precision: nullopt, correct: t.correct);
1012 }
1013 }
1014
1015 // See corresponding headers in this directory.
1016 for (const auto& t : float_hex_precision_to_chars_test_cases) {
1017 test_floating_to_chars(value: t.value, opt_fmt: t.fmt, opt_precision: t.precision, correct: t.correct);
1018 }
1019 for (const auto& t : float_fixed_precision_to_chars_test_cases) {
1020 test_floating_to_chars(value: t.value, opt_fmt: t.fmt, opt_precision: t.precision, correct: t.correct);
1021 }
1022 for (const auto& t : float_scientific_precision_to_chars_test_cases) {
1023 test_floating_to_chars(value: t.value, opt_fmt: t.fmt, opt_precision: t.precision, correct: t.correct);
1024 }
1025 for (const auto& t : float_general_precision_to_chars_test_cases) {
1026 test_floating_to_chars(value: t.value, opt_fmt: t.fmt, opt_precision: t.precision, correct: t.correct);
1027 }
1028 for (const auto& t : double_hex_precision_to_chars_test_cases) {
1029 test_floating_to_chars(value: t.value, opt_fmt: t.fmt, opt_precision: t.precision, correct: t.correct);
1030 }
1031 for (const auto& t : double_fixed_precision_to_chars_test_cases_1) {
1032 test_floating_to_chars(value: t.value, opt_fmt: t.fmt, opt_precision: t.precision, correct: t.correct);
1033 }
1034 for (const auto& t : double_fixed_precision_to_chars_test_cases_2) {
1035 test_floating_to_chars(value: t.value, opt_fmt: t.fmt, opt_precision: t.precision, correct: t.correct);
1036 }
1037 for (const auto& t : double_fixed_precision_to_chars_test_cases_3) {
1038 test_floating_to_chars(value: t.value, opt_fmt: t.fmt, opt_precision: t.precision, correct: t.correct);
1039 }
1040 for (const auto& t : double_fixed_precision_to_chars_test_cases_4) {
1041 test_floating_to_chars(value: t.value, opt_fmt: t.fmt, opt_precision: t.precision, correct: t.correct);
1042 }
1043 for (const auto& t : double_scientific_precision_to_chars_test_cases_1) {
1044 test_floating_to_chars(value: t.value, opt_fmt: t.fmt, opt_precision: t.precision, correct: t.correct);
1045 }
1046 for (const auto& t : double_scientific_precision_to_chars_test_cases_2) {
1047 test_floating_to_chars(value: t.value, opt_fmt: t.fmt, opt_precision: t.precision, correct: t.correct);
1048 }
1049 for (const auto& t : double_scientific_precision_to_chars_test_cases_3) {
1050 test_floating_to_chars(value: t.value, opt_fmt: t.fmt, opt_precision: t.precision, correct: t.correct);
1051 }
1052 for (const auto& t : double_scientific_precision_to_chars_test_cases_4) {
1053 test_floating_to_chars(value: t.value, opt_fmt: t.fmt, opt_precision: t.precision, correct: t.correct);
1054 }
1055 for (const auto& t : double_general_precision_to_chars_test_cases) {
1056 test_floating_to_chars(value: t.value, opt_fmt: t.fmt, opt_precision: t.precision, correct: t.correct);
1057 }
1058}
1059
1060int main(int argc, char** argv) {
1061 const auto start = chrono::steady_clock::now();
1062
1063 mt19937_64 mt64;
1064
1065 initialize_randomness(mt64, argc, argv);
1066
1067 all_integer_tests();
1068
1069 all_floating_tests(mt64);
1070
1071 const auto finish = chrono::steady_clock::now();
1072 const long long ms = chrono::duration_cast<chrono::milliseconds>(d: finish - start).count();
1073
1074 puts(s: "PASS");
1075 printf(format: "Randomized test cases: %zu\n", static_cast<std::size_t>(PrefixesToTest * Fractions));
1076 printf(format: "Total time: %lld ms\n", ms);
1077
1078 if (ms < 3'000) {
1079 puts(s: "That was fast. Consider tuning PrefixesToTest and FractionBits to test more cases.");
1080 } else if (ms > 30'000) {
1081 puts(s: "That was slow. Consider tuning PrefixesToTest and FractionBits to test fewer cases.");
1082 }
1083}
1084

source code of libcxx/test/std/utilities/charconv/charconv.msvc/test.cpp