mirror of
https://github.com/boostorg/json.git
synced 2025-05-11 05:33:57 +00:00
Fixes
This commit is contained in:
parent
adcebea5a9
commit
a0e46853a8
@ -325,8 +325,13 @@ struct nlohmann_impl : public any_impl
|
||||
}
|
||||
|
||||
void
|
||||
serialize(string_view, int) const override
|
||||
serialize(string_view s, int repeat) const override
|
||||
{
|
||||
auto jv = nlohmann::json::parse(
|
||||
s.begin(), s.end());
|
||||
while(repeat--)
|
||||
auto s = jv.dump();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@ -369,7 +374,7 @@ benchParse(
|
||||
std::endl;
|
||||
for(unsigned j = 0; j < vi.size(); ++j)
|
||||
{
|
||||
for(unsigned k = 0; k < 10; ++k)
|
||||
for(unsigned k = 0; k < 7; ++k)
|
||||
{
|
||||
auto const when = clock_type::now();
|
||||
vi[j]->parse(vs[i].text, 250);
|
||||
@ -401,14 +406,14 @@ benchSerialize(
|
||||
std::endl;
|
||||
for(unsigned j = 0; j < vi.size(); ++j)
|
||||
{
|
||||
for(unsigned k = 0; k < 5; ++k)
|
||||
for(unsigned k = 0; k < 7; ++k)
|
||||
{
|
||||
auto const when = clock_type::now();
|
||||
vi[j]->serialize(vs[i].text, 1000);
|
||||
auto const ms = std::chrono::duration_cast<
|
||||
std::chrono::milliseconds>(
|
||||
clock_type::now() - when).count();
|
||||
if(k > 9)
|
||||
if(k > 4)
|
||||
dout << " " << vi[j]->name() << ": " <<
|
||||
std::to_string(ms) << "ms" <<
|
||||
std::endl;
|
||||
@ -442,13 +447,13 @@ main(
|
||||
std::vector<std::unique_ptr<any_impl const>> vi;
|
||||
vi.reserve(10);
|
||||
//vi.emplace_back(new boost_default_impl);
|
||||
vi.emplace_back(new boost_impl);
|
||||
//.emplace_back(new boost_impl);
|
||||
//vi.emplace_back(new boost_vec_impl);
|
||||
vi.emplace_back(new rapidjson_impl);
|
||||
//vi.emplace_back(new nlohmann_impl);
|
||||
//vi.emplace_back(new rapidjson_impl);
|
||||
vi.emplace_back(new nlohmann_impl);
|
||||
|
||||
benchParse(vs, vi);
|
||||
//benchSerialize(vs, vi);
|
||||
//benchParse(vs, vi);
|
||||
benchSerialize(vs, vi);
|
||||
}
|
||||
catch(system_error const& se)
|
||||
{
|
||||
|
@ -487,6 +487,7 @@ public:
|
||||
std::initializer_list<value> init,
|
||||
storage_ptr sp = {});
|
||||
|
||||
explicit
|
||||
BOOST_JSON_DECL
|
||||
array(unchecked_array&& ua);
|
||||
|
||||
@ -1594,6 +1595,11 @@ private:
|
||||
impl_type& operator=(
|
||||
impl_type const&) = default;
|
||||
|
||||
inline
|
||||
impl_type(
|
||||
size_type capacity,
|
||||
storage_ptr const& sp);
|
||||
|
||||
inline
|
||||
impl_type&
|
||||
operator=(
|
||||
@ -1611,12 +1617,6 @@ private:
|
||||
void
|
||||
swap(impl_type& rhs) noexcept;
|
||||
|
||||
inline
|
||||
void
|
||||
construct(
|
||||
size_type capacity,
|
||||
storage_ptr const& sp);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
void
|
||||
destroy(storage_ptr const& sp) noexcept;
|
||||
@ -1636,7 +1636,7 @@ private:
|
||||
array(
|
||||
InputIt first, InputIt last,
|
||||
storage_ptr sp,
|
||||
std::random_access_iterator_tag);
|
||||
std::forward_iterator_tag);
|
||||
|
||||
template<class InputIt>
|
||||
iterator
|
||||
@ -1650,7 +1650,7 @@ private:
|
||||
insert(
|
||||
const_iterator pos,
|
||||
InputIt first, InputIt last,
|
||||
std::random_access_iterator_tag);
|
||||
std::forward_iterator_tag);
|
||||
|
||||
inline
|
||||
void
|
||||
@ -1686,7 +1686,7 @@ private:
|
||||
class undo_assign;
|
||||
class undo_insert;
|
||||
|
||||
storage_ptr sp_;
|
||||
storage_ptr sp_; // must come first
|
||||
impl_type impl_;
|
||||
};
|
||||
|
||||
|
@ -420,12 +420,13 @@ array::
|
||||
array(
|
||||
InputIt first, InputIt last,
|
||||
storage_ptr sp,
|
||||
std::random_access_iterator_tag)
|
||||
std::forward_iterator_tag)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
undo_create u(*this);
|
||||
auto const n = static_cast<
|
||||
unsigned long long>(last - first);
|
||||
auto const n =
|
||||
static_cast<std::size_t>(
|
||||
std::distance(first, last));
|
||||
if(n > max_size())
|
||||
BOOST_JSON_THROW(
|
||||
std::length_error(
|
||||
@ -471,11 +472,12 @@ array::
|
||||
insert(
|
||||
const_iterator pos,
|
||||
InputIt first, InputIt last,
|
||||
std::random_access_iterator_tag) ->
|
||||
std::forward_iterator_tag) ->
|
||||
iterator
|
||||
{
|
||||
auto const n = static_cast<
|
||||
unsigned long long>(last - first);
|
||||
auto const n =
|
||||
static_cast<std::size_t>(
|
||||
std::distance(first, last));
|
||||
if(n > max_size())
|
||||
BOOST_JSON_THROW(
|
||||
std::length_error(
|
||||
|
@ -24,6 +24,25 @@ namespace json {
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
array::
|
||||
impl_type::
|
||||
impl_type(
|
||||
size_type capacity_,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
// The choice of minimum capacity
|
||||
// affects the speed of parsing.
|
||||
// if( capacity_ < min_capacity_)
|
||||
// capacity_ = min_capacity_;
|
||||
vec = reinterpret_cast<value*>(
|
||||
sp->allocate(
|
||||
capacity_ * sizeof(value),
|
||||
alignof(value)));
|
||||
size = 0;
|
||||
capacity = capacity_;
|
||||
}
|
||||
|
||||
|
||||
array::
|
||||
impl_type::
|
||||
impl_type(impl_type&& other) noexcept
|
||||
@ -76,25 +95,6 @@ destroy(
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
array::
|
||||
impl_type::
|
||||
construct(
|
||||
size_type capacity_,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
// The choice of minimum capacity
|
||||
// affects the speed of parsing.
|
||||
if( capacity_ < min_capacity_)
|
||||
capacity_ = min_capacity_;
|
||||
vec = reinterpret_cast<value*>(
|
||||
sp->allocate(
|
||||
capacity_ * sizeof(value),
|
||||
alignof(value)));
|
||||
size = 0;
|
||||
capacity = capacity_;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
array::
|
||||
@ -281,12 +281,10 @@ array(
|
||||
array::
|
||||
array(unchecked_array&& ua)
|
||||
: sp_(ua.get_storage())
|
||||
, impl_(ua.size(), sp_) // exact
|
||||
{
|
||||
undo_create u(*this);
|
||||
reserve(ua.size());
|
||||
impl_.size = ua.size();
|
||||
ua.relocate(impl_.vec);
|
||||
u.commit = true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
@ -346,13 +344,18 @@ shrink_to_fit() noexcept
|
||||
impl_.capacity <= min_capacity_)
|
||||
return;
|
||||
|
||||
impl_type impl;
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
impl.construct(
|
||||
impl_.size, sp_);
|
||||
impl_type impl(impl_.size, sp_);
|
||||
relocate(
|
||||
impl.vec,
|
||||
impl_.vec, impl_.size);
|
||||
impl.size = impl_.size;
|
||||
impl_.size = 0;
|
||||
impl_.swap(impl);
|
||||
impl.destroy(sp_);
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch(...)
|
||||
@ -361,14 +364,6 @@ shrink_to_fit() noexcept
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
relocate(
|
||||
impl.vec,
|
||||
impl_.vec, impl_.size);
|
||||
impl.size = impl_.size;
|
||||
impl_.size = 0;
|
||||
impl_.swap(impl);
|
||||
impl.destroy(sp_);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
@ -628,15 +623,16 @@ reserve_impl(size_type capacity)
|
||||
else if(capacity < hint)
|
||||
capacity = hint;
|
||||
}
|
||||
impl_type impl;
|
||||
impl.construct(capacity, sp_);
|
||||
if( capacity < min_capacity_)
|
||||
capacity = min_capacity_;
|
||||
impl_type impl(capacity, sp_);
|
||||
relocate(
|
||||
impl.vec,
|
||||
impl_.vec, impl_.size);
|
||||
impl.size = impl_.size;
|
||||
impl_.size = 0;
|
||||
impl_.swap(impl);
|
||||
impl.destroy(sp_);
|
||||
impl_.destroy(sp_);
|
||||
impl_ = impl;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include <boost/json/detail/except.hpp>
|
||||
#include <boost/json/detail/exchange.hpp>
|
||||
#include <boost/json/detail/string.hpp>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <cmath>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@ -123,66 +123,35 @@ bucket_end() const noexcept ->
|
||||
return bucket_begin() + buckets();
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
class object::undo_construct
|
||||
struct object::undo_construct
|
||||
{
|
||||
object& self_;
|
||||
|
||||
public:
|
||||
bool commit = false;
|
||||
object* self;
|
||||
|
||||
~undo_construct()
|
||||
{
|
||||
if(! commit)
|
||||
self_.impl_.destroy(
|
||||
self_.sp_);
|
||||
}
|
||||
|
||||
explicit
|
||||
undo_construct(
|
||||
object& self) noexcept
|
||||
: self_(self)
|
||||
{
|
||||
if(self)
|
||||
self->impl_.destroy(
|
||||
self->sp_);
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
class object::undo_insert
|
||||
struct object::place_one
|
||||
{
|
||||
object& self_;
|
||||
virtual
|
||||
void
|
||||
operator()(void* dest) = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
value_type* const first;
|
||||
value_type* last;
|
||||
bool commit = false;
|
||||
|
||||
~undo_insert()
|
||||
{
|
||||
if(commit)
|
||||
{
|
||||
self_.impl_.grow(last - first);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(auto it = first; it != last; ++it)
|
||||
self_.impl_.remove(
|
||||
self_.impl_.bucket(it->key()), it);
|
||||
value_type::destroy(
|
||||
first, static_cast<
|
||||
std::size_t>(last - first));
|
||||
}
|
||||
}
|
||||
|
||||
explicit
|
||||
undo_insert(
|
||||
object& self) noexcept
|
||||
: self_(self)
|
||||
, first(self_.impl_.end())
|
||||
, last(first)
|
||||
{
|
||||
}
|
||||
struct object::place_range
|
||||
{
|
||||
virtual
|
||||
bool
|
||||
operator()(void* dest) = 0;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
@ -200,11 +169,11 @@ object(
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
undo_construct u(*this);
|
||||
undo_construct u{this};
|
||||
insert_range(
|
||||
first, last,
|
||||
min_capacity);
|
||||
u.commit = true;
|
||||
u.self = nullptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
@ -355,22 +324,30 @@ object::
|
||||
insert(P&& p) ->
|
||||
std::pair<iterator, bool>
|
||||
{
|
||||
reserve(size() + 1);
|
||||
auto& e = *::new(
|
||||
impl_.end()) value_type(
|
||||
std::forward<P>(p), sp_);
|
||||
auto const result = find_impl(e.key());
|
||||
if(result.first)
|
||||
struct place_impl : place_one
|
||||
{
|
||||
e.~value_type();
|
||||
return { result.first, false };
|
||||
}
|
||||
auto& head =
|
||||
impl_.bucket(result.second);
|
||||
e.next_ = head;
|
||||
head = &e;
|
||||
impl_.grow(1);
|
||||
return { &e, true };
|
||||
P&& p;
|
||||
storage_ptr const& sp;
|
||||
|
||||
place_impl(
|
||||
P&& p_,
|
||||
storage_ptr const& sp_)
|
||||
: p(std::forward<P>(p_))
|
||||
, sp(sp_)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(void* dest) override
|
||||
{
|
||||
::new(dest) value_type(
|
||||
std::forward<P>(p), sp);
|
||||
}
|
||||
};
|
||||
|
||||
place_impl f(
|
||||
std::forward<P>(p), sp_);
|
||||
return insert_impl(f);
|
||||
}
|
||||
|
||||
template<class M>
|
||||
@ -380,6 +357,30 @@ insert_or_assign(
|
||||
key_type key, M&& m) ->
|
||||
std::pair<iterator, bool>
|
||||
{
|
||||
struct place_impl : place_one
|
||||
{
|
||||
key_type key;
|
||||
M&& m;
|
||||
storage_ptr const& sp;
|
||||
|
||||
place_impl(
|
||||
key_type key_,
|
||||
M&& m_,
|
||||
storage_ptr const& sp_)
|
||||
: key(key_)
|
||||
, m(std::forward<M>(m_))
|
||||
, sp(sp_)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(void* dest) override
|
||||
{
|
||||
::new(dest) value_type(key,
|
||||
std::forward<M>(m), sp);
|
||||
}
|
||||
};
|
||||
|
||||
auto const result = find_impl(key);
|
||||
if(result.first)
|
||||
{
|
||||
@ -387,16 +388,11 @@ insert_or_assign(
|
||||
std::forward<M>(m);
|
||||
return { result.first, false };
|
||||
}
|
||||
reserve(size() + 1);
|
||||
auto& e = *::new(
|
||||
impl_.end()) value_type(
|
||||
key, std::forward<M>(m), sp_);
|
||||
auto& head =
|
||||
impl_.bucket(result.second);
|
||||
e.next_ = head;
|
||||
head = &e;
|
||||
impl_.grow(1);
|
||||
return { &e, true };
|
||||
|
||||
place_impl f(key,
|
||||
std::forward<M>(m), sp_);
|
||||
return { insert_impl(
|
||||
result.second, f), true };
|
||||
}
|
||||
|
||||
template<class Arg>
|
||||
@ -407,17 +403,33 @@ emplace(
|
||||
Arg&& arg) ->
|
||||
std::pair<iterator, bool>
|
||||
{
|
||||
auto const result = find_impl(key);
|
||||
if(result.first)
|
||||
return { result.first, false };
|
||||
reserve(size() + 1);
|
||||
auto p = ::new(impl_.end()) value_type(
|
||||
key, std::forward<Arg>(arg), sp_);
|
||||
auto& head = impl_.bucket(result.second);
|
||||
p->next_ = head;
|
||||
head = p;
|
||||
impl_.grow(1);
|
||||
return { p, true };
|
||||
struct place_impl : place_one
|
||||
{
|
||||
key_type key;
|
||||
Arg&& arg;
|
||||
storage_ptr const& sp;
|
||||
|
||||
place_impl(
|
||||
key_type key_,
|
||||
Arg&& arg_,
|
||||
storage_ptr const& sp_)
|
||||
: key(key_)
|
||||
, arg(std::forward<Arg>(arg_))
|
||||
, sp(sp_)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(void* dest) override
|
||||
{
|
||||
::new(dest) value_type(key,
|
||||
std::forward<Arg>(arg), sp);
|
||||
}
|
||||
};
|
||||
|
||||
place_impl f(key,
|
||||
std::forward<Arg>(arg), sp_);
|
||||
return emplace_impl(key, f);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
@ -482,33 +494,15 @@ insert_range(
|
||||
std::size_t min_capacity,
|
||||
std::input_iterator_tag)
|
||||
{
|
||||
// Since input iterators cannot be rewound,
|
||||
// we keep inserted elements on an exception.
|
||||
//
|
||||
reserve(min_capacity);
|
||||
undo_insert u(*this);
|
||||
while(first != last)
|
||||
{
|
||||
reserve(size() + 1);
|
||||
auto& e = *::new(
|
||||
u.last) value_type(*first++, sp_);
|
||||
auto& head = impl_.bucket(e.key());
|
||||
for(auto it = head;;
|
||||
it = it->next_)
|
||||
{
|
||||
if(it)
|
||||
{
|
||||
if(it->key() != e.key())
|
||||
continue;
|
||||
e.~value_type();
|
||||
}
|
||||
else
|
||||
{
|
||||
e.next_ = head;
|
||||
head = &e;
|
||||
++u.last;
|
||||
}
|
||||
break;
|
||||
}
|
||||
insert(*first);
|
||||
++first;
|
||||
}
|
||||
u.commit = true;
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
@ -518,42 +512,44 @@ insert_range(
|
||||
InputIt first,
|
||||
InputIt last,
|
||||
std::size_t min_capacity,
|
||||
std::random_access_iterator_tag)
|
||||
std::forward_iterator_tag)
|
||||
{
|
||||
auto n = static_cast<
|
||||
std::size_t>(last - first);
|
||||
struct place_impl : place_range
|
||||
{
|
||||
InputIt it;
|
||||
std::size_t n;
|
||||
storage_ptr const& sp;
|
||||
|
||||
place_impl(
|
||||
InputIt it_,
|
||||
std::size_t n_,
|
||||
storage_ptr const& sp_)
|
||||
: it(it_)
|
||||
, n(n_)
|
||||
, sp(sp_)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
operator()(void* dest) override
|
||||
{
|
||||
if(n-- == 0)
|
||||
return false;
|
||||
::new(dest) value_type(*it++, sp);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
auto const n = static_cast<std::size_t>(
|
||||
std::distance(first, last));
|
||||
auto const n0 = size();
|
||||
if(n > max_size() - n0)
|
||||
BOOST_JSON_THROW(
|
||||
detail::object_too_large_exception());
|
||||
if( min_capacity < n0 + n)
|
||||
min_capacity = n0 + n;
|
||||
reserve(min_capacity);
|
||||
undo_insert u(*this);
|
||||
while(n--)
|
||||
{
|
||||
auto& e = *::new(
|
||||
u.last) value_type(*first++, sp_);
|
||||
auto& head = impl_.bucket(e.key());
|
||||
for(auto it = head;;
|
||||
it = it->next_)
|
||||
{
|
||||
if(it)
|
||||
{
|
||||
if(it->key() != e.key())
|
||||
continue;
|
||||
e.~value_type();
|
||||
}
|
||||
else
|
||||
{
|
||||
e.next_ = head;
|
||||
head = &e;
|
||||
++u.last;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
u.commit = true;
|
||||
place_impl f(first, n, sp_);
|
||||
insert_range_impl(min_capacity, f);
|
||||
}
|
||||
|
||||
} // json
|
||||
|
@ -148,6 +148,52 @@ swap(impl_type& rhs) noexcept
|
||||
rhs.tab_ = tmp;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
class object::undo_insert
|
||||
{
|
||||
object& self_;
|
||||
|
||||
public:
|
||||
std::size_t const first;
|
||||
std::size_t last;
|
||||
bool commit = false;
|
||||
|
||||
~undo_insert()
|
||||
{
|
||||
if(commit)
|
||||
{
|
||||
self_.impl_.grow(last - first);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto p0 = self_.impl_.begin() + first;
|
||||
auto p1 = self_.impl_.begin() + last;
|
||||
for(auto it = p0; it != p1; ++it)
|
||||
self_.impl_.remove(
|
||||
self_.impl_.bucket(it->key()), it);
|
||||
value_type::destroy(p0, last - first);
|
||||
}
|
||||
}
|
||||
|
||||
explicit
|
||||
undo_insert(
|
||||
object& self) noexcept
|
||||
: self_(self)
|
||||
, first(
|
||||
self_.impl_.end() -
|
||||
self_.impl_.begin())
|
||||
, last(first)
|
||||
{
|
||||
}
|
||||
|
||||
value_type*
|
||||
pos() noexcept
|
||||
{
|
||||
return self_.begin() + last;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// object
|
||||
@ -188,11 +234,11 @@ object(
|
||||
}
|
||||
else
|
||||
{
|
||||
undo_construct u(*this);
|
||||
undo_construct u{this};
|
||||
insert_range(
|
||||
other.begin(),
|
||||
other.end(), 0);
|
||||
u.commit = true;
|
||||
u.self = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,11 +254,11 @@ object(
|
||||
object const& other)
|
||||
: sp_(other.sp_)
|
||||
{
|
||||
undo_construct u(*this);
|
||||
undo_construct u{this};
|
||||
insert_range(
|
||||
other.begin(),
|
||||
other.end(), 0);
|
||||
u.commit = true;
|
||||
u.self = nullptr;
|
||||
}
|
||||
|
||||
object::
|
||||
@ -221,11 +267,11 @@ object(
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
undo_construct u(*this);
|
||||
undo_construct u{this};
|
||||
insert_range(
|
||||
other.begin(),
|
||||
other.end(), 0);
|
||||
u.commit = true;
|
||||
u.self = nullptr;
|
||||
}
|
||||
|
||||
object::
|
||||
@ -235,12 +281,12 @@ object(
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
undo_construct u(*this);
|
||||
undo_construct u{this};
|
||||
insert_range(
|
||||
init.begin(),
|
||||
init.end(),
|
||||
min_capacity);
|
||||
u.commit = true;
|
||||
u.self = nullptr;
|
||||
}
|
||||
|
||||
object::
|
||||
@ -565,6 +611,106 @@ rehash(std::size_t new_capacity)
|
||||
impl_.rebuild();
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
emplace_impl(
|
||||
key_type key,
|
||||
place_one& f) ->
|
||||
std::pair<iterator, bool>
|
||||
{
|
||||
auto const result = find_impl(key);
|
||||
if(result.first)
|
||||
return { result.first, false };
|
||||
reserve(size() + 1);
|
||||
auto& e = *impl_.end();
|
||||
f(&e);
|
||||
auto& head =
|
||||
impl_.bucket(result.second);
|
||||
e.next_ = head;
|
||||
head = &e;
|
||||
impl_.grow(1);
|
||||
return { &e, true };
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
insert_impl(
|
||||
place_one& f) ->
|
||||
std::pair<iterator, bool>
|
||||
{
|
||||
reserve(size() + 1);
|
||||
auto& e = *impl_.end();
|
||||
f(&e);
|
||||
auto const result =
|
||||
find_impl(e.key());
|
||||
if(result.first)
|
||||
{
|
||||
e.~value_type();
|
||||
return { result.first, false };
|
||||
}
|
||||
auto& head =
|
||||
impl_.bucket(result.second);
|
||||
e.next_ = head;
|
||||
head = &e;
|
||||
impl_.grow(1);
|
||||
return { &e, true };
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
insert_impl(
|
||||
std::size_t hash,
|
||||
place_one& f) ->
|
||||
iterator
|
||||
{
|
||||
reserve(size() + 1);
|
||||
auto& e = *impl_.end();
|
||||
f(&e);
|
||||
auto& head =
|
||||
impl_.bucket(hash);
|
||||
e.next_ = head;
|
||||
head = &e;
|
||||
impl_.grow(1);
|
||||
return &e;
|
||||
}
|
||||
|
||||
void
|
||||
object::
|
||||
insert_range_impl(
|
||||
std::size_t min_capacity,
|
||||
place_range& f)
|
||||
{
|
||||
reserve(min_capacity);
|
||||
undo_insert u(*this);
|
||||
for(;;)
|
||||
{
|
||||
reserve(size() + 1);
|
||||
auto& e = *u.pos();
|
||||
if(! f(&e))
|
||||
break;
|
||||
auto& head =
|
||||
impl_.bucket(e.key());
|
||||
for(auto it = head;;
|
||||
it = it->next_)
|
||||
{
|
||||
if(it)
|
||||
{
|
||||
if(it->key() != e.key())
|
||||
continue;
|
||||
e.~value_type();
|
||||
}
|
||||
else
|
||||
{
|
||||
e.next_ = head;
|
||||
head = &e;
|
||||
++u.last;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
u.commit = true;
|
||||
}
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
|
@ -97,6 +97,7 @@ void
|
||||
parser::
|
||||
on_document_begin(error_code&)
|
||||
{
|
||||
lev_ = level{ 0, false };
|
||||
st_.placeholder(sizeof(value));
|
||||
}
|
||||
|
||||
@ -115,7 +116,6 @@ void
|
||||
parser::
|
||||
on_object_begin(error_code&)
|
||||
{
|
||||
lev_ = level{ 0, false };
|
||||
st_.push(lev_);
|
||||
lev_ = level{ 0, true };
|
||||
st_.placeholder(sizeof(
|
||||
@ -204,6 +204,7 @@ on_key(
|
||||
st_.push(s);
|
||||
key_ += static_cast<size_type>(
|
||||
s.size());
|
||||
st_.align();
|
||||
st_.push(key_);
|
||||
key_ = 0;
|
||||
}
|
||||
|
@ -136,6 +136,20 @@ from_json(T& t, value const& v)
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
value::
|
||||
value(unchecked_object&& uo)
|
||||
: obj_(std::move(uo))
|
||||
, kind_(json::kind::object)
|
||||
{
|
||||
}
|
||||
|
||||
value::
|
||||
value(unchecked_array&& ua)
|
||||
: arr_(std::move(ua))
|
||||
, kind_(json::kind::array)
|
||||
{
|
||||
}
|
||||
|
||||
template<class Bool, class>
|
||||
value::
|
||||
value(Bool b, storage_ptr sp) noexcept
|
||||
@ -165,6 +179,7 @@ value_type(
|
||||
Args&&... args)
|
||||
: value_(std::forward<Args>(args)...)
|
||||
, len_(key.size())
|
||||
#if 0
|
||||
, key_(
|
||||
[&]
|
||||
{
|
||||
@ -178,7 +193,16 @@ value_type(
|
||||
s[key.size()] = 0;
|
||||
return s;
|
||||
}())
|
||||
#endif
|
||||
{
|
||||
if(key.size() > detail::max_string_length_)
|
||||
BOOST_JSON_THROW(
|
||||
detail::string_too_large_exception());
|
||||
key_ = reinterpret_cast<
|
||||
char*>(value_.get_storage()->
|
||||
allocate(key.size() + 1));
|
||||
std::memcpy(key_, key.data(), key.size());
|
||||
key_[key.size()] = 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
@ -446,34 +446,6 @@ maybe_object(
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
storage_ptr const&
|
||||
value::
|
||||
get_storage() const noexcept
|
||||
{
|
||||
switch(kind_)
|
||||
{
|
||||
case json::kind::object:
|
||||
return obj_.get_storage();
|
||||
|
||||
case json::kind::array:
|
||||
return arr_.get_storage();
|
||||
|
||||
case json::kind::string:
|
||||
return str_.get_storage();
|
||||
|
||||
case json::kind::int64:
|
||||
case json::kind::uint64:
|
||||
case json::kind::double_:
|
||||
case json::kind::boolean:
|
||||
case json::kind::null:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return sca_.sp;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
storage_ptr
|
||||
value::
|
||||
destroy() noexcept
|
||||
|
@ -225,7 +225,7 @@ private:
|
||||
bucket_end() const noexcept;
|
||||
};
|
||||
|
||||
class undo_construct;
|
||||
struct undo_construct;
|
||||
class undo_insert;
|
||||
|
||||
template<class T>
|
||||
@ -242,7 +242,7 @@ private:
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
storage_ptr sp_;
|
||||
storage_ptr sp_; // must come first
|
||||
impl_type impl_;
|
||||
|
||||
public:
|
||||
@ -553,6 +553,7 @@ public:
|
||||
|
||||
/**
|
||||
*/
|
||||
explicit
|
||||
BOOST_JSON_DECL
|
||||
object(unchecked_object&& uo);
|
||||
|
||||
@ -1345,12 +1346,8 @@ public:
|
||||
contains(key_type key) const noexcept;
|
||||
|
||||
private:
|
||||
struct place
|
||||
{
|
||||
virtual
|
||||
void
|
||||
operator()(void* dest) = 0;
|
||||
};
|
||||
struct place_one;
|
||||
struct place_range;
|
||||
|
||||
template<class It>
|
||||
using iter_cat = typename
|
||||
@ -1376,15 +1373,39 @@ private:
|
||||
digest(key_type key) noexcept;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
std::pair<
|
||||
value_type*,
|
||||
std::size_t>
|
||||
std::pair<value_type*, std::size_t>
|
||||
find_impl(key_type key) const noexcept;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
void
|
||||
rehash(std::size_t new_capacity);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
std::pair<iterator, bool>
|
||||
emplace_impl(
|
||||
key_type key, place_one& f);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
std::pair<iterator, bool>
|
||||
insert_impl(place_one& f);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
iterator
|
||||
insert_impl(
|
||||
std::size_t hash,
|
||||
place_one& f);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
std::pair<iterator, bool>
|
||||
insert_or_assign_impl(
|
||||
key_type key, place_one& f);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
void
|
||||
insert_range_impl(
|
||||
std::size_t min_capacity,
|
||||
place_range& f);
|
||||
|
||||
template<class InputIt>
|
||||
void
|
||||
insert_range(
|
||||
@ -1399,7 +1420,7 @@ private:
|
||||
InputIt first,
|
||||
InputIt last,
|
||||
std::size_t min_capacity,
|
||||
std::random_access_iterator_tag);
|
||||
std::forward_iterator_tag);
|
||||
|
||||
template<class InputIt>
|
||||
void
|
||||
|
@ -31,8 +31,9 @@ class parser final
|
||||
{
|
||||
struct level
|
||||
{
|
||||
size_type size;
|
||||
std::int32_t size;
|
||||
bool obj;
|
||||
char pad[3];
|
||||
};
|
||||
|
||||
class stack
|
||||
@ -97,8 +98,9 @@ class parser final
|
||||
object::value_type&
|
||||
emplace_pair(Arg&& arg)
|
||||
{
|
||||
size_type len;
|
||||
std::size_t len;
|
||||
pop_impl(len);
|
||||
size_ -= alignup(len) - len;
|
||||
auto key = pop_string(len);
|
||||
auto const n = sizeof(object::value_type);
|
||||
// size for n was placeheld
|
||||
@ -114,7 +116,10 @@ class parser final
|
||||
placeholder(
|
||||
std::size_t bytes)
|
||||
{
|
||||
bytes = alignup(bytes);
|
||||
BOOST_JSON_ASSERT(
|
||||
alignup(bytes) == bytes);
|
||||
BOOST_JSON_ASSERT(
|
||||
alignup(size_) == size_);
|
||||
prepare(bytes);
|
||||
size_ += bytes;
|
||||
}
|
||||
@ -123,14 +128,26 @@ class parser final
|
||||
unreserve(
|
||||
std::size_t bytes)
|
||||
{
|
||||
bytes = alignup(bytes);
|
||||
BOOST_JSON_ASSERT(
|
||||
alignup(bytes) == bytes);
|
||||
BOOST_JSON_ASSERT(
|
||||
alignup(size_) == size_);
|
||||
BOOST_JSON_ASSERT(
|
||||
bytes <= size_);
|
||||
size_ -= bytes;
|
||||
}
|
||||
|
||||
void
|
||||
push(size_type u)
|
||||
align()
|
||||
{
|
||||
auto const n = alignup(size_);
|
||||
if(n > capacity_)
|
||||
grow(n - size_);
|
||||
size_ = n;
|
||||
}
|
||||
|
||||
void
|
||||
push(std::size_t u)
|
||||
{
|
||||
push_impl(u);
|
||||
}
|
||||
@ -147,7 +164,7 @@ class parser final
|
||||
prepare(s.size());
|
||||
std::memcpy(base_ + size_,
|
||||
s.data(), s.size());
|
||||
size_ += alignup(s.size());
|
||||
size_ += s.size();
|
||||
}
|
||||
|
||||
void
|
||||
@ -159,11 +176,16 @@ class parser final
|
||||
unchecked_array
|
||||
pop_array(size_type size) noexcept
|
||||
{
|
||||
BOOST_JSON_ASSERT(
|
||||
alignup(size_) == size_);
|
||||
if(size == 0)
|
||||
return { nullptr, 0, sp_ };
|
||||
auto const n = sizeof(value) * size;
|
||||
auto const n =
|
||||
sizeof(value) * size;
|
||||
BOOST_JSON_ASSERT(
|
||||
alignup(n) == n);
|
||||
BOOST_JSON_ASSERT(n <= size_);
|
||||
size_ -= alignup(n);
|
||||
size_ -= n;
|
||||
return { reinterpret_cast<
|
||||
value*>(base_ + size_),
|
||||
size, sp_ };
|
||||
@ -172,19 +194,23 @@ class parser final
|
||||
unchecked_object
|
||||
pop_object(size_type size) noexcept
|
||||
{
|
||||
BOOST_JSON_ASSERT(
|
||||
alignup(size_) == size_);
|
||||
if(size == 0)
|
||||
return { nullptr, 0, sp_ };
|
||||
auto const n = sizeof(
|
||||
object::value_type) * size;
|
||||
BOOST_JSON_ASSERT(
|
||||
alignup(n) == n);
|
||||
BOOST_JSON_ASSERT(n <= size_);
|
||||
size_ -= alignup(n);
|
||||
size_ -= n;
|
||||
return { reinterpret_cast<
|
||||
object::value_type*>(base_ + size_),
|
||||
size, sp_ };
|
||||
}
|
||||
|
||||
string_view
|
||||
pop_string(size_type len) noexcept
|
||||
pop_string(std::size_t len) noexcept
|
||||
{
|
||||
BOOST_JSON_ASSERT(len <= size_);
|
||||
size_ -= len;
|
||||
@ -205,7 +231,6 @@ class parser final
|
||||
void
|
||||
prepare(std::size_t n)
|
||||
{
|
||||
n = alignup(n);
|
||||
if(n > capacity_ - size_)
|
||||
grow(n);
|
||||
}
|
||||
@ -238,7 +263,11 @@ class parser final
|
||||
void
|
||||
push_impl(T t)
|
||||
{
|
||||
auto const n = alignup(sizeof(T));
|
||||
BOOST_JSON_ASSERT((sizeof(T) %
|
||||
sizeof(max_align_t)) == 0);
|
||||
BOOST_JSON_ASSERT((size_ %
|
||||
sizeof(max_align_t)) == 0);
|
||||
auto const n = sizeof(T);
|
||||
if(n > capacity_ - size_)
|
||||
grow(n);
|
||||
::new(base_ + size_) T(t);
|
||||
@ -249,9 +278,13 @@ class parser final
|
||||
void
|
||||
pop_impl(T& t) noexcept
|
||||
{
|
||||
BOOST_JSON_ASSERT(
|
||||
size_ >= sizeof(T));
|
||||
size_ -= alignup(sizeof(T));
|
||||
BOOST_JSON_ASSERT((sizeof(T) %
|
||||
sizeof(max_align_t)) == 0);
|
||||
BOOST_JSON_ASSERT((size_ %
|
||||
sizeof(max_align_t)) == 0);
|
||||
auto const n = sizeof(T);
|
||||
BOOST_JSON_ASSERT(size_ >= n);
|
||||
size_ -= n;
|
||||
std::memcpy(
|
||||
&t, base_ + size_, sizeof(T));
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ private:
|
||||
union
|
||||
{
|
||||
char* p;
|
||||
char buf[20]; // SBO
|
||||
char buf[4]; // SBO
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -227,7 +227,7 @@ private:
|
||||
|
||||
};
|
||||
|
||||
storage_ptr sp_;
|
||||
storage_ptr sp_; // must come first
|
||||
impl impl_;
|
||||
|
||||
public:
|
||||
|
@ -33,6 +33,8 @@ namespace boost {
|
||||
namespace json {
|
||||
|
||||
class value;
|
||||
class unchecked_object;
|
||||
class unchecked_array;
|
||||
|
||||
/** Customization point for assigning to and from class types.
|
||||
*/
|
||||
@ -109,7 +111,7 @@ class value
|
||||
#ifndef GENERATING_DOCUMENTATION
|
||||
struct scalar
|
||||
{
|
||||
storage_ptr sp;
|
||||
storage_ptr sp; // must come first
|
||||
union
|
||||
{
|
||||
std::uint64_t u;
|
||||
@ -132,6 +134,7 @@ class value
|
||||
// XSL scripts have trouble with private anon unions
|
||||
union
|
||||
{
|
||||
storage_ptr sp_; // must come first
|
||||
object obj_;
|
||||
array arr_;
|
||||
string str_;
|
||||
@ -377,6 +380,11 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/** Construct an array.
|
||||
*/
|
||||
inline
|
||||
value(unchecked_object&& uo);
|
||||
|
||||
/** Construct an array.
|
||||
*/
|
||||
value(array arr) noexcept
|
||||
@ -402,6 +410,11 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/** Construct an array.
|
||||
*/
|
||||
inline
|
||||
value(unchecked_array&& ua);
|
||||
|
||||
/** Construct a string.
|
||||
*/
|
||||
value(
|
||||
@ -1055,9 +1068,11 @@ public:
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
storage_ptr const&
|
||||
get_storage() const noexcept;
|
||||
get_storage() const noexcept
|
||||
{
|
||||
return sp_;
|
||||
}
|
||||
|
||||
/** Return a pointer to an object, or nullptr.
|
||||
|
||||
|
@ -588,14 +588,14 @@ public:
|
||||
|
||||
// insert_or_assign(key, o);
|
||||
{
|
||||
fail_loop([&](storage_ptr const& sp)
|
||||
fail_loop([&](storage_ptr const& sp)
|
||||
{
|
||||
object o({{"a", 1}}, sp);
|
||||
o.insert_or_assign("a", str_);
|
||||
BEAST_EXPECT(o["a"].is_string());
|
||||
});
|
||||
|
||||
fail_loop([&](storage_ptr const& sp)
|
||||
fail_loop([&](storage_ptr const& sp)
|
||||
{
|
||||
object o({
|
||||
{"a", 1},
|
||||
@ -606,7 +606,7 @@ public:
|
||||
BEAST_EXPECT(o.size() == 4);
|
||||
});
|
||||
|
||||
fail_loop([&](storage_ptr const& sp)
|
||||
fail_loop([&](storage_ptr const& sp)
|
||||
{
|
||||
object o({{"a", 1}}, sp);
|
||||
o.insert_or_assign("b", true);
|
||||
@ -614,7 +614,7 @@ public:
|
||||
check(o, 3);
|
||||
});
|
||||
|
||||
fail_loop([&](storage_ptr const& sp)
|
||||
fail_loop([&](storage_ptr const& sp)
|
||||
{
|
||||
object o({{"a", 1}}, sp);
|
||||
BEAST_EXPECT(
|
||||
|
@ -92,6 +92,12 @@ struct fail_storage
|
||||
|
||||
std::size_t fail_max = 1;
|
||||
std::size_t fail = 0;
|
||||
std::size_t nalloc = 0;
|
||||
|
||||
~fail_storage()
|
||||
{
|
||||
BEAST_EXPECT(nalloc == 0);
|
||||
}
|
||||
|
||||
void*
|
||||
allocate(
|
||||
@ -104,7 +110,9 @@ struct fail_storage
|
||||
fail = 0;
|
||||
throw test_failure{};
|
||||
}
|
||||
return ::operator new(n);
|
||||
auto p = ::operator new(n);
|
||||
++nalloc;
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
@ -113,6 +121,8 @@ struct fail_storage
|
||||
std::size_t,
|
||||
std::size_t) noexcept
|
||||
{
|
||||
if(BEAST_EXPECT(nalloc > 0))
|
||||
--nalloc;
|
||||
::operator delete(p);
|
||||
}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user