This commit is contained in:
Vinnie Falco 2019-11-08 15:22:52 -08:00
parent adcebea5a9
commit a0e46853a8
15 changed files with 494 additions and 273 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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