diff --git a/include/boost/json/detail/except.hpp b/include/boost/json/detail/except.hpp index 08c12d27..2628b6a1 100644 --- a/include/boost/json/detail/except.hpp +++ b/include/boost/json/detail/except.hpp @@ -33,6 +33,7 @@ BOOST_JSON_DECL void BOOST_NORETURN throw_invalid_argument(char const* what, sou BOOST_JSON_DECL void BOOST_NORETURN throw_length_error(char const* what, source_location const& loc); BOOST_JSON_DECL void BOOST_NORETURN throw_out_of_range(source_location const& loc); BOOST_JSON_DECL void BOOST_NORETURN throw_system_error(error_code const& ec, source_location const& loc); +BOOST_JSON_DECL void BOOST_NORETURN throw_system_error(error e, source_location const& loc); } // detail BOOST_JSON_NS_END diff --git a/include/boost/json/detail/impl/except.ipp b/include/boost/json/detail/impl/except.ipp index f7b5ded0..7135f092 100644 --- a/include/boost/json/detail/impl/except.ipp +++ b/include/boost/json/detail/impl/except.ipp @@ -120,6 +120,20 @@ throw_system_error( ); } +void +throw_system_error( + error e, + source_location const& loc) +{ + (void)loc; + throw_exception( + system_error(e) +#if ! defined(BOOST_JSON_STANDALONE) + , loc +#endif + ); +} + } // detail BOOST_JSON_NS_END diff --git a/include/boost/json/value.hpp b/include/boost/json/value.hpp index 20bc9674..23b1769a 100644 --- a/include/boost/json/value.hpp +++ b/include/boost/json/value.hpp @@ -2354,10 +2354,22 @@ public: @param ec Set to the error, if any occurred. */ -#ifdef BOOST_JSON_DOCS template - T to_number(error_code& ec) const noexcept; +#ifdef BOOST_JSON_DOCS + T +#else + typename std::enable_if< + std::is_arithmetic::value && + ! std::is_same::value, + T>::type #endif + to_number(error_code& ec) const noexcept + { + error e; + auto result = to_number(e); + ec = e; + return result; + } /** Return the stored number cast to an arithmetic type. @@ -2406,141 +2418,14 @@ public: #endif to_number() const { - error_code ec; - auto result = to_number(ec); - if(ec) - detail::throw_system_error(ec, + error e; + auto result = to_number(e); + if(error() != e) + detail::throw_system_error(e, BOOST_JSON_SOURCE_POS); return result; } -#ifndef BOOST_JSON_DOCS - template - auto - to_number(error_code& ec) const noexcept -> - typename std::enable_if< - std::is_signed::value && - ! std::is_floating_point::value, - T>::type - { - if(sca_.k == json::kind::int64) - { - auto const i = sca_.i; - if( i >= (std::numeric_limits::min)() && - i <= (std::numeric_limits::max)()) - { - ec = {}; - return static_cast(i); - } - ec = error::not_exact; - } - else if(sca_.k == json::kind::uint64) - { - auto const u = sca_.u; - if(u <= static_cast(( - std::numeric_limits::max)())) - { - ec = {}; - return static_cast(u); - } - ec = error::not_exact; - } - else if(sca_.k == json::kind::double_) - { - auto const d = sca_.d; - if( d >= static_cast( - (detail::to_number_limit::min)()) && - d <= static_cast( - (detail::to_number_limit::max)()) && - static_cast(d) == d) - { - ec = {}; - return static_cast(d); - } - ec = error::not_exact; - } - else - { - ec = error::not_number; - } - return T{}; - } - - template - auto - to_number(error_code& ec) const noexcept -> - typename std::enable_if< - std::is_unsigned::value && - ! std::is_same::value, - T>::type - { - if(sca_.k == json::kind::int64) - { - auto const i = sca_.i; - if( i >= 0 && static_cast(i) <= - (std::numeric_limits::max)()) - { - ec = {}; - return static_cast(i); - } - ec = error::not_exact; - } - else if(sca_.k == json::kind::uint64) - { - auto const u = sca_.u; - if(u <= (std::numeric_limits::max)()) - { - ec = {}; - return static_cast(u); - } - ec = error::not_exact; - } - else if(sca_.k == json::kind::double_) - { - auto const d = sca_.d; - if( d >= 0 && - d <= (detail::to_number_limit::max)() && - static_cast(d) == d) - { - ec = {}; - return static_cast(d); - } - ec = error::not_exact; - } - else - { - ec = error::not_number; - } - return T{}; - } - - template - auto - to_number(error_code& ec) const noexcept -> - typename std::enable_if< - std::is_floating_point< - T>::value, T>::type - { - if(sca_.k == json::kind::int64) - { - ec = {}; - return static_cast(sca_.i); - } - if(sca_.k == json::kind::uint64) - { - ec = {}; - return static_cast(sca_.u); - } - if(sca_.k == json::kind::double_) - { - ec = {}; - return static_cast(sca_.d); - } - ec = error::not_number; - return {}; - } -#endif - //------------------------------------------------------ // // Accessors @@ -3373,6 +3258,131 @@ private: BOOST_JSON_DECL bool equal(value const& other) const noexcept; + + template + auto + to_number(error& e) const noexcept -> + typename std::enable_if< + std::is_signed::value && + ! std::is_floating_point::value, + T>::type + { + if(sca_.k == json::kind::int64) + { + auto const i = sca_.i; + if( i >= (std::numeric_limits::min)() && + i <= (std::numeric_limits::max)()) + { + e = {}; + return static_cast(i); + } + e = error::not_exact; + } + else if(sca_.k == json::kind::uint64) + { + auto const u = sca_.u; + if(u <= static_cast(( + std::numeric_limits::max)())) + { + e = {}; + return static_cast(u); + } + e = error::not_exact; + } + else if(sca_.k == json::kind::double_) + { + auto const d = sca_.d; + if( d >= static_cast( + (detail::to_number_limit::min)()) && + d <= static_cast( + (detail::to_number_limit::max)()) && + static_cast(d) == d) + { + e = {}; + return static_cast(d); + } + e = error::not_exact; + } + else + { + e = error::not_number; + } + return T{}; + } + + template + auto + to_number(error& e) const noexcept -> + typename std::enable_if< + std::is_unsigned::value && + ! std::is_same::value, + T>::type + { + if(sca_.k == json::kind::int64) + { + auto const i = sca_.i; + if( i >= 0 && static_cast(i) <= + (std::numeric_limits::max)()) + { + e = {}; + return static_cast(i); + } + e = error::not_exact; + } + else if(sca_.k == json::kind::uint64) + { + auto const u = sca_.u; + if(u <= (std::numeric_limits::max)()) + { + e = {}; + return static_cast(u); + } + e = error::not_exact; + } + else if(sca_.k == json::kind::double_) + { + auto const d = sca_.d; + if( d >= 0 && + d <= (detail::to_number_limit::max)() && + static_cast(d) == d) + { + e = {}; + return static_cast(d); + } + e = error::not_exact; + } + else + { + e = error::not_number; + } + return T{}; + } + + template + auto + to_number(error& e) const noexcept -> + typename std::enable_if< + std::is_floating_point< + T>::value, T>::type + { + if(sca_.k == json::kind::int64) + { + e = {}; + return static_cast(sca_.i); + } + if(sca_.k == json::kind::uint64) + { + e = {}; + return static_cast(sca_.u); + } + if(sca_.k == json::kind::double_) + { + e = {}; + return static_cast(sca_.d); + } + e = error::not_number; + return {}; + } }; // Make sure things are as big as we think they should be diff --git a/test/value.cpp b/test/value.cpp index 11a7c7d2..9e650c04 100644 --- a/test/value.cpp +++ b/test/value.cpp @@ -1647,6 +1647,10 @@ public: EQAL(float); EQAL(double); } + + error_code ec; + value(nullptr).to_number(ec); + BOOST_TEST(error::not_number == ec); } void @@ -2026,7 +2030,7 @@ public: check_array(value{false,2}, false, 2); check_array(value{false,2,"3",nullptr}, false, 2, "3", nullptr); check_array(value{2,false,"3"}, 2, false, "3"); - check_array(value{true,2,"3"}, true, 2, "3"); + check_array(value{true,2,"3"}, true, 2, "3"); } //------------------------------------------------------ @@ -2127,7 +2131,7 @@ public: value({{"a",1}, {"b",2}, {"c",3}}), object({{"b",2}, {"c",3}, {"a",1}}))); BOOST_TEST(expect_hash_not_equal( - value({{"a",1}, {"b",2}, {"c",3}}), + value({{"a",1}, {"b",2}, {"c",3}}), value({{"b",2}, {"c",3}}))); BOOST_TEST(check_hash_equal( value({"a", "b", 17}),