diff --git a/include/boost/json/detail/impl/number.ipp b/include/boost/json/detail/impl/number.ipp deleted file mode 100644 index 73a39d99..00000000 --- a/include/boost/json/detail/impl/number.ipp +++ /dev/null @@ -1,743 +0,0 @@ -// -// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/vinniefalco/json -// - -#ifndef BOOST_JSON_DETAIL_IMPL_NUMBER_IPP -#define BOOST_JSON_DETAIL_IMPL_NUMBER_IPP - -#include -#include - -namespace boost { -namespace json { -namespace detail { - -/* References - - https://ampl.com/netlib/fp/dtoa.c - -*/ -inline -double -pow10(int exp) noexcept -{ - static double const tab[618] = { - 1e-308, 1e-307, 1e-306, 1e-305, 1e-304, 1e-303, 1e-302, 1e-301, - - 1e-300, 1e-299, 1e-298, 1e-297, 1e-296, 1e-295, 1e-294, 1e-293, 1e-292, 1e-291, - 1e-290, 1e-289, 1e-288, 1e-287, 1e-286, 1e-285, 1e-284, 1e-283, 1e-282, 1e-281, - 1e-280, 1e-279, 1e-278, 1e-277, 1e-276, 1e-275, 1e-274, 1e-273, 1e-272, 1e-271, - 1e-270, 1e-269, 1e-268, 1e-267, 1e-266, 1e-265, 1e-264, 1e-263, 1e-262, 1e-261, - 1e-260, 1e-259, 1e-258, 1e-257, 1e-256, 1e-255, 1e-254, 1e-253, 1e-252, 1e-251, - 1e-250, 1e-249, 1e-248, 1e-247, 1e-246, 1e-245, 1e-244, 1e-243, 1e-242, 1e-241, - 1e-240, 1e-239, 1e-238, 1e-237, 1e-236, 1e-235, 1e-234, 1e-233, 1e-232, 1e-231, - 1e-230, 1e-229, 1e-228, 1e-227, 1e-226, 1e-225, 1e-224, 1e-223, 1e-222, 1e-221, - 1e-220, 1e-219, 1e-218, 1e-217, 1e-216, 1e-215, 1e-214, 1e-213, 1e-212, 1e-211, - 1e-210, 1e-209, 1e-208, 1e-207, 1e-206, 1e-205, 1e-204, 1e-203, 1e-202, 1e-201, - - 1e-200, 1e-199, 1e-198, 1e-197, 1e-196, 1e-195, 1e-194, 1e-193, 1e-192, 1e-191, - 1e-190, 1e-189, 1e-188, 1e-187, 1e-186, 1e-185, 1e-184, 1e-183, 1e-182, 1e-181, - 1e-180, 1e-179, 1e-178, 1e-177, 1e-176, 1e-175, 1e-174, 1e-173, 1e-172, 1e-171, - 1e-170, 1e-169, 1e-168, 1e-167, 1e-166, 1e-165, 1e-164, 1e-163, 1e-162, 1e-161, - 1e-160, 1e-159, 1e-158, 1e-157, 1e-156, 1e-155, 1e-154, 1e-153, 1e-152, 1e-151, - 1e-150, 1e-149, 1e-148, 1e-147, 1e-146, 1e-145, 1e-144, 1e-143, 1e-142, 1e-141, - 1e-140, 1e-139, 1e-138, 1e-137, 1e-136, 1e-135, 1e-134, 1e-133, 1e-132, 1e-131, - 1e-130, 1e-129, 1e-128, 1e-127, 1e-126, 1e-125, 1e-124, 1e-123, 1e-122, 1e-121, - 1e-120, 1e-119, 1e-118, 1e-117, 1e-116, 1e-115, 1e-114, 1e-113, 1e-112, 1e-111, - 1e-110, 1e-109, 1e-108, 1e-107, 1e-106, 1e-105, 1e-104, 1e-103, 1e-102, 1e-101, - - 1e-100, 1e-099, 1e-098, 1e-097, 1e-096, 1e-095, 1e-094, 1e-093, 1e-092, 1e-091, - 1e-090, 1e-089, 1e-088, 1e-087, 1e-086, 1e-085, 1e-084, 1e-083, 1e-082, 1e-081, - 1e-080, 1e-079, 1e-078, 1e-077, 1e-076, 1e-075, 1e-074, 1e-073, 1e-072, 1e-071, - 1e-070, 1e-069, 1e-068, 1e-067, 1e-066, 1e-065, 1e-064, 1e-063, 1e-062, 1e-061, - 1e-060, 1e-059, 1e-058, 1e-057, 1e-056, 1e-055, 1e-054, 1e-053, 1e-052, 1e-051, - 1e-050, 1e-049, 1e-048, 1e-047, 1e-046, 1e-045, 1e-044, 1e-043, 1e-042, 1e-041, - 1e-040, 1e-039, 1e-038, 1e-037, 1e-036, 1e-035, 1e-034, 1e-033, 1e-032, 1e-031, - 1e-030, 1e-029, 1e-028, 1e-027, 1e-026, 1e-025, 1e-024, 1e-023, 1e-022, 1e-021, - 1e-020, 1e-019, 1e-018, 1e-017, 1e-016, 1e-015, 1e-014, 1e-013, 1e-012, 1e-011, - 1e-010, 1e-009, 1e-008, 1e-007, 1e-006, 1e-005, 1e-004, 1e-003, 1e-002, 1e-001, - - 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, - 1e+010, 1e+011, 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, - 1e+020, 1e+021, 1e+022, 1e+023, 1e+024, 1e+025, 1e+026, 1e+027, 1e+028, 1e+029, - 1e+030, 1e+031, 1e+032, 1e+033, 1e+034, 1e+035, 1e+036, 1e+037, 1e+038, 1e+039, - 1e+040, 1e+041, 1e+042, 1e+043, 1e+044, 1e+045, 1e+046, 1e+047, 1e+048, 1e+049, - 1e+050, 1e+051, 1e+052, 1e+053, 1e+054, 1e+055, 1e+056, 1e+057, 1e+058, 1e+059, - 1e+060, 1e+061, 1e+062, 1e+063, 1e+064, 1e+065, 1e+066, 1e+067, 1e+068, 1e+069, - 1e+070, 1e+071, 1e+072, 1e+073, 1e+074, 1e+075, 1e+076, 1e+077, 1e+078, 1e+079, - 1e+080, 1e+081, 1e+082, 1e+083, 1e+084, 1e+085, 1e+086, 1e+087, 1e+088, 1e+089, - 1e+090, 1e+091, 1e+092, 1e+093, 1e+094, 1e+095, 1e+096, 1e+097, 1e+098, 1e+099, - - 1e+100, 1e+101, 1e+102, 1e+103, 1e+104, 1e+105, 1e+106, 1e+107, 1e+108, 1e+109, - 1e+110, 1e+111, 1e+112, 1e+113, 1e+114, 1e+115, 1e+116, 1e+117, 1e+118, 1e+119, - 1e+120, 1e+121, 1e+122, 1e+123, 1e+124, 1e+125, 1e+126, 1e+127, 1e+128, 1e+129, - 1e+130, 1e+131, 1e+132, 1e+133, 1e+134, 1e+135, 1e+136, 1e+137, 1e+138, 1e+139, - 1e+140, 1e+141, 1e+142, 1e+143, 1e+144, 1e+145, 1e+146, 1e+147, 1e+148, 1e+149, - 1e+150, 1e+151, 1e+152, 1e+153, 1e+154, 1e+155, 1e+156, 1e+157, 1e+158, 1e+159, - 1e+160, 1e+161, 1e+162, 1e+163, 1e+164, 1e+165, 1e+166, 1e+167, 1e+168, 1e+169, - 1e+170, 1e+171, 1e+172, 1e+173, 1e+174, 1e+175, 1e+176, 1e+177, 1e+178, 1e+179, - 1e+180, 1e+181, 1e+182, 1e+183, 1e+184, 1e+185, 1e+186, 1e+187, 1e+188, 1e+189, - 1e+190, 1e+191, 1e+192, 1e+193, 1e+194, 1e+195, 1e+196, 1e+197, 1e+198, 1e+199, - - 1e+200, 1e+201, 1e+202, 1e+203, 1e+204, 1e+205, 1e+206, 1e+207, 1e+208, 1e+209, - 1e+210, 1e+211, 1e+212, 1e+213, 1e+214, 1e+215, 1e+216, 1e+217, 1e+218, 1e+219, - 1e+220, 1e+221, 1e+222, 1e+223, 1e+224, 1e+225, 1e+226, 1e+227, 1e+228, 1e+229, - 1e+230, 1e+231, 1e+232, 1e+233, 1e+234, 1e+235, 1e+236, 1e+237, 1e+238, 1e+239, - 1e+240, 1e+241, 1e+242, 1e+243, 1e+244, 1e+245, 1e+246, 1e+247, 1e+248, 1e+249, - 1e+250, 1e+251, 1e+252, 1e+253, 1e+254, 1e+255, 1e+256, 1e+257, 1e+258, 1e+259, - 1e+260, 1e+261, 1e+262, 1e+263, 1e+264, 1e+265, 1e+266, 1e+267, 1e+268, 1e+269, - 1e+270, 1e+271, 1e+272, 1e+273, 1e+274, 1e+275, 1e+276, 1e+277, 1e+278, 1e+279, - 1e+280, 1e+281, 1e+282, 1e+283, 1e+284, 1e+285, 1e+286, 1e+287, 1e+288, 1e+289, - 1e+290, 1e+291, 1e+292, 1e+293, 1e+294, 1e+295, 1e+296, 1e+297, 1e+298, 1e+299, - - 1e+300, 1e+301, 1e+302, 1e+303, 1e+304, 1e+305, 1e+306, 1e+307, 1e+308 }; - - if (exp < -308 || exp > 308) - { - return std::pow(10.0, exp); - } - else - { - exp += 308; - BOOST_ASSERT(exp >= 0 && exp < 618); - return tab[exp]; - } -} - -inline -double -dec_to_float( - std::uint64_t m, - std::int32_t e, - bool neg) noexcept -{ - if(neg) - return (-static_cast< - double>(m)) * - pow10(e); - return (static_cast< - double>(m)) * - pow10(e); -} - -// return true on '-' '0' '1'..'9'. -// caller consumes ch on true -bool -number_parser:: -maybe_init(char ch) noexcept -{ - if(ch == '-') - { - n_.u = 0; - n_.kind = kind::int64; - exp_ = 0; - dig_ = 0; - pos_ = -1; - sig_ = 0; - neg_ = true; - st_ = state::init0; - return true; - } - unsigned char const d = ch - '0'; - if(d >= 10) - return false; - n_.u = d; - exp_ = 0; - pos_ = -1; - sig_ = 0; - neg_ = false; - n_.kind = kind::int64; - if(ch == '0') - { - dig_ = 0; - st_ = state::init1; - } - else - { - dig_ = 1; - sig_ = 1; - st_ = state::mant; - } - return true; -} - -size_t -number_parser:: -write_some( - char const* const data, - size_t const size, - error_code& ec) noexcept -{ - auto p = data; - auto const p0 = data; - auto const p1 = data + size; - //ec = {}; - -loop: - switch(st_) - { - case state::init: - if(p >= p1) - break; - if(! maybe_init(*p)) - { - ec = error::not_number; - goto finish; - } - ++p; - goto loop; - - //----------------------------------- - - // [0,1..9] - case state::init0: - { - // got minus sign - BOOST_ASSERT(neg_); - BOOST_ASSERT( - n_.kind == kind::int64); - if(p >= p1) - break; - unsigned char const d = *p - '0'; - if(d >= 10) - { - ec = error::expected_mantissa; - goto finish; - } - ++p; - if(d == 0) - { - st_ = state::init1; - goto loop; - } - n_.u = d; - dig_ = 1; - sig_ = 1; - st_ = state::mantn; - goto loop; - } - - // [.eE] - case state::init1: - { - // got leading 0 - BOOST_ASSERT( - n_.kind == kind::int64); - if(p >= p1) - break; - if(*p == '.') - { - BOOST_ASSERT(pos_ < 0); - BOOST_ASSERT(dig_ == 0); - ++p; - pos_ = 0; - st_ = state::mantf; - n_.kind = kind::double_; - goto do_mantf; - } - if((*p | 32) == 'e') // 'E' or 'e' - { - ++p; - n_.kind = kind::double_; - st_ = state::exp1; - goto loop; - } - unsigned char const d = *p - '0'; - if(d < 10) - { - ec = error::expected_fraction; - goto finish; - } - // reached end of number - st_ = state::end; - goto finish; - } - - // 1*digit - do_mantf: - case state::mantf: - { - if (p >= p1) - break; - unsigned char const d = *p - '0'; - if(d < 10) - { - if(d == 0 && n_.u == 0) - { - ++p; - ++dig_; - st_ = state::zeroes; - goto do_zeroes; - } - if(neg_) - { - st_ = state::mantn; - goto do_mantn; - } - st_ = state::mant; - goto do_mant; - } - - ec = error::expected_fraction; - goto finish; - } - - // *[0] - do_zeroes: - case state::zeroes: - { - BOOST_ASSERT(pos_ == 0); - while(p < p1) - { - unsigned char const d = *p - '0'; - if(d == 0) - { - ++p; - ++dig_; - continue; - } - if(d < 10 || - *p == 'e' || *p == 'E') - { - if(neg_) - st_ = state::mantn; - else - st_ = state::mant; - goto loop; - } - // reached end of number - st_ = state::end; - goto finish; - } - break; - } - - //----------------------------------- - - // *[0..9] - do_mant: - case state::mant: - { - BOOST_ASSERT(! neg_); - if(p >= p1) - break; - auto m = n_.u; - do - { - unsigned char const d = *p - '0'; - if(d < 10) - { - // 18446744073709551615 UINT64_MAX - if( m > 1844674407370955161 || ( - m == 1844674407370955161 && d > 5)) - { - n_.u = m; - goto enter_mantd; - } - ++p; - // VFALCO Check dig_ for overflow - // Could use an implementation-defined limit - // which is lower than USHRT_MAX - ++dig_; - ++sig_; - m = 10 * m + d; - continue; - } - if(*p == '.' && pos_ < 0) - { - ++p; - pos_ = dig_; - n_.kind = kind::double_; - st_ = state::mantf; - n_.u = m; - goto loop; - } - if(*p == 'e' || *p == 'E') - { - // treat 'E' as '.' - if (pos_ < 0) - pos_ = dig_; - ++p; - n_.u = m; - n_.kind = kind::double_; - st_ = state::exp1; - goto loop; - } - // reached end of number - n_.u = m; - finish(ec); - goto finish; - } - while(p < p1); - n_.u = m; - break; - } - - // *[0..9] (negative) - do_mantn: - case state::mantn: - { - BOOST_ASSERT(neg_); - if(p >= p1) - break; - auto m = n_.u; - do - { - unsigned char const d = *p - '0'; - if(d < 10) - { - // 9223372036854775808 INT64_MIN - if( m > 922337203685477580 || ( - m == 922337203685477580 && d > 8)) - { - n_.u = m; - goto enter_mantd; - } - ++p; - // VFALCO Check dig_ for overflow - // Could use an implementation-defined limit - // which is lower than USHRT_MAX - ++sig_; - ++dig_; - m = 10 * m + d; - continue; - } - if(*p == '.' && pos_ < 0) - { - ++p; - pos_ = dig_; - n_.kind = kind::double_; - n_.u = m; - st_ = state::mantf; - goto loop; - } - if(*p == 'e' || *p == 'E') - { - // treat 'E' as '.' - if (pos_ < 0) - pos_ = dig_; - ++p; - n_.u = m; - n_.kind = kind::double_; - st_ = state::exp1; - goto loop; - } - // reached end of number - n_.u = m; - finish(ec); - goto finish; - } - while(p < p1); - n_.u = m; - break; - } - - enter_mantd: - // make sure we are past the - // limit of double precision. - BOOST_ASSERT(sig_ == dig_); - BOOST_ASSERT(dig_ >= 18); - ++p; - // VFALCO Check dig_ for overflow - // Could use an implementation-defined limit - // which is lower than USHRT_MAX - ++dig_; - st_ = state::mantd; - n_.kind = kind::double_; - BOOST_FALLTHROUGH; - - // *[0..9] (double) - case state::mantd: - { - while(p < p1) - { - if(*p == '.' && pos_ < 0) - { - ++p; - pos_ = dig_; - continue; - } - if(*p == 'e' || *p == 'E') - { - // treat 'E' as '.' - if (pos_ < 0) - pos_ = dig_; - ++p; - st_ = state::exp1; - goto loop; - } - unsigned char const d = *p - '0'; - if(d >= 10) - { - // reached end of number - finish(ec); - goto finish; - } - ++p; - // VFALCO Check dig_ for overflow - // Could use an implementation-defined limit - // which is lower than USHRT_MAX - ++dig_; - } - break; - } - - //----------------------------------- - - // [-+,0..9] - case state::exp1: - { - BOOST_ASSERT( - n_.kind == kind::double_); - if(p >= p1) - break; - if(*p == '-') - { - ++p; - eneg_ = true; - } - else - { - if(*p == '+') - ++p; - eneg_ = false; - } - st_ = state::exp2; - BOOST_FALLTHROUGH; - } - - // [0..9] - case state::exp2: - { - if(p >= p1) - break; - unsigned char const d = *p - '0'; - if(d >= 10) - { - ec = error::expected_exponent; - goto finish; - } - ++p; - exp_ = d; - st_ = state::exp3; - BOOST_FALLTHROUGH; - } - - // *[0..9] - case state::exp3: - { - if(p < p1) - { - // VFALCO FIX - auto const lim = 700;//308 - off_; - auto e = exp_; - while(p < p1) - { - unsigned char const d = *p - '0'; - if(d < 10) - { - ++p; - e = 10 * e + d; - if(e > lim) - { - ec = error::exponent_overflow; - goto finish; - } - continue; - } - exp_ = e; - finish(ec); - goto finish; - } - while(p < p1); - exp_ = e; - } - break; - } - - case state::end: - ec = error::extra_data; - break; - } -finish: - return p - p0; -} - -size_t -number_parser:: -write( - char const* data, - size_t size, - error_code& ec) noexcept -{ - auto n = write_some( - data, size, ec); - if(ec) - return n; - if(n < size) - { - n += write_some( - data + n, size - n, ec); - if(ec) - return n; - } - finish(ec); - return n; -} - -void -number_parser:: -finish( - error_code& ec) noexcept -{ - switch(st_) - { - case state::init: - case state::init0: - ec = error::expected_mantissa; - break; - - case state::init1: - BOOST_ASSERT(n_.u == 0); - BOOST_ASSERT( - n_.kind == kind::int64); - //ec = {}; - st_ = state::end; - break; - - case state::zeroes: - BOOST_ASSERT(n_.u == 0); - if(pos_ == dig_) - { - ec = error::expected_fraction; - break; - } - if(pos_ >= 0) - { - BOOST_ASSERT( - n_.kind == kind::double_); - if(neg_) - n_.d = -0.0; - else - n_.d = 0; - } - else - { - BOOST_ASSERT( - n_.kind == kind::int64); - n_.i = 0; - } - st_ = state::end; - break; - - case state::mantf: - ec = error::expected_fraction; - break; - - case state::mant: - BOOST_ASSERT(! neg_); - BOOST_FALLTHROUGH; - case state::mantn: - BOOST_ASSERT(dig_ > 0); - if(pos_ == dig_) - { - ec = error::expected_fraction; - break; - } - if(n_.kind == kind::double_) - { - if( pos_ < 0) - pos_ = dig_; - n_.d = dec_to_float( - n_.u, pos_ - dig_, neg_); - } - else - { - BOOST_ASSERT( - n_.kind == kind::int64); - if(st_ == state::mantn) - { - n_.i = static_cast< - int64_t>(~n_.u+1); - } - else - { - if( n_.u <= INT64_MAX) - n_.i = static_cast< - int64_t>(n_.u); - else - n_.kind = kind::uint64; - } - } - st_ = state::end; - break; - - case state::mantd: - BOOST_ASSERT( - n_.kind == kind::double_); - if(pos_ == dig_) - { - ec = error::expected_fraction; - break; - } - if( pos_ < 0) - pos_ = dig_; - #if 0 - n_.d = static_cast(n_.u) * - pow10(pos_ - sig_); - if(neg_) - n_.d = -n_.d; - n_.d *= pow10(exp_); - #else - n_.d = dec_to_float(n_.u, - pos_ - sig_ + exp_, neg_); - #endif - st_ = state::end; - break; - - case state::exp1: // expected [-,+,0..9] - ec = error::expected_exponent; - break; - - case state::exp2: // expected [0..9] - ec = error::expected_exponent; - break; - - case state::exp3: - { - if (eneg_) - exp_ = -exp_; - - if (pos_ == 0) - { - // abs(mantissa) < 1 - exp_ = static_cast( - exp_ + sig_ - dig_ - 1); - } - else - { - // abs(mantissa) >= 1 - exp_ = static_cast( - exp_ + pos_ - sig_); - } - - n_.d = dec_to_float( - n_.u, exp_, neg_); - st_ = state::end; - break; - } - case state::end: - break; - } -} - -} // detail -} // json -} // boost - -#endif diff --git a/include/boost/json/detail/number.hpp b/include/boost/json/detail/number.hpp deleted file mode 100644 index 02a62b5c..00000000 --- a/include/boost/json/detail/number.hpp +++ /dev/null @@ -1,114 +0,0 @@ -// -// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/vinniefalco/json -// - -#ifndef BOOST_JSON_DETAIL_NUMBER_HPP -#define BOOST_JSON_DETAIL_NUMBER_HPP - -#include -#include -#include -#include -#include - -namespace boost { -namespace json { -namespace detail { - -struct number -{ - union - { - double d; - int64_t i; - uint64_t u; - }; - - json::kind kind; -}; - -//---------------------------------------------------------- - -class number_parser -{ - enum class state - { - init, init0, init1, - mantf, - zeroes, - mant, mantn, mantd, - exp1, exp2, exp3, - end - }; - - number n_; - short exp_; // exponent string as integer - short dig_; // digits in mantissa - short pos_; // position of decimal point - short sig_; // significant digits in mantissa - bool neg_; - bool eneg_; - state st_; - -public: - number_parser() - : st_(state::init) - { - } - - number - get() const noexcept - { - return n_; - } - - bool - is_done() const noexcept - { - return st_ == state::end; - } - - void - reset() - { - st_ = state::init; - } - - BOOST_JSON_DECL - bool - maybe_init(char ch) noexcept; - - BOOST_JSON_DECL - size_t - write_some( - char const* data, - size_t size, - error_code& ec) noexcept; - - BOOST_JSON_DECL - size_t - write( - char const* data, - size_t size, - error_code& ec) noexcept; - - BOOST_JSON_DECL - void - finish( - error_code& ec) noexcept; -}; - -} // detail -} // json -} // boost - -#ifdef BOOST_JSON_HEADER_ONLY -#include -#endif - -#endif diff --git a/include/boost/json/impl/basic_parser.ipp b/include/boost/json/impl/basic_parser.ipp index 904471d1..231b138f 100644 --- a/include/boost/json/impl/basic_parser.ipp +++ b/include/boost/json/impl/basic_parser.ipp @@ -13,9 +13,8 @@ #include #include #include -#include -#include #include +#include namespace boost { namespace json { @@ -48,6 +47,120 @@ enum class basic_parser::state : char //---------------------------------------------------------- +namespace detail { + +/* References + + https://ampl.com/netlib/fp/dtoa.c + +*/ +inline +double +pow10(int exp) noexcept +{ + static double const tab[618] = { + 1e-308, 1e-307, 1e-306, 1e-305, 1e-304, 1e-303, 1e-302, 1e-301, + + 1e-300, 1e-299, 1e-298, 1e-297, 1e-296, 1e-295, 1e-294, 1e-293, 1e-292, 1e-291, + 1e-290, 1e-289, 1e-288, 1e-287, 1e-286, 1e-285, 1e-284, 1e-283, 1e-282, 1e-281, + 1e-280, 1e-279, 1e-278, 1e-277, 1e-276, 1e-275, 1e-274, 1e-273, 1e-272, 1e-271, + 1e-270, 1e-269, 1e-268, 1e-267, 1e-266, 1e-265, 1e-264, 1e-263, 1e-262, 1e-261, + 1e-260, 1e-259, 1e-258, 1e-257, 1e-256, 1e-255, 1e-254, 1e-253, 1e-252, 1e-251, + 1e-250, 1e-249, 1e-248, 1e-247, 1e-246, 1e-245, 1e-244, 1e-243, 1e-242, 1e-241, + 1e-240, 1e-239, 1e-238, 1e-237, 1e-236, 1e-235, 1e-234, 1e-233, 1e-232, 1e-231, + 1e-230, 1e-229, 1e-228, 1e-227, 1e-226, 1e-225, 1e-224, 1e-223, 1e-222, 1e-221, + 1e-220, 1e-219, 1e-218, 1e-217, 1e-216, 1e-215, 1e-214, 1e-213, 1e-212, 1e-211, + 1e-210, 1e-209, 1e-208, 1e-207, 1e-206, 1e-205, 1e-204, 1e-203, 1e-202, 1e-201, + + 1e-200, 1e-199, 1e-198, 1e-197, 1e-196, 1e-195, 1e-194, 1e-193, 1e-192, 1e-191, + 1e-190, 1e-189, 1e-188, 1e-187, 1e-186, 1e-185, 1e-184, 1e-183, 1e-182, 1e-181, + 1e-180, 1e-179, 1e-178, 1e-177, 1e-176, 1e-175, 1e-174, 1e-173, 1e-172, 1e-171, + 1e-170, 1e-169, 1e-168, 1e-167, 1e-166, 1e-165, 1e-164, 1e-163, 1e-162, 1e-161, + 1e-160, 1e-159, 1e-158, 1e-157, 1e-156, 1e-155, 1e-154, 1e-153, 1e-152, 1e-151, + 1e-150, 1e-149, 1e-148, 1e-147, 1e-146, 1e-145, 1e-144, 1e-143, 1e-142, 1e-141, + 1e-140, 1e-139, 1e-138, 1e-137, 1e-136, 1e-135, 1e-134, 1e-133, 1e-132, 1e-131, + 1e-130, 1e-129, 1e-128, 1e-127, 1e-126, 1e-125, 1e-124, 1e-123, 1e-122, 1e-121, + 1e-120, 1e-119, 1e-118, 1e-117, 1e-116, 1e-115, 1e-114, 1e-113, 1e-112, 1e-111, + 1e-110, 1e-109, 1e-108, 1e-107, 1e-106, 1e-105, 1e-104, 1e-103, 1e-102, 1e-101, + + 1e-100, 1e-099, 1e-098, 1e-097, 1e-096, 1e-095, 1e-094, 1e-093, 1e-092, 1e-091, + 1e-090, 1e-089, 1e-088, 1e-087, 1e-086, 1e-085, 1e-084, 1e-083, 1e-082, 1e-081, + 1e-080, 1e-079, 1e-078, 1e-077, 1e-076, 1e-075, 1e-074, 1e-073, 1e-072, 1e-071, + 1e-070, 1e-069, 1e-068, 1e-067, 1e-066, 1e-065, 1e-064, 1e-063, 1e-062, 1e-061, + 1e-060, 1e-059, 1e-058, 1e-057, 1e-056, 1e-055, 1e-054, 1e-053, 1e-052, 1e-051, + 1e-050, 1e-049, 1e-048, 1e-047, 1e-046, 1e-045, 1e-044, 1e-043, 1e-042, 1e-041, + 1e-040, 1e-039, 1e-038, 1e-037, 1e-036, 1e-035, 1e-034, 1e-033, 1e-032, 1e-031, + 1e-030, 1e-029, 1e-028, 1e-027, 1e-026, 1e-025, 1e-024, 1e-023, 1e-022, 1e-021, + 1e-020, 1e-019, 1e-018, 1e-017, 1e-016, 1e-015, 1e-014, 1e-013, 1e-012, 1e-011, + 1e-010, 1e-009, 1e-008, 1e-007, 1e-006, 1e-005, 1e-004, 1e-003, 1e-002, 1e-001, + + 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, + 1e+010, 1e+011, 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, + 1e+020, 1e+021, 1e+022, 1e+023, 1e+024, 1e+025, 1e+026, 1e+027, 1e+028, 1e+029, + 1e+030, 1e+031, 1e+032, 1e+033, 1e+034, 1e+035, 1e+036, 1e+037, 1e+038, 1e+039, + 1e+040, 1e+041, 1e+042, 1e+043, 1e+044, 1e+045, 1e+046, 1e+047, 1e+048, 1e+049, + 1e+050, 1e+051, 1e+052, 1e+053, 1e+054, 1e+055, 1e+056, 1e+057, 1e+058, 1e+059, + 1e+060, 1e+061, 1e+062, 1e+063, 1e+064, 1e+065, 1e+066, 1e+067, 1e+068, 1e+069, + 1e+070, 1e+071, 1e+072, 1e+073, 1e+074, 1e+075, 1e+076, 1e+077, 1e+078, 1e+079, + 1e+080, 1e+081, 1e+082, 1e+083, 1e+084, 1e+085, 1e+086, 1e+087, 1e+088, 1e+089, + 1e+090, 1e+091, 1e+092, 1e+093, 1e+094, 1e+095, 1e+096, 1e+097, 1e+098, 1e+099, + + 1e+100, 1e+101, 1e+102, 1e+103, 1e+104, 1e+105, 1e+106, 1e+107, 1e+108, 1e+109, + 1e+110, 1e+111, 1e+112, 1e+113, 1e+114, 1e+115, 1e+116, 1e+117, 1e+118, 1e+119, + 1e+120, 1e+121, 1e+122, 1e+123, 1e+124, 1e+125, 1e+126, 1e+127, 1e+128, 1e+129, + 1e+130, 1e+131, 1e+132, 1e+133, 1e+134, 1e+135, 1e+136, 1e+137, 1e+138, 1e+139, + 1e+140, 1e+141, 1e+142, 1e+143, 1e+144, 1e+145, 1e+146, 1e+147, 1e+148, 1e+149, + 1e+150, 1e+151, 1e+152, 1e+153, 1e+154, 1e+155, 1e+156, 1e+157, 1e+158, 1e+159, + 1e+160, 1e+161, 1e+162, 1e+163, 1e+164, 1e+165, 1e+166, 1e+167, 1e+168, 1e+169, + 1e+170, 1e+171, 1e+172, 1e+173, 1e+174, 1e+175, 1e+176, 1e+177, 1e+178, 1e+179, + 1e+180, 1e+181, 1e+182, 1e+183, 1e+184, 1e+185, 1e+186, 1e+187, 1e+188, 1e+189, + 1e+190, 1e+191, 1e+192, 1e+193, 1e+194, 1e+195, 1e+196, 1e+197, 1e+198, 1e+199, + + 1e+200, 1e+201, 1e+202, 1e+203, 1e+204, 1e+205, 1e+206, 1e+207, 1e+208, 1e+209, + 1e+210, 1e+211, 1e+212, 1e+213, 1e+214, 1e+215, 1e+216, 1e+217, 1e+218, 1e+219, + 1e+220, 1e+221, 1e+222, 1e+223, 1e+224, 1e+225, 1e+226, 1e+227, 1e+228, 1e+229, + 1e+230, 1e+231, 1e+232, 1e+233, 1e+234, 1e+235, 1e+236, 1e+237, 1e+238, 1e+239, + 1e+240, 1e+241, 1e+242, 1e+243, 1e+244, 1e+245, 1e+246, 1e+247, 1e+248, 1e+249, + 1e+250, 1e+251, 1e+252, 1e+253, 1e+254, 1e+255, 1e+256, 1e+257, 1e+258, 1e+259, + 1e+260, 1e+261, 1e+262, 1e+263, 1e+264, 1e+265, 1e+266, 1e+267, 1e+268, 1e+269, + 1e+270, 1e+271, 1e+272, 1e+273, 1e+274, 1e+275, 1e+276, 1e+277, 1e+278, 1e+279, + 1e+280, 1e+281, 1e+282, 1e+283, 1e+284, 1e+285, 1e+286, 1e+287, 1e+288, 1e+289, + 1e+290, 1e+291, 1e+292, 1e+293, 1e+294, 1e+295, 1e+296, 1e+297, 1e+298, 1e+299, + + 1e+300, 1e+301, 1e+302, 1e+303, 1e+304, 1e+305, 1e+306, 1e+307, 1e+308 }; + + if (exp < -308 || exp > 308) + { + return std::pow(10.0, exp); + } + else + { + exp += 308; + BOOST_ASSERT(exp >= 0 && exp < 618); + return tab[exp]; + } +} + +inline +double +dec_to_float( + std::uint64_t m, + std::int32_t e, + bool neg) noexcept +{ + if(neg) + return (-static_cast< + double>(m)) * + pow10(e); + return (static_cast< + double>(m)) * + pow10(e); +} + +} // detail + +//---------------------------------------------------------- + bool basic_parser:: is_control(char c) noexcept diff --git a/include/boost/json/src.hpp b/include/boost/json/src.hpp index d62c5e01..5c8e940a 100644 --- a/include/boost/json/src.hpp +++ b/include/boost/json/src.hpp @@ -39,7 +39,6 @@ in a translation unit of the program. #include #include -#include #include #include #include diff --git a/test/Jamfile b/test/Jamfile index 968412a9..8f6a481e 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -25,7 +25,6 @@ else } local SOURCES = - _detail_number.cpp array.cpp basic_parser.cpp error.cpp diff --git a/test/_detail_number.cpp b/test/_detail_number.cpp deleted file mode 100644 index 3421bad1..00000000 --- a/test/_detail_number.cpp +++ /dev/null @@ -1,673 +0,0 @@ -// -// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/vinniefalco/json -// - -// Test that header file is self-contained. -#include - -#include -#include -#include - -#include "test_suite.hpp" - -#define ACCURATE_CONVERSION 0 - -namespace boost { -namespace json { -namespace detail { - -bool -operator==( - number const& lhs, - number const& rhs) noexcept -{ - if(lhs.kind != rhs.kind) - return false; - switch(lhs.kind) - { - case json::kind::int64: - return lhs.i == rhs.i; - case json::kind::uint64: - return lhs.u == rhs.u; - default: - break; - } - return - std::signbit(lhs.d) == - std::signbit(rhs.d) && - lhs.d == rhs.d; -} - -struct double_diagnoser -{ - - static void emit_hex(std::ostream& os, double d) - { - std::uint64_t binary; - static_assert(sizeof(binary) == sizeof(d), ""); - - std::memcpy(&binary, &d, sizeof(d)); - auto oldflags = os.flags(); - - try - { - os << std::hex << std::setw(16) << std::setfill('0') << binary; - os.flags(oldflags); - } - catch(...) - { - os.flags(oldflags); - } - } - static void emit_pow2(std::ostream& os, double d) - { - auto oldflags = os.flags(); - try - { - int exponent = 0; - auto mantissa = std::frexp(d, &exponent); - os << std::fixed << mantissa; - os << " *2^ "; - os << exponent; - os.flags(oldflags); - } - catch(...) - { - os.flags(oldflags); - throw; - } - } - - static void emit_scientific(std::ostream& os, double d) - { - auto oldflags = os.flags(); - try - { - os - << std::setprecision(std::numeric_limits::max_digits10) - << d; - os.flags(oldflags); - } - catch(...) - { - os.flags(oldflags); - throw; - } - } - - friend - std::ostream& - operator<<(std::ostream& os, double_diagnoser diag) - { - emit_scientific(os, diag.d); - os << "(0x"; - emit_hex(os, diag.d); - os << ") "; - emit_pow2(os, diag.d); - return os; - } - - double d; -}; - -auto diagnose(double d) -> double_diagnoser -{ - return double_diagnoser { d }; -} - -bool -are_close( - double x, - double y) -{ - std::uint64_t bx, by; - std::memcpy(&bx, &x, sizeof(x)); - std::memcpy(&by, &y, sizeof(y)); - - auto diff = bx - by; - switch (diff) - { - case 0: - case 1: - case 0xffffffffffffffff: - return true; - default: - break; - } - return false; -} - - -class number_test -{ -public: - test_suite::log_type log; - - template - static - void - grind( - string_view s, - F&& f) - { - { - error_code ec; - number_parser p; - p.write(s.data(), s.size(), ec); - if(BOOST_TEST(! ec)) - { - BOOST_TEST(p.is_done()); - f(p.get()); - } - } - for(;;) - { - error_code ec; - number_parser p; - p.write_some(s.data(), s.size(), ec); - if(! BOOST_TEST(! ec)) - break; - auto n = p.write_some("x", 1, ec); - if(! BOOST_TEST( - p.is_done())) - break; - if(! BOOST_TEST(n == 0)) - break; - f(p.get()); - p.finish(ec); - BOOST_TEST(! ec); - break; - } - for(size_t i = 1; i < s.size(); ++i) - { - error_code ec; - number_parser p; - p.write_some(s.data(), i, ec); - if(! BOOST_TEST(! ec)) - continue; - p.write( - s.data() + i, s.size() - i, ec); - if(! BOOST_TEST(! ec)) - continue; - BOOST_TEST(p.is_done()); - f(p.get()); - } - } - - //------------------------------------------------------ - - void - testMembers() - { - // maybe_init - { - number_parser p; - BOOST_TEST(! p.maybe_init(0)); - BOOST_TEST(! p.maybe_init('A')); - BOOST_TEST(! p.maybe_init('a')); - BOOST_TEST(! p.maybe_init('.')); - BOOST_TEST(! p.maybe_init('!')); - BOOST_TEST(! p.maybe_init(' ')); - BOOST_TEST(p.maybe_init('0')); p.reset(); - BOOST_TEST(p.maybe_init('1')); p.reset(); - BOOST_TEST(p.maybe_init('2')); p.reset(); - BOOST_TEST(p.maybe_init('3')); p.reset(); - BOOST_TEST(p.maybe_init('4')); p.reset(); - BOOST_TEST(p.maybe_init('5')); p.reset(); - BOOST_TEST(p.maybe_init('6')); p.reset(); - BOOST_TEST(p.maybe_init('7')); p.reset(); - BOOST_TEST(p.maybe_init('8')); p.reset(); - BOOST_TEST(p.maybe_init('9')); p.reset(); - BOOST_TEST(p.maybe_init('0')); p.reset(); - BOOST_TEST(p.maybe_init('-')); p.reset(); - } - - // finish - { - error_code ec; - number_parser p; - p.write_some("0x", 2, ec); - if(BOOST_TEST(! ec)) - { - p.finish(ec); - BOOST_TEST(! ec); - } - } - } - - //------------------------------------------------------ - - void - check_bad(string_view s) - { - error_code xec; - { - number_parser p; - p.write(s.data(), s.size(), xec); - BOOST_TEST(xec); - } - for(size_t i = 1; i < s.size(); ++i) - { - error_code ec; - number_parser p; - p.write_some(s.data(), i, ec); - if(ec == xec) - { - BOOST_TEST_PASS(); - continue; - } - if(! BOOST_TEST(! ec)) - continue; - p.write( - s.data() + i, s.size() - i, ec); - BOOST_TEST(ec == xec); - } - } - - void - check_int64( - string_view s, - int64_t i) - { - grind(s, - [&](number num) - { - if( BOOST_TEST( - num.kind == kind::int64)) - BOOST_TEST(num.i == i); - }); - } - - void - check_uint64( - string_view s, - uint64_t u) - { - grind(s, - [&](number num) - { - if( BOOST_TEST( - num.kind == kind::uint64)) - BOOST_TEST(num.u == u); - }); - } - - void - testIntegers() - { - check_int64( "-9223372036854775808", INT64_MIN); - check_int64( "-9223372036854775807", -9223372036854775807); - check_int64( "-999999999999999999", -999999999999999999); - check_int64( "-99999999999999999", -99999999999999999); - check_int64( "-9999999999999999", -9999999999999999); - check_int64( "-999999999999999", -999999999999999); - check_int64( "-99999999999999", -99999999999999); - check_int64( "-9999999999999", -9999999999999); - check_int64( "-999999999999", -999999999999); - check_int64( "-99999999999", -99999999999); - check_int64( "-9999999999", -9999999999); - check_int64( "-999999999", -999999999); - check_int64( "-99999999", -99999999); - check_int64( "-9999999", -9999999); - check_int64( "-999999", -999999); - check_int64( "-99999", -99999); - check_int64( "-9999", -9999); - check_int64( "-999", -999); - check_int64( "-99", -99); - check_int64( "-9", -9); - check_int64( "0", 0); - check_int64( "9", 9); - check_int64( "99", 99); - check_int64( "999", 999); - check_int64( "9999", 9999); - check_int64( "99999", 99999); - check_int64( "999999", 999999); - check_int64( "9999999", 9999999); - check_int64( "99999999", 99999999); - check_int64( "999999999", 999999999); - check_int64( "9999999999", 9999999999); - check_int64( "99999999999", 99999999999); - check_int64( "999999999999", 999999999999); - check_int64( "9999999999999", 9999999999999); - check_int64( "99999999999999", 99999999999999); - check_int64( "999999999999999", 999999999999999); - check_int64( "9999999999999999", 9999999999999999); - check_int64( "99999999999999999", 99999999999999999); - check_int64( "999999999999999999", 999999999999999999); - check_int64( "9223372036854775807", INT64_MAX); - - check_uint64( "9223372036854775808", 9223372036854775808ULL); - check_uint64( "9999999999999999999", 9999999999999999999ULL); - check_uint64( "18446744073709551615", UINT64_MAX); - } - - void - testBad() - { - check_bad(""); - check_bad("x"); - check_bad("e"); - check_bad("1ex"); - check_bad("-"); - check_bad("1a"); - check_bad("."); - check_bad("-."); - check_bad("1."); - check_bad("-1."); - check_bad("1.x"); - check_bad("1+"); - check_bad("1-"); - check_bad("0.0+"); - check_bad("0.0e+"); - check_bad("0.0e-"); - check_bad("0.0e0-"); - check_bad("0.0e"); - check_bad("0.e1"); - check_bad("-e"); - check_bad("-x"); - check_bad("2.e+3"); - check_bad("-2.e+3"); - - // leading 0 must be followed by [.eE] or nothing - check_bad( "00"); - check_bad( "01"); - check_bad( "00."); - check_bad( "00.0"); - check_bad("-00"); - check_bad("-01"); - check_bad("-00."); - check_bad("-00.0"); - } - - //------------------------------------------------------ - - struct f_boost - { - static - string_view - name() noexcept - { - return "boost"; - } - - double - operator()(string_view s) const - { - error_code ec; - number_parser p; - p.write(s.data(), s.size(), ec); - if(ec) - BOOST_THROW_EXCEPTION( - system_error(ec)); - BOOST_TEST(p.is_done()); - auto const num = p.get(); - BOOST_ASSERT( - num.kind == kind::double_); - - grind(s, - [&](number num1) - { - if( BOOST_TEST( - num1.kind == kind::double_)) - BOOST_TEST(num1.d == num.d); - }); - - return num.d; - } - }; - - // Verify that f converts to the - // same double produced by `strtod`. - // Requires `s` is not represented by an integral type. - template - void - fcheck(std::string const& s, F const& f) - { - char* str_end; - double const need = - std::strtod(s.c_str(), &str_end); - BOOST_TEST(str_end == &s.back() + 1); - double const got = f(s); - auto same = got == need; - -#if !ACCURATE_CONVERSION - auto close = same ? true : are_close(got, need); - if(! BOOST_TEST(close)) - { - log << "not close : " << - f.name() << "\n" - "string: " << s << "\n" - "need : " << diagnose(need) << "\n" - "got : " << diagnose(got) << - std::endl; - } -#else - if (!BOOST_TEST(same)) - { - log << "close but not close enough : " << - f.name() << "\n" - "string: " << s << "\n" - "need : " << diagnose(need) << "\n" - "got : " << diagnose(got) << - std::endl; - } -#endif - } - - template - void - check_numbers(F const& f) - { - auto const fc = - [&](std::string const& s) - { - fcheck(s, f); - }; - - fc("-999999999999999999999"); - fc("-100000000000000000009"); - fc("-10000000000000000000"); - fc("-9223372036854775809"); - - fc("18446744073709551616"); - fc("99999999999999999999"); - fc("999999999999999999999"); - fc("1000000000000000000000"); - fc("9999999999999999999999"); - fc("99999999999999999999999"); - - fc("-0.9999999999999999999999"); - fc("-0.9999999999999999"); - fc("-0.9007199254740991"); - fc("-0.999999999999999"); - fc("-0.99999999999999"); - fc("-0.9999999999999"); - fc("-0.999999999999"); - fc("-0.99999999999"); - fc("-0.9999999999"); - fc("-0.999999999"); - fc("-0.99999999"); - fc("-0.9999999"); - fc("-0.999999"); - fc("-0.99999"); - fc("-0.9999"); - fc("-0.8125"); - fc("-0.999"); - fc("-0.99"); - fc("-1.0"); - fc("-0.9"); - fc("-0.0"); - fc("0.0"); - fc("0.9"); - fc("0.99"); - fc("0.999"); - fc("0.8125"); - fc("0.9999"); - fc("0.99999"); - fc("0.999999"); - fc("0.9999999"); - fc("0.99999999"); - fc("0.999999999"); - fc("0.9999999999"); - fc("0.99999999999"); - fc("0.999999999999"); - fc("0.9999999999999"); - fc("0.99999999999999"); - fc("0.999999999999999"); - fc("0.9007199254740991"); - fc("0.9999999999999999"); - fc("0.9999999999999999999999"); - fc("0.999999999999999999999999999"); - - fc("-1e308"); - fc("-1e-308"); - fc("-9999e300"); - fc("-999e100"); - fc("-99e10"); - fc("-9e1"); - fc("9e1"); - fc("99e10"); - fc("999e100"); - fc("9999e300"); - fc("999999999999999999.0"); - fc("999999999999999999999.0"); - fc("999999999999999999999e5"); - fc("999999999999999999999.0e5"); - - fc("0.00000000000000001"); - - fc("-1e-1"); - fc("-1e0"); - fc("-1e1"); - fc("0e0"); - fc("1e0"); - fc("1e10"); - - fc("0." - "00000000000000000000000000000000000000000000000000" // 50 zeroes - "1e50"); - fc("-0." - "00000000000000000000000000000000000000000000000000" // 50 zeroes - "1e50"); - - fc("0." - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" // 500 zeroes - "1e600"); - fc("-0." - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" // 500 zeroes - "1e600"); - - fc("0e" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" // 500 zeroes - ); - } - - void - testDoubles() - { - check_numbers(f_boost{}); - } - - static - number - int64_num(int64_t i) noexcept - { - number num; - num.i = i; - num.kind = kind::int64; - return num; - } - - static - number - uint64_num(uint64_t u) noexcept - { - number num; - num.u = u; - num.kind = kind::uint64; - return num; - } - - static - number - double_num(double d) noexcept - { - number num; - num.d = d; - num.kind = kind::double_; - return num; - } - - void - testEdgeCases() - { - auto const parse = - [&](string_view s) - { - error_code ec; - number_parser p; - p.write(s.data(), s.size(), ec); - BOOST_TEST(! ec); - return p.get(); - }; - - BOOST_TEST(parse("-0.0") == double_num(-0.0)); - BOOST_TEST(parse("-0E0") == double_num(-0.0)); - BOOST_TEST(parse("-0") == int64_num(0)); - - BOOST_TEST(parse("0") == int64_num(0)); - BOOST_TEST(parse("0.010") == double_num(0.01)); - BOOST_TEST(parse("-0.010") == double_num(-0.01)); - BOOST_TEST(parse("1.010") == double_num(1.01)); - BOOST_TEST(parse("-1.010") == double_num(-1.01)); - } - - void - run() - { - testEdgeCases(); - testMembers(); - testIntegers(); - testBad(); - testDoubles(); - } -}; - -TEST_SUITE(number_test, "boost.json.detail.number"); - -} // detail -} // json -} // boost diff --git a/test/basic_parser.cpp b/test/basic_parser.cpp index d3145950..3d94e901 100644 --- a/test/basic_parser.cpp +++ b/test/basic_parser.cpp @@ -451,21 +451,26 @@ public: good("1000000000000000000000000.0e1"); good("1000000000000000000000000.0 "); - bad (""); + bad ( ""); bad ("-"); - bad ("00"); - bad ("00."); - bad ("00.0"); - bad ("1a"); - bad ("."); - bad ("1."); - bad ("1+"); - bad ("0.0+"); - bad ("0.0e+"); - bad ("0.0e-"); - bad ("0.0e0-"); - bad ("0.0e"); - bad ("1000000000000000000000000.e"); + bad ( "00"); + bad ( "01"); + bad ( "00."); + bad ( "00.0"); + bad ("-00"); + bad ("-01"); + bad ("-00."); + bad ("-00.0"); + bad ( "1a"); + bad ( "."); + bad ( "1."); + bad ( "1+"); + bad ( "0.0+"); + bad ( "0.0e+"); + bad ( "0.0e-"); + bad ( "0.0e0-"); + bad ( "0.0e"); + bad ( "1000000000000000000000000.e"); } void diff --git a/test/parser.cpp b/test/parser.cpp index 9e3a23be..120dcf8a 100644 --- a/test/parser.cpp +++ b/test/parser.cpp @@ -27,6 +27,7 @@ class parser_test public: ::test_suite::log_type log; + static value from_string_test( string_view s, @@ -41,23 +42,20 @@ public: } void - check_round_trip( - value const& jv1, - string_view s1) + static + check_round_trip(value const& jv1) { auto const s2 = //to_string_test(jv1); // use this if serializer is broken to_string(jv1); auto jv2 = from_string_test(s2); - if(! BOOST_TEST(equal(jv1, jv2))) - log << - " " << s1 << "\n" << - " " << s2 << std::endl; + BOOST_TEST(equal(jv1, jv2)); } template void + static grind_one( string_view s, storage_ptr sp, @@ -68,15 +66,17 @@ public: f(jv); } + static void grind_one(string_view s) { auto const jv = from_string_test(s); - check_round_trip(jv, s); + check_round_trip(jv); } template + static void grind(string_view s, F const& f) { @@ -118,16 +118,18 @@ public: } } + static void grind(string_view s) { grind(s, - [this, &s](value const& jv) + [&s](value const& jv) { - check_round_trip(jv, s); + check_round_trip(jv); }); } + static void grind_int64(string_view s, int64_t v) { @@ -140,6 +142,7 @@ public: }); } + static void grind_uint64(string_view s, uint64_t v) { @@ -152,6 +155,7 @@ public: }); } + static void grind_double(string_view s, double v) { @@ -259,13 +263,83 @@ public: js.size() - N, ec); if(BOOST_TEST(! ec)) check_round_trip( - p.release(), js); + p.release()); } } } } //------------------------------------------------------ + + struct f_boost + { + static + string_view + name() noexcept + { + return "boost"; + } + + double + operator()(string_view s) const + { + BOOST_TEST_CHECKPOINT(); + error_code ec; + parser p; + p.start(); + p.finish(s.data(), s.size(), ec); + if(! BOOST_TEST(! ec)) + return 0; + auto const jv = p.release(); + double const d = jv.as_double(); + grind_double(s, d); + return d; + } + }; + + bool + within_1ulp(double x, double y) + { + std::uint64_t bx, by; + std::memcpy(&bx, &x, sizeof(x)); + std::memcpy(&by, &y, sizeof(y)); + + auto diff = bx - by; + switch (diff) + { + case 0: + case 1: + case 0xffffffffffffffff: + return true; + default: + break; + } + return false; + } + + // Verify that f converts to the + // same double produced by `strtod`. + // Requires `s` is not represented by an integral type. + template + void + fc(std::string const& s, F const& f) + { + char* str_end; + double const need = + std::strtod(s.c_str(), &str_end); + BOOST_TEST(str_end == &s.back() + 1); + double const got = f(s); + auto same = got == need; + auto close = same ? + true : within_1ulp(got, need); + BOOST_TEST(close); + } + + void + fc(std::string const& s) + { + fc(s, f_boost{}); + } void testNumber() @@ -324,6 +398,10 @@ public: grind_uint64( "9999999999999999999", 9999999999999999999ULL); grind_uint64( "18446744073709551615", UINT64_MAX); + grind_double("-1.010", -1.01); + grind_double("-0.010", -0.01); + grind_double("-0.0", -0.0); + grind_double("-0e0", -0.0); grind_double( "18446744073709551616", 1.8446744073709552e+19); grind_double("-18446744073709551616", -1.8446744073709552e+19); grind_double( "18446744073709551616.0", 1.8446744073709552e+19); @@ -340,7 +418,129 @@ public: grind_double( "11.1111", 11.1111); grind_double( "111.111", 111.111); - grind("1.0"); + fc("-999999999999999999999"); + fc("-100000000000000000009"); + fc("-10000000000000000000"); + fc("-9223372036854775809"); + + fc("18446744073709551616"); + fc("99999999999999999999"); + fc("999999999999999999999"); + fc("1000000000000000000000"); + fc("9999999999999999999999"); + fc("99999999999999999999999"); + + fc("-0.9999999999999999999999"); + fc("-0.9999999999999999"); + fc("-0.9007199254740991"); + fc("-0.999999999999999"); + fc("-0.99999999999999"); + fc("-0.9999999999999"); + fc("-0.999999999999"); + fc("-0.99999999999"); + fc("-0.9999999999"); + fc("-0.999999999"); + fc("-0.99999999"); + fc("-0.9999999"); + fc("-0.999999"); + fc("-0.99999"); + fc("-0.9999"); + fc("-0.8125"); + fc("-0.999"); + fc("-0.99"); + fc("-1.0"); + fc("-0.9"); + fc("-0.0"); + fc("0.0"); + fc("0.9"); + fc("0.99"); + fc("0.999"); + fc("0.8125"); + fc("0.9999"); + fc("0.99999"); + fc("0.999999"); + fc("0.9999999"); + fc("0.99999999"); + fc("0.999999999"); + fc("0.9999999999"); + fc("0.99999999999"); + fc("0.999999999999"); + fc("0.9999999999999"); + fc("0.99999999999999"); + fc("0.999999999999999"); + fc("0.9007199254740991"); + fc("0.9999999999999999"); + fc("0.9999999999999999999999"); + fc("0.999999999999999999999999999"); + + fc("-1e308"); + fc("-1e-308"); + fc("-9999e300"); + fc("-999e100"); + fc("-99e10"); + fc("-9e1"); + fc("9e1"); + fc("99e10"); + fc("999e100"); + fc("9999e300"); + fc("999999999999999999.0"); + fc("999999999999999999999.0"); + fc("999999999999999999999e5"); + fc("999999999999999999999.0e5"); + + fc("0.00000000000000001"); + + fc("-1e-1"); + fc("-1e0"); + fc("-1e1"); + fc("0e0"); + fc("1e0"); + fc("1e10"); + + fc("0." + "00000000000000000000000000000000000000000000000000" // 50 zeroes + "1e50"); + fc("-0." + "00000000000000000000000000000000000000000000000000" // 50 zeroes + "1e50"); + + fc("0." + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" // 500 zeroes + "1e600"); + fc("-0." + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" // 500 zeroes + "1e600"); + + fc("0e" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000" // 500 zeroes + ); } //------------------------------------------------------ @@ -487,7 +687,7 @@ public: error_code ec; auto jv = parse(js, ec); BOOST_TEST(! ec); - check_round_trip(jv, js); + check_round_trip(jv); } { error_code ec; @@ -504,7 +704,7 @@ public: scoped_storage sp; auto jv = parse(js, ec, sp); BOOST_TEST(! ec); - check_round_trip(jv, js); + check_round_trip(jv); } { @@ -520,8 +720,7 @@ public: { { check_round_trip( - parse(js), - js); + parse(js)); } { @@ -536,7 +735,7 @@ public: { { scoped_storage sp; - check_round_trip(parse(js, sp), js); + check_round_trip(parse(js, sp)); } { diff --git a/test/test_suite.hpp b/test/test_suite.hpp index 06c6b552..9aac3adc 100644 --- a/test/test_suite.hpp +++ b/test/test_suite.hpp @@ -449,7 +449,7 @@ public: "(#" << id << ") " << filename(cp->file) << "(" << cp->line << ") " - "failed:" << expr << "\n"; + "failed: " << expr << "\n"; else log_ << "#" << id <<