Better number handling

This commit is contained in:
Vinnie Falco 2019-10-24 05:23:30 -07:00
parent 6fa86cb0f0
commit b1e03f7326
7 changed files with 476 additions and 287 deletions

View File

@ -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);
}
}
}

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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_;
}
//------------------------------------------------------