]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/json/test/double.cpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / libs / json / test / double.cpp
1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Official repository: https://github.com/boostorg/json
9 //
10
11 #include <boost/json/stream_parser.hpp>
12 #include <boost/json/parse.hpp>
13 #include <boost/json/serialize.hpp>
14
15 #include <iostream>
16 #include <random>
17 #include <cinttypes>
18
19 #include "parse-vectors.hpp"
20 #include "test.hpp"
21 #include "test_suite.hpp"
22
23 BOOST_JSON_NS_BEGIN
24
25 template<std::size_t N, class... Args>
26 void
27 sprintf(char (&buf)[N],
28 char const* format, Args&&... args)
29 {
30 #ifdef _MSC_VER
31 sprintf_s(buf, format,
32 std::forward<Args>(args)...);
33 #else
34 std::sprintf(buf, format,
35 std::forward<Args>(args)...);
36 #endif
37 }
38
39 class double_test
40 {
41 public:
42 struct f_boost
43 {
44 static
45 string_view
46 name() noexcept
47 {
48 return "boost";
49 }
50
51 double
52 operator()(string_view s) const
53 {
54 BOOST_TEST_CHECKPOINT();
55 error_code ec;
56 stream_parser p;
57 p.write(s.data(), s.size(), ec);
58 if(BOOST_TEST(! ec))
59 p.finish(ec);
60 if(! BOOST_TEST(! ec))
61 return 0;
62 auto const jv = p.release();
63 double const d = jv.as_double();
64 grind_double(s, d);
65 return d;
66 }
67 };
68
69 bool
70 within_1ulp(double x, double y)
71 {
72 std::uint64_t bx, by;
73 std::memcpy(&bx, &x, sizeof(x));
74 std::memcpy(&by, &y, sizeof(y));
75
76 auto diff = bx - by;
77 switch (diff)
78 {
79 case 0:
80 case 1:
81 case 0xffffffffffffffff:
82 return true;
83 default:
84 break;
85 }
86 return false;
87 }
88
89 static
90 value
91 from_string_test(
92 string_view s,
93 storage_ptr sp = {},
94 const parse_options& po = parse_options())
95 {
96 stream_parser p(storage_ptr(), po);
97 error_code ec;
98 p.reset(std::move(sp));
99 p.write(s.data(), s.size(), ec);
100 if(BOOST_TEST(! ec))
101 p.finish(ec);
102 BOOST_TEST(! ec);
103 return p.release();
104 }
105
106 void
107 static
108 check_round_trip(value const& jv1,
109 const parse_options& po = parse_options())
110 {
111 auto const s2 =
112 //to_string_test(jv1); // use this if serializer is broken
113 serialize(jv1);
114 auto jv2 =
115 from_string_test(s2, {}, po);
116 BOOST_TEST(equal(jv1, jv2));
117 }
118
119 template<class F>
120 void
121 static
122 grind_one(
123 string_view s,
124 storage_ptr sp,
125 F const& f,
126 const parse_options& po = parse_options())
127 {
128 auto const jv =
129 from_string_test(s, sp, po);
130 f(jv, po);
131 }
132
133 static
134 void
135 grind_one(string_view s)
136 {
137 auto const jv =
138 from_string_test(s);
139 check_round_trip(jv);
140 }
141
142 template<class F>
143 static
144 void
145 grind(string_view s, F const& f,
146 const parse_options& po = parse_options())
147 {
148 try
149 {
150 grind_one(s, {}, f, po);
151
152 fail_loop([&](storage_ptr const& sp)
153 {
154 grind_one(s, sp, f, po);
155 });
156
157 if(s.size() > 1)
158 {
159 // Destroy the stream_parser at every
160 // split point to check leaks.
161 for(std::size_t i = 1;
162 i < s.size(); ++i)
163 {
164 fail_resource mr;
165 mr.fail_max = 0;
166 stream_parser p(storage_ptr(), po);
167 error_code ec;
168 p.reset(&mr);
169 p.write(s.data(), i, ec);
170 if(BOOST_TEST(! ec))
171 p.write(
172 s.data() + i,
173 s.size() - i, ec);
174 if(BOOST_TEST(! ec))
175 p.finish(ec);
176 if(BOOST_TEST(! ec))
177 f(p.release(), po);
178 }
179 }
180 }
181 catch(std::exception const&)
182 {
183 BOOST_TEST_FAIL();
184 }
185 }
186
187 static
188 void
189 grind(string_view s,
190 const parse_options& po = parse_options())
191 {
192 grind(s,
193 [](value const& jv, const parse_options& po)
194 {
195 check_round_trip(jv, po);
196 }, po);
197 }
198
199 static
200 void
201 grind_double(string_view s, double v)
202 {
203 grind(s,
204 [v](value const& jv, const parse_options&)
205 {
206 if(! BOOST_TEST(jv.is_double()))
207 return;
208 BOOST_TEST(jv.get_double() == v);
209 });
210 }
211
212 // Verify that f converts to the
213 // same double produced by `strtod`.
214 // Requires `s` is not represented by an integral type.
215 template<class F>
216 void
217 fc(std::string const& s, F const& f)
218 {
219 char* str_end;
220 double const need =
221 std::strtod(s.c_str(), &str_end);
222 // BOOST_TEST(str_end == &s.back() + 1);
223 double const got = f(s);
224 auto same = got == need;
225 auto close = same ?
226 true : within_1ulp(got, need);
227
228 if( !BOOST_TEST(close) )
229 {
230 std::cerr << "Failure on '" << s << "': " << got << " != " << need << "\n";
231 }
232 }
233
234 void
235 fc(std::string const& s)
236 {
237 fc(s, f_boost{});
238 fc(s + std::string( 64, ' ' ), f_boost{});
239 }
240
241 void
242 testDouble()
243 {
244 grind_double("-1.010", -1.01);
245 grind_double("-0.010", -0.01);
246 grind_double("-0.0", -0.0);
247 grind_double("-0e0", -0.0);
248 grind_double( "18.4", 18.4);
249 grind_double("-18.4", -18.4);
250 grind_double( "18446744073709551616", 1.8446744073709552e+19);
251 grind_double("-18446744073709551616", -1.8446744073709552e+19);
252 grind_double( "18446744073709551616.0", 1.8446744073709552e+19);
253 grind_double( "18446744073709551616.00009", 1.8446744073709552e+19);
254 grind_double( "1844674407370955161600000", 1.8446744073709552e+24);
255 grind_double("-1844674407370955161600000", -1.8446744073709552e+24);
256 grind_double( "1844674407370955161600000.0", 1.8446744073709552e+24);
257 grind_double( "1844674407370955161600000.00009", 1.8446744073709552e+24);
258 grind_double( "19700720435664.186294290058937593e13", 1.9700720435664185e+26);
259
260 grind_double( "1.0", 1.0);
261 grind_double( "1.1", 1.1);
262 grind_double( "1.11", 1.11);
263 grind_double( "1.11111", 1.11111);
264 grind_double( "11.1111", 11.1111);
265 grind_double( "111.111", 111.111);
266
267 fc("-0.9999999999999999999999");
268 fc("-0.9999999999999999");
269 fc("-0.9007199254740991");
270 fc("-0.999999999999999");
271 fc("-0.99999999999999");
272 fc("-0.9999999999999");
273 fc("-0.999999999999");
274 fc("-0.99999999999");
275 fc("-0.9999999999");
276 fc("-0.999999999");
277 fc("-0.99999999");
278 fc("-0.9999999");
279 fc("-0.999999");
280 fc("-0.99999");
281 fc("-0.9999");
282 fc("-0.8125");
283 fc("-0.999");
284 fc("-0.99");
285 fc("-1.0");
286 fc("-0.9");
287 fc("-0.0");
288 fc("0.0");
289 fc("0.9");
290 fc("0.99");
291 fc("0.999");
292 fc("0.8125");
293 fc("0.9999");
294 fc("0.99999");
295 fc("0.999999");
296 fc("0.9999999");
297 fc("0.99999999");
298 fc("0.999999999");
299 fc("0.9999999999");
300 fc("0.99999999999");
301 fc("0.999999999999");
302 fc("0.9999999999999");
303 fc("0.99999999999999");
304 fc("0.999999999999999");
305 fc("0.9007199254740991");
306 fc("0.9999999999999999");
307 fc("0.9999999999999999999999");
308 fc("0.999999999999999999999999999");
309
310 fc("-1e308");
311 fc("-1e-308");
312 fc("-9999e300");
313 fc("-999e100");
314 fc("-99e10");
315 fc("-9e1");
316 fc("9e1");
317 fc("99e10");
318 fc("999e100");
319 fc("9999e300");
320 fc("999999999999999999.0");
321 fc("999999999999999999999.0");
322 fc("999999999999999999999e5");
323 fc("999999999999999999999.0e5");
324
325 fc("0.00000000000000001");
326
327 fc("-1e-1");
328 fc("-1e0");
329 fc("-1e1");
330 fc("0e0");
331 fc("1e0");
332 fc("1e10");
333
334 fc("0."
335 "00000000000000000000000000000000000000000000000000" // 50 zeroes
336 "1e50");
337 fc("-0."
338 "00000000000000000000000000000000000000000000000000" // 50 zeroes
339 "1e50");
340
341 fc("0."
342 "00000000000000000000000000000000000000000000000000"
343 "00000000000000000000000000000000000000000000000000"
344 "00000000000000000000000000000000000000000000000000"
345 "00000000000000000000000000000000000000000000000000"
346 "00000000000000000000000000000000000000000000000000"
347 "00000000000000000000000000000000000000000000000000"
348 "00000000000000000000000000000000000000000000000000"
349 "00000000000000000000000000000000000000000000000000"
350 "00000000000000000000000000000000000000000000000000"
351 "00000000000000000000000000000000000000000000000000" // 500 zeroes
352 "1e600");
353 fc("-0."
354 "00000000000000000000000000000000000000000000000000"
355 "00000000000000000000000000000000000000000000000000"
356 "00000000000000000000000000000000000000000000000000"
357 "00000000000000000000000000000000000000000000000000"
358 "00000000000000000000000000000000000000000000000000"
359 "00000000000000000000000000000000000000000000000000"
360 "00000000000000000000000000000000000000000000000000"
361 "00000000000000000000000000000000000000000000000000"
362 "00000000000000000000000000000000000000000000000000"
363 "00000000000000000000000000000000000000000000000000" // 500 zeroes
364 "1e600");
365
366 fc("0e"
367 "00000000000000000000000000000000000000000000000000"
368 "00000000000000000000000000000000000000000000000000"
369 "00000000000000000000000000000000000000000000000000"
370 "00000000000000000000000000000000000000000000000000"
371 "00000000000000000000000000000000000000000000000000"
372 "00000000000000000000000000000000000000000000000000"
373 "00000000000000000000000000000000000000000000000000"
374 "00000000000000000000000000000000000000000000000000"
375 "00000000000000000000000000000000000000000000000000"
376 "00000000000000000000000000000000000000000000000000" // 500 zeroes
377 );
378 }
379
380 void checkAccuracy(const char* nm, int max_ulp)
381 {
382 double x = std::strtod( nm, 0 );
383 double y = boost::json::parse( nm ).as_double();
384 std::uint64_t bx, by;
385 std::memcpy( &bx, &x, sizeof(x) );
386 std::memcpy( &by, &y, sizeof(y) );
387 std::int64_t diff = bx - by;
388 if (!BOOST_TEST(std::abs( diff ) <= max_ulp))
389 std::fprintf(stderr,
390 "%s: difference %" PRId64 " ulp\n"
391 " strtod: %.13a %.16g\n"
392 " boost.json: %.13a %.16g\n\n",
393 nm, diff, x, x, y, y );
394 }
395
396 void
397 testWithinULP()
398 {
399 std::mt19937_64 rng;
400
401 checkAccuracy("10199214983525025199.13135016100190689227e-308", 2);
402
403 for( int i = 0; i < 1000000; ++i )
404 {
405 unsigned long long x1 = rng();
406 unsigned long long x2 = rng();
407 int x3 = std::uniform_int_distribution<>( -308, +308 )( rng );
408
409 char buffer[ 128 ];
410 sprintf( buffer, "%llu.%llue%d", x1, x2, x3 );
411
412 checkAccuracy( buffer, 2 );
413 }
414
415 for( int i = -326; i <= +309; ++i )
416 {
417 char buffer[ 128 ];
418 sprintf( buffer, "1e%d", i );
419
420 checkAccuracy( buffer, 0 );
421 }
422 };
423
424 void
425 run()
426 {
427 testDouble();
428 testWithinULP();
429 }
430 };
431
432 TEST_SUITE(double_test, "boost.json.double");
433
434 BOOST_JSON_NS_END