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 | |
49 | using namespace std; |
50 | |
51 | void 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 | |
88 | static_assert((chars_format::scientific & chars_format::fixed) == chars_format{}); |
89 | static_assert((chars_format::scientific & chars_format::hex) == chars_format{}); |
90 | static_assert((chars_format::fixed & chars_format::hex) == chars_format{}); |
91 | static_assert(chars_format::general == (chars_format::fixed | chars_format::scientific)); |
92 | |
93 | template <typename T, typename Optional> |
94 | void 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 = 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 | |
163 | template <typename T> |
164 | void 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}] |
185 | constexpr 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}] |
190 | constexpr std::uint64_t stress_chunks_positive = 12000000345000678900ULL; |
191 | constexpr 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}] |
293 | constexpr std::int64_t stress_chunks_negative = -9000876000000054321LL; |
294 | constexpr 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 | |
353 | template <typename T> |
354 | void 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 | |
382 | enum class TestFromCharsMode { Normal, SignalingNaN }; |
383 | |
384 | template <typename T, typename BaseOrFmt> |
385 | void (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 | |
423 | constexpr errc inv_arg = errc::invalid_argument; |
424 | constexpr errc out_ran = errc::result_out_of_range; |
425 | |
426 | template <typename T> |
427 | void 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 | |
507 | template <typename T> |
508 | void test_integer() { |
509 | test_integer_to_chars<T>(); |
510 | test_integer_from_chars<T>(); |
511 | } |
512 | |
513 | void 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 | |
546 | void 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 | |
556 | void 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 | |
567 | constexpr std::uint32_t FractionBits = 10; // Tunable for test coverage vs. performance. |
568 | static_assert(FractionBits >= 1, "Must test at least 1 fraction bit." ); |
569 | static_assert(FractionBits <= 23, "There are only 23 fraction bits in a float." ); |
570 | |
571 | constexpr std::uint32_t Fractions = 1U << FractionBits; |
572 | constexpr std::uint32_t Mask32 = ~((1U << FractionBits) - 1U); |
573 | constexpr std::uint64_t Mask64 = ~((1ULL << FractionBits) - 1ULL); |
574 | |
575 | constexpr std::uint32_t PrefixesToTest = 100; // Tunable for test coverage vs. performance. |
576 | static_assert(PrefixesToTest >= 1, "Must test at least 1 prefix." ); |
577 | |
578 | constexpr std::uint32_t PrefixLimit = 2 // sign bit |
579 | * 255 // non-INF/NAN exponents for float |
580 | * (1U << (23 - FractionBits)); // fraction bits in prefix |
581 | static_assert(PrefixesToTest <= PrefixLimit, "Too many prefixes." ); |
582 | |
583 | template <bool IsDouble> |
584 | void 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 | |
645 | template <bool IsDouble> |
646 | void 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 | |
683 | template <bool IsDouble> |
684 | void 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 | |
749 | void 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 |
791 | template <typename T> |
792 | void 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 | |
946 | template <typename T> |
947 | void 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 | |
953 | void 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 | |
1060 | int 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 | |