mirror of
https://github.com/boostorg/json.git
synced 2025-05-11 13:44:06 +00:00
Better number handling
This commit is contained in:
parent
6fa86cb0f0
commit
b1e03f7326
158
bench/bench.cpp
158
bench/bench.cpp
@ -17,9 +17,10 @@
|
||||
#include <boost/beast/_experimental/unit_test/dstream.hpp>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
|
||||
#include <boost/json/fixed_storage.hpp>
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
/*
|
||||
|
||||
@ -49,27 +50,8 @@ public:
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
class boost_impl : public any_impl
|
||||
struct boost_impl : public any_impl
|
||||
{
|
||||
json::parser* p_;
|
||||
|
||||
public:
|
||||
boost_impl()
|
||||
: p_(new json::parser)
|
||||
{
|
||||
}
|
||||
|
||||
explicit
|
||||
boost_impl(json::storage_ptr sp)
|
||||
: p_(new json::parser(std::move(sp)))
|
||||
{
|
||||
}
|
||||
|
||||
~boost_impl()
|
||||
{
|
||||
delete p_;
|
||||
}
|
||||
|
||||
boost::string_view
|
||||
name() const noexcept override
|
||||
{
|
||||
@ -77,25 +59,18 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
parse(
|
||||
boost::string_view s) override
|
||||
parse(boost::string_view s) override
|
||||
{
|
||||
json::parser p;
|
||||
boost::system::error_code ec;
|
||||
p_->write(s.data(), s.size(), ec);
|
||||
p.write(s.data(), s.size(), ec);
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
class nlohmann_impl : public any_impl
|
||||
struct nlohmann_impl : public any_impl
|
||||
{
|
||||
nlohmann::json root_;
|
||||
|
||||
public:
|
||||
nlohmann_impl()
|
||||
{
|
||||
}
|
||||
|
||||
boost::string_view
|
||||
name() const noexcept override
|
||||
{
|
||||
@ -103,18 +78,17 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
parse(
|
||||
boost::string_view s) override
|
||||
parse(boost::string_view s) override
|
||||
{
|
||||
auto jv = nlohmann::json::parse(s.begin(), s.end());
|
||||
auto jv = nlohmann::json::parse(
|
||||
s.begin(), s.end());
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
class rapidjson_impl : public any_impl
|
||||
struct rapidjson_impl : public any_impl
|
||||
{
|
||||
public:
|
||||
boost::string_view
|
||||
name() const noexcept override
|
||||
{
|
||||
@ -122,8 +96,7 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
parse(
|
||||
boost::string_view s) override
|
||||
parse(boost::string_view s) override
|
||||
{
|
||||
rapidjson::Document d;
|
||||
d.Parse(s.data(), s.size());
|
||||
@ -354,12 +327,14 @@ public:
|
||||
void
|
||||
benchParse(
|
||||
boost::string_view doc,
|
||||
any_impl& impl)
|
||||
any_impl& impl,
|
||||
int repeat = 1)
|
||||
{
|
||||
using clock_type = std::chrono::steady_clock;
|
||||
auto const when = clock_type::now();
|
||||
dout << impl.name();
|
||||
impl.parse(doc);
|
||||
while(repeat--)
|
||||
impl.parse(doc);
|
||||
auto const elapsed =
|
||||
std::chrono::duration_cast<
|
||||
std::chrono::milliseconds>(
|
||||
@ -372,35 +347,86 @@ benchParse(
|
||||
dout.flush();
|
||||
}
|
||||
|
||||
int
|
||||
main(int, char**)
|
||||
std::string
|
||||
load_file(char const* path)
|
||||
{
|
||||
for(int i = 5; i < 7; ++i)
|
||||
FILE* f = fopen(path, "rb");
|
||||
fseek(f, 0, SEEK_END);
|
||||
auto const size = ftell(f);
|
||||
std::string s;
|
||||
s.resize(size);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fread(&s[0], 1, size, f);
|
||||
fclose(f);
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
main(
|
||||
int const argc,
|
||||
char const* const* const argv)
|
||||
{
|
||||
if(argc > 1)
|
||||
{
|
||||
factory f;
|
||||
f.max_depth(i);
|
||||
auto const doc = f.make_document();
|
||||
std::vector<std::string> vs;
|
||||
vs.reserve(argc - 1);
|
||||
for(int i = 1; i < argc; ++i)
|
||||
vs.emplace_back(load_file(argv[i]));
|
||||
|
||||
std::vector<
|
||||
std::unique_ptr<any_impl>> v;
|
||||
v.reserve(10);
|
||||
|
||||
for(int i = 0; i < argc - 1; ++i)
|
||||
{
|
||||
v.clear();
|
||||
#if 1
|
||||
for(int j = 0; j < 3; ++j)
|
||||
{
|
||||
rapidjson_impl impl;
|
||||
benchParse(doc, impl);
|
||||
}
|
||||
for(int j = 0; j < 3; ++j)
|
||||
{
|
||||
nlohmann_impl impl;
|
||||
benchParse(doc, impl);
|
||||
}
|
||||
v.emplace_back(new nlohmann_impl);
|
||||
v.emplace_back(new nlohmann_impl);
|
||||
v.emplace_back(new nlohmann_impl);
|
||||
v.emplace_back(new rapidjson_impl);
|
||||
v.emplace_back(new rapidjson_impl);
|
||||
v.emplace_back(new rapidjson_impl);
|
||||
#endif
|
||||
for(int j = 0; j < 3; ++j)
|
||||
v.emplace_back(new boost_impl);
|
||||
v.emplace_back(new boost_impl);
|
||||
v.emplace_back(new boost_impl);
|
||||
|
||||
dout << "File: " << argv[i + 1] << std::endl;
|
||||
for(auto& impl : v)
|
||||
benchParse(vs[i], *impl, 100);
|
||||
dout << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = 5; i < 7; ++i)
|
||||
{
|
||||
#if 0
|
||||
boost_impl impl(json::make_storage<
|
||||
json::fixed_storage>(2047 * 1024 * 1024));
|
||||
#else
|
||||
boost_impl impl;
|
||||
#endif
|
||||
benchParse(doc, impl);
|
||||
factory f;
|
||||
f.max_depth(i);
|
||||
auto const doc = f.make_document();
|
||||
#if 1
|
||||
for(int j = 0; j < 3; ++j)
|
||||
{
|
||||
rapidjson_impl impl;
|
||||
benchParse(doc, impl);
|
||||
}
|
||||
for(int j = 0; j < 3; ++j)
|
||||
{
|
||||
nlohmann_impl impl;
|
||||
benchParse(doc, impl);
|
||||
}
|
||||
#endif
|
||||
for(int j = 0; j < 3; ++j)
|
||||
{
|
||||
#if 0
|
||||
boost_impl impl(json::make_storage<
|
||||
json::fixed_storage>(2047 * 1024 * 1024));
|
||||
#else
|
||||
boost_impl impl;
|
||||
#endif
|
||||
benchParse(doc, impl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
65
include/boost/json/detail/number.hpp
Normal file
65
include/boost/json/detail/number.hpp
Normal file
@ -0,0 +1,65 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot 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
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
inline
|
||||
double
|
||||
pow10(int exp) noexcept
|
||||
{
|
||||
static double const tab[309] = {
|
||||
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 };
|
||||
|
||||
BOOST_JSON_ASSERT(exp >= 0 && exp < 309);
|
||||
return tab[exp];
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
#endif
|
@ -11,6 +11,7 @@
|
||||
#define BOOST_JSON_IMPL_NUMBER_IPP
|
||||
|
||||
#include <boost/json/number.hpp>
|
||||
#include <boost/json/detail/number.hpp>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
@ -26,79 +27,173 @@ namespace json {
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
struct number::pow10
|
||||
/* Reference work:
|
||||
|
||||
https://www.ampl.com/netlib/fp/dtoa.c
|
||||
|
||||
https://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
number::
|
||||
~number()
|
||||
{
|
||||
std::size_t
|
||||
size() const noexcept
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
}
|
||||
|
||||
mantissa_type const*
|
||||
begin() const noexcept
|
||||
{
|
||||
return begin_;
|
||||
}
|
||||
number::
|
||||
number() noexcept
|
||||
: sp_(default_storage())
|
||||
, k_(kind::type_int64)
|
||||
{
|
||||
int64_ = 0;
|
||||
}
|
||||
|
||||
mantissa_type const*
|
||||
end() const noexcept
|
||||
{
|
||||
return end_;
|
||||
}
|
||||
number::
|
||||
number(storage_ptr sp) noexcept
|
||||
: sp_(std::move(sp))
|
||||
, k_(kind::type_int64)
|
||||
{
|
||||
int64_ = 0;
|
||||
}
|
||||
|
||||
mantissa_type
|
||||
operator[](
|
||||
exponent_type n) const
|
||||
number::
|
||||
number(pilfered<number> p) noexcept
|
||||
: sp_(std::move(p.get().sp_))
|
||||
, k_(p.get().k_)
|
||||
{
|
||||
auto& other = p.get();
|
||||
switch(k_)
|
||||
{
|
||||
return begin_[n];
|
||||
default:
|
||||
case kind::type_double:
|
||||
double_ = other.double_;
|
||||
break;
|
||||
|
||||
case kind::type_int64:
|
||||
int64_ = other.int64_;
|
||||
break;
|
||||
|
||||
case kind::type_uint64:
|
||||
uint64_ = other.uint64_;
|
||||
break;
|
||||
}
|
||||
|
||||
static
|
||||
pow10 const&
|
||||
get() noexcept
|
||||
}
|
||||
|
||||
number::
|
||||
number(number const& other)
|
||||
: sp_(other.sp_)
|
||||
, k_(other.k_)
|
||||
{
|
||||
switch(k_)
|
||||
{
|
||||
struct pow10_impl : pow10
|
||||
{
|
||||
pow10_impl()
|
||||
{
|
||||
static mantissa_type constexpr list[] = {
|
||||
1ULL,
|
||||
10ULL,
|
||||
100ULL,
|
||||
1000ULL,
|
||||
10000ULL,
|
||||
100000ULL,
|
||||
1000000ULL,
|
||||
10000000ULL,
|
||||
100000000ULL,
|
||||
1000000000ULL,
|
||||
10000000000ULL,
|
||||
100000000000ULL,
|
||||
1000000000000ULL,
|
||||
10000000000000ULL,
|
||||
100000000000000ULL,
|
||||
1000000000000000ULL,
|
||||
10000000000000000ULL,
|
||||
100000000000000000ULL,
|
||||
1000000000000000000ULL,
|
||||
10000000000000000000ULL
|
||||
};
|
||||
size_ = std::extent<
|
||||
decltype(list)>::value;
|
||||
begin_ = &list[0];
|
||||
end_ = &list[size_];
|
||||
}
|
||||
};
|
||||
default:
|
||||
case kind::type_double:
|
||||
double_ = other.double_;
|
||||
break;
|
||||
|
||||
static pow10_impl const tab;
|
||||
return tab;
|
||||
case kind::type_int64:
|
||||
int64_ = other.int64_;
|
||||
break;
|
||||
|
||||
case kind::type_uint64:
|
||||
uint64_ = other.uint64_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
std::size_t size_;
|
||||
mantissa_type const* begin_;
|
||||
mantissa_type const* end_;
|
||||
};
|
||||
number::
|
||||
number(
|
||||
number const& other,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
, k_(other.k_)
|
||||
{
|
||||
switch(k_)
|
||||
{
|
||||
default:
|
||||
case kind::type_double:
|
||||
double_ = other.double_;
|
||||
break;
|
||||
|
||||
case kind::type_int64:
|
||||
int64_ = other.int64_;
|
||||
break;
|
||||
|
||||
case kind::type_uint64:
|
||||
uint64_ = other.uint64_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
number::
|
||||
number(number&& other)
|
||||
: sp_(other.sp_)
|
||||
, k_(other.k_)
|
||||
{
|
||||
switch(k_)
|
||||
{
|
||||
default:
|
||||
case kind::type_double:
|
||||
double_ = other.double_;
|
||||
break;
|
||||
|
||||
case kind::type_int64:
|
||||
int64_ = other.int64_;
|
||||
break;
|
||||
|
||||
case kind::type_uint64:
|
||||
uint64_ = other.uint64_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
number::
|
||||
number(
|
||||
number&& other,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
, k_(other.k_)
|
||||
{
|
||||
switch(k_)
|
||||
{
|
||||
default:
|
||||
case kind::type_double:
|
||||
double_ = other.double_;
|
||||
break;
|
||||
|
||||
case kind::type_int64:
|
||||
int64_ = other.int64_;
|
||||
break;
|
||||
|
||||
case kind::type_uint64:
|
||||
uint64_ = other.uint64_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
number&
|
||||
number::
|
||||
operator=(number const& other)
|
||||
{
|
||||
k_ = other.k_;
|
||||
switch(k_)
|
||||
{
|
||||
default:
|
||||
case kind::type_double:
|
||||
double_ = other.double_;
|
||||
break;
|
||||
|
||||
case kind::type_int64:
|
||||
int64_ = other.int64_;
|
||||
break;
|
||||
|
||||
case kind::type_uint64:
|
||||
uint64_ = other.uint64_;
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
@ -111,9 +206,8 @@ number(
|
||||
auto const as_double =
|
||||
[&]
|
||||
{
|
||||
double d =
|
||||
static_cast<double>(mant) *
|
||||
std::pow(10.0, exp);
|
||||
double d = static_cast<
|
||||
double>(mant) * detail::pow10(exp);
|
||||
if(sign)
|
||||
d *= -1;
|
||||
return d;
|
||||
@ -234,21 +328,17 @@ is_int64() const noexcept
|
||||
{
|
||||
switch(k_)
|
||||
{
|
||||
case type_int64:
|
||||
default:
|
||||
case kind::type_int64:
|
||||
return true;
|
||||
|
||||
case type_uint64:
|
||||
case kind::type_uint64:
|
||||
return int64_ >= 0;
|
||||
|
||||
case type_double:
|
||||
case kind::type_double:
|
||||
return static_cast<long long>(
|
||||
double_) == double_;
|
||||
|
||||
default:
|
||||
case type_ieee:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -257,22 +347,18 @@ is_uint64() const noexcept
|
||||
{
|
||||
switch(k_)
|
||||
{
|
||||
case type_int64:
|
||||
default:
|
||||
case kind::type_int64:
|
||||
return int64_ >= 0;
|
||||
|
||||
case type_uint64:
|
||||
case kind::type_uint64:
|
||||
return true;
|
||||
|
||||
case type_double:
|
||||
case kind::type_double:
|
||||
return static_cast<
|
||||
unsigned long long>(
|
||||
double_) == double_;
|
||||
|
||||
default:
|
||||
case type_ieee:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::int_least64_t
|
||||
@ -281,22 +367,18 @@ get_int64() const noexcept
|
||||
{
|
||||
switch(k_)
|
||||
{
|
||||
case type_int64:
|
||||
default:
|
||||
case kind::type_int64:
|
||||
return int64_;
|
||||
|
||||
case type_uint64:
|
||||
case kind::type_uint64:
|
||||
return static_cast<
|
||||
long long>(uint64_);
|
||||
|
||||
case type_double:
|
||||
case kind::type_double:
|
||||
return static_cast<
|
||||
long long>(double_);
|
||||
|
||||
default:
|
||||
case type_ieee:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::uint_least64_t
|
||||
@ -305,22 +387,18 @@ get_uint64() const noexcept
|
||||
{
|
||||
switch(k_)
|
||||
{
|
||||
case type_int64:
|
||||
default:
|
||||
case kind::type_int64:
|
||||
return static_cast<
|
||||
unsigned long long>(int64_);
|
||||
|
||||
case type_uint64:
|
||||
case kind::type_uint64:
|
||||
return uint64_;
|
||||
|
||||
case type_double:
|
||||
case kind::type_double:
|
||||
return static_cast<
|
||||
unsigned long long>(double_);
|
||||
|
||||
default:
|
||||
case type_ieee:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
double
|
||||
@ -329,20 +407,16 @@ get_double() const noexcept
|
||||
{
|
||||
switch(k_)
|
||||
{
|
||||
case type_int64:
|
||||
default:
|
||||
case kind::type_int64:
|
||||
return static_cast<double>(int64_);
|
||||
|
||||
case type_uint64:
|
||||
case kind::type_uint64:
|
||||
return static_cast<double>(uint64_);
|
||||
|
||||
case type_double:
|
||||
case kind::type_double:
|
||||
return double_;
|
||||
|
||||
default:
|
||||
case type_ieee:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
string_view
|
||||
@ -354,25 +428,20 @@ print(
|
||||
int n;
|
||||
switch(k_)
|
||||
{
|
||||
case type_int64:
|
||||
default:
|
||||
case kind::type_int64:
|
||||
n = snprintf(buf, buf_size,
|
||||
"%lld", int64_);
|
||||
break;
|
||||
|
||||
case type_uint64:
|
||||
case kind::type_uint64:
|
||||
n = snprintf(buf, buf_size,
|
||||
"%llu", uint64_);
|
||||
break;
|
||||
|
||||
case type_double:
|
||||
case kind::type_double:
|
||||
n = detail::ryu::d2s_buffered_n(double_, buf);
|
||||
break;
|
||||
|
||||
default:
|
||||
case type_ieee:
|
||||
n = snprintf(buf, buf_size,
|
||||
"_unimpl");
|
||||
break;
|
||||
}
|
||||
return { buf, static_cast<
|
||||
std::size_t>(n) };
|
||||
@ -384,7 +453,7 @@ void
|
||||
number::
|
||||
assign_signed(long long i) noexcept
|
||||
{
|
||||
k_ = type_int64;
|
||||
k_ = kind::type_int64;
|
||||
int64_ = i;
|
||||
}
|
||||
|
||||
@ -392,7 +461,7 @@ void
|
||||
number::
|
||||
assign_unsigned(unsigned long long i) noexcept
|
||||
{
|
||||
k_ = type_uint64;
|
||||
k_ = kind::type_uint64;
|
||||
uint64_ = i;
|
||||
}
|
||||
|
||||
@ -400,7 +469,7 @@ void
|
||||
number::
|
||||
assign_double(double f) noexcept
|
||||
{
|
||||
k_ = type_double;
|
||||
k_ = kind::type_double;
|
||||
double_ = f;
|
||||
}
|
||||
|
||||
@ -421,28 +490,24 @@ operator==(
|
||||
{
|
||||
switch(lhs.k_)
|
||||
{
|
||||
case number::type_int64:
|
||||
default:
|
||||
case number::kind::type_int64:
|
||||
return
|
||||
rhs.is_int64() &&
|
||||
lhs.get_int64() ==
|
||||
rhs.get_int64();
|
||||
|
||||
case number::type_uint64:
|
||||
case number::kind::type_uint64:
|
||||
return
|
||||
rhs.is_uint64() &&
|
||||
lhs.get_uint64() ==
|
||||
rhs.get_uint64();
|
||||
|
||||
case number::type_double:
|
||||
case number::kind::type_double:
|
||||
return
|
||||
lhs.get_double() ==
|
||||
rhs.get_double();
|
||||
|
||||
default:
|
||||
case number::type_ieee:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -112,7 +112,9 @@ to_json(char const* t, value& v)
|
||||
template<class T
|
||||
,class = typename std::enable_if<
|
||||
std::is_constructible<number, T>::value &&
|
||||
! std::is_same<number, T>::value>::type
|
||||
! std::is_same<number, T>::value &&
|
||||
! std::is_convertible<T, storage_ptr>::value
|
||||
>::type
|
||||
>
|
||||
inline
|
||||
void
|
||||
|
@ -90,12 +90,12 @@ value::
|
||||
break;
|
||||
|
||||
case json::kind::number:
|
||||
nat_.num_.~number();
|
||||
BOOST_FALLTHROUGH;
|
||||
num_.~number();
|
||||
break;
|
||||
|
||||
case json::kind::boolean:
|
||||
case json::kind::null:
|
||||
nat_.sp_.~storage_ptr();
|
||||
sp_.~storage_ptr();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -139,19 +139,18 @@ value(
|
||||
break;
|
||||
|
||||
case json::kind::number:
|
||||
::new(&nat_.num_) number;
|
||||
::new(&nat_.sp_)
|
||||
storage_ptr(std::move(sp));
|
||||
::new(&num_) number(
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::boolean:
|
||||
::new(&nat_.bool_) bool{};
|
||||
::new(&nat_.sp_)
|
||||
::new(&bool_) bool{};
|
||||
::new(&sp_)
|
||||
storage_ptr(std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::null:
|
||||
::new(&nat_.sp_)
|
||||
::new(&sp_)
|
||||
storage_ptr(std::move(sp));
|
||||
break;
|
||||
}
|
||||
@ -189,20 +188,18 @@ value(
|
||||
break;
|
||||
|
||||
case json::kind::number:
|
||||
::new(&nat_.num_) number(
|
||||
other.nat_.num_);
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
std::move(sp));
|
||||
::new(&num_) number(
|
||||
other.num_, std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::boolean:
|
||||
nat_.bool_ = other.nat_.bool_;
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
bool_ = other.bool_;
|
||||
::new(&sp_) storage_ptr(
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::null:
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
::new(&sp_) storage_ptr(
|
||||
std::move(sp));
|
||||
break;
|
||||
}
|
||||
@ -217,34 +214,33 @@ value(pilfered<value> p) noexcept
|
||||
{
|
||||
case json::kind::object:
|
||||
relocate(&obj_, other.obj_);
|
||||
::new(&other.nat_.sp_) storage_ptr;
|
||||
::new(&other.sp_) storage_ptr;
|
||||
break;
|
||||
|
||||
case json::kind::array:
|
||||
relocate(&arr_, other.arr_);
|
||||
::new(&other.nat_.sp_) storage_ptr;
|
||||
::new(&other.sp_) storage_ptr;
|
||||
break;
|
||||
|
||||
case json::kind::string:
|
||||
relocate(&str_, other.str_);
|
||||
::new(&other.nat_.sp_) storage_ptr;
|
||||
::new(&other.sp_) storage_ptr;
|
||||
break;
|
||||
|
||||
case json::kind::number:
|
||||
relocate(&nat_.num_, other.nat_.num_);
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
std::move(other.nat_.sp_));
|
||||
relocate(&num_, other.num_);
|
||||
::new(&other.sp_) storage_ptr;
|
||||
break;
|
||||
|
||||
case json::kind::boolean:
|
||||
nat_.bool_ = other.nat_.bool_;
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
std::move(other.nat_.sp_));
|
||||
bool_ = other.bool_;
|
||||
::new(&sp_) storage_ptr(
|
||||
std::move(other.sp_));
|
||||
break;
|
||||
|
||||
case json::kind::null:
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
std::move(other.nat_.sp_));
|
||||
::new(&sp_) storage_ptr(
|
||||
std::move(other.sp_));
|
||||
break;
|
||||
}
|
||||
kind_ = other.kind_;
|
||||
@ -272,21 +268,19 @@ value(value&& other) noexcept
|
||||
break;
|
||||
|
||||
case json::kind::number:
|
||||
::new(&nat_.num_) number(
|
||||
std::move(other.nat_.num_));
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
other.nat_.sp_);
|
||||
::new(&num_) number(
|
||||
std::move(other.num_));
|
||||
break;
|
||||
|
||||
case json::kind::boolean:
|
||||
nat_.bool_ = other.nat_.bool_;
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
other.nat_.sp_);
|
||||
bool_ = other.bool_;
|
||||
::new(&sp_) storage_ptr(
|
||||
other.sp_);
|
||||
break;
|
||||
|
||||
case json::kind::null:
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
other.nat_.sp_);
|
||||
::new(&sp_) storage_ptr(
|
||||
other.sp_);
|
||||
break;
|
||||
}
|
||||
kind_ = other.kind_;
|
||||
@ -318,20 +312,19 @@ value(
|
||||
break;
|
||||
|
||||
case json::kind::number:
|
||||
relocate(
|
||||
&nat_.num_, other.nat_.num_);
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
::new(&num_) number(
|
||||
std::move(other.num_),
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::boolean:
|
||||
nat_.bool_ = other.nat_.bool_;
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
bool_ = other.bool_;
|
||||
::new(&sp_) storage_ptr(
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::null:
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
::new(&sp_) storage_ptr(
|
||||
std::move(sp));
|
||||
break;
|
||||
}
|
||||
@ -428,9 +421,8 @@ value::
|
||||
value(number num) noexcept
|
||||
: kind_(json::kind::number)
|
||||
{
|
||||
::new(&nat_.num_) number(num);
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
default_storage());
|
||||
::new(&num_) number(
|
||||
std::move(num));
|
||||
}
|
||||
|
||||
value::
|
||||
@ -439,8 +431,8 @@ value(
|
||||
storage_ptr sp)
|
||||
: kind_(json::kind::number)
|
||||
{
|
||||
::new(&nat_.num_) number(num);
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
::new(&num_) number(
|
||||
std::move(num),
|
||||
std::move(sp));
|
||||
}
|
||||
|
||||
@ -551,10 +543,16 @@ reset(json::kind k) noexcept
|
||||
}
|
||||
|
||||
case json::kind::number:
|
||||
{
|
||||
sp = num_.release_storage();
|
||||
num_.~number();
|
||||
break;
|
||||
}
|
||||
|
||||
case json::kind::boolean:
|
||||
case json::kind::null:
|
||||
{
|
||||
sp = std::move(nat_.sp_);
|
||||
sp = std::move(sp_);
|
||||
this->~value();
|
||||
break;
|
||||
}
|
||||
@ -578,11 +576,11 @@ reset(json::kind k) noexcept
|
||||
break;
|
||||
|
||||
case json::kind::number:
|
||||
nat_.num_ = 0;
|
||||
num_ = 0;
|
||||
break;
|
||||
|
||||
case json::kind::boolean:
|
||||
nat_.bool_ = false;
|
||||
bool_ = false;
|
||||
break;
|
||||
|
||||
case json::kind::null:
|
||||
@ -671,10 +669,13 @@ get_storage() const noexcept
|
||||
case json::kind::string:
|
||||
return str_.get_storage();
|
||||
|
||||
case json::kind::number:
|
||||
return num_.get_storage();
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nat_.sp_;
|
||||
return sp_;
|
||||
}
|
||||
|
||||
} // json
|
||||
|
@ -11,7 +11,9 @@
|
||||
#define BOOST_JSON_NUMBER_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/storage.hpp>
|
||||
#include <boost/json/detail/string.hpp>
|
||||
#include <boost/pilfer.hpp>
|
||||
#include <cstdint>
|
||||
#include <iosfwd>
|
||||
#include <type_traits>
|
||||
@ -30,22 +32,15 @@ struct ieee_decimal
|
||||
*/
|
||||
class number
|
||||
{
|
||||
struct base10_ieee
|
||||
{
|
||||
unsigned
|
||||
long long mant;
|
||||
short exp;
|
||||
bool sign;
|
||||
};
|
||||
|
||||
enum kind
|
||||
enum class kind : char
|
||||
{
|
||||
type_int64,
|
||||
type_uint64,
|
||||
type_double,
|
||||
type_ieee
|
||||
type_double
|
||||
};
|
||||
|
||||
storage_ptr sp_;
|
||||
|
||||
#ifndef GENERATING_DOCUMENTATION
|
||||
// The XSLT has problems with private anon unions
|
||||
union
|
||||
@ -54,7 +49,6 @@ class number
|
||||
long long uint64_;
|
||||
long long int64_;
|
||||
double double_;
|
||||
base10_ieee ieee_;
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -80,14 +74,42 @@ public:
|
||||
using exponent_type =
|
||||
short;
|
||||
|
||||
number(number const&) = default;
|
||||
number& operator=(number const&) = default;
|
||||
//------------------------------------------------------
|
||||
|
||||
number() noexcept
|
||||
: k_(type_int64)
|
||||
{
|
||||
int64_ = 0;
|
||||
}
|
||||
BOOST_JSON_DECL
|
||||
~number();
|
||||
|
||||
BOOST_JSON_DECL
|
||||
number() noexcept;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
explicit
|
||||
number(storage_ptr sp) noexcept;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
number(pilfered<number> other) noexcept;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
number(number const& other);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
number(
|
||||
number const& other,
|
||||
storage_ptr sp);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
number(number&& other);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
number(
|
||||
number&& other,
|
||||
storage_ptr sp);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
number&
|
||||
operator=(number const& other);
|
||||
|
||||
//------------------------------------------------------
|
||||
|
||||
/** Construct a number from mantissa, exponent, and sign
|
||||
*/
|
||||
@ -141,6 +163,12 @@ public:
|
||||
BOOST_JSON_DECL
|
||||
number(long double v) noexcept;
|
||||
|
||||
storage_ptr const&
|
||||
get_storage() const noexcept
|
||||
{
|
||||
return sp_;
|
||||
}
|
||||
|
||||
/// Return true if the number is negative
|
||||
BOOST_JSON_DECL
|
||||
bool
|
||||
@ -232,6 +260,16 @@ private:
|
||||
operator!=(
|
||||
number const& lhs,
|
||||
number const& rhs) noexcept;
|
||||
|
||||
|
||||
inline
|
||||
storage_ptr
|
||||
release_storage() noexcept
|
||||
{
|
||||
return std::move(sp_);
|
||||
}
|
||||
|
||||
friend class value;
|
||||
};
|
||||
|
||||
BOOST_JSON_DECL
|
||||
|
@ -108,26 +108,18 @@ class value
|
||||
|
||||
#ifndef GENERATING_DOCUMENTATION
|
||||
// XSL scripts have trouble with private anon unions
|
||||
struct native
|
||||
{
|
||||
union
|
||||
{
|
||||
number num_;
|
||||
bool bool_;
|
||||
};
|
||||
storage_ptr sp_;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
object obj_;
|
||||
array arr_;
|
||||
string str_;
|
||||
native nat_;
|
||||
object obj_;
|
||||
array arr_;
|
||||
string str_;
|
||||
number num_;
|
||||
storage_ptr sp_;
|
||||
};
|
||||
#endif
|
||||
|
||||
json::kind kind_;
|
||||
bool bool_;
|
||||
|
||||
public:
|
||||
/// Destroy a value and all of its contents
|
||||
@ -539,7 +531,7 @@ public:
|
||||
emplace_number() noexcept
|
||||
{
|
||||
reset(json::kind::number);
|
||||
return nat_.num_;
|
||||
return num_;
|
||||
}
|
||||
|
||||
/** Set the value to boolean false, and return it.
|
||||
@ -560,7 +552,7 @@ public:
|
||||
emplace_bool() noexcept
|
||||
{
|
||||
reset(json::kind::boolean);
|
||||
return nat_.bool_;
|
||||
return bool_;
|
||||
}
|
||||
|
||||
/** Set the value to null.
|
||||
@ -1049,7 +1041,7 @@ public:
|
||||
if_number() noexcept
|
||||
{
|
||||
if(kind_ == json::kind::number)
|
||||
return &nat_.num_;
|
||||
return &num_;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1071,7 +1063,7 @@ public:
|
||||
if_number() const noexcept
|
||||
{
|
||||
if(kind_ == json::kind::number)
|
||||
return &nat_.num_;
|
||||
return &num_;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1093,7 +1085,7 @@ public:
|
||||
if_bool() noexcept
|
||||
{
|
||||
if(kind_ == json::kind::boolean)
|
||||
return &nat_.bool_;
|
||||
return &bool_;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1115,7 +1107,7 @@ public:
|
||||
if_bool() const noexcept
|
||||
{
|
||||
if(kind_ == json::kind::boolean)
|
||||
return &nat_.bool_;
|
||||
return &bool_;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1300,7 +1292,7 @@ public:
|
||||
BOOST_JSON_THROW(
|
||||
system_error(
|
||||
error::not_number));
|
||||
return nat_.num_;
|
||||
return num_;
|
||||
}
|
||||
|
||||
/** Return a reference to the number, or throw an exception.
|
||||
@ -1326,7 +1318,7 @@ public:
|
||||
BOOST_JSON_THROW(
|
||||
system_error(
|
||||
error::not_number));
|
||||
return nat_.num_;
|
||||
return num_;
|
||||
}
|
||||
|
||||
/** Return a reference to the bool, or throw an exception.
|
||||
@ -1352,7 +1344,7 @@ public:
|
||||
BOOST_JSON_THROW(
|
||||
system_error(
|
||||
error::not_bool));
|
||||
return nat_.bool_;
|
||||
return bool_;
|
||||
}
|
||||
|
||||
/** Return a reference to the bool, or throw an exception.
|
||||
@ -1378,7 +1370,7 @@ public:
|
||||
BOOST_JSON_THROW(
|
||||
system_error(
|
||||
error::not_bool));
|
||||
return nat_.bool_;
|
||||
return bool_;
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user