mirror of
https://github.com/boostorg/json.git
synced 2026-01-19 04:12:14 +00:00
array work
This commit is contained in:
@@ -30,9 +30,11 @@
|
||||
[template include_file[path][^<'''<ulink url="../../../../'''[path]'''">'''[path]'''</ulink>'''>]]
|
||||
[template issue[n] '''<ulink url="https://github.com/boostorg/beast/issues/'''[n]'''">#'''[n]'''</ulink>''']
|
||||
|
||||
[/ C++ Named Requirements ]
|
||||
[/ Named Requirements ]
|
||||
|
||||
[def __Allocator__ [@https://en.cppreference.com/w/cpp/named_req/Allocator ['Allocator]]]
|
||||
[def __InputIterator__ [@https://en.cppreference.com/w/cpp/named_req/InputIterator ['InputIterator]]]
|
||||
|
||||
[def __ConstBufferSequence__ [@boost:/doc/html/boost_asio/reference/ConstBufferSequence.html ['ConstBufferSequence]]]
|
||||
[def __MutableBufferSequence__ [@boost:/doc/html/boost_asio/reference/MutableBufferSequence.html ['MutableBufferSequence]]]
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<!-- CLASS_DETAIL_TEMPLATE BEGIN -->
|
||||
<xsl:when test="$normal-tparam = 'Allocator'"> <xsl:text>__Allocator__</xsl:text></xsl:when>
|
||||
<xsl:when test="$normal-tparam = 'ConstBufferSequence'"> <xsl:text>__ConstBufferSequence__</xsl:text></xsl:when>
|
||||
<xsl:when test="$normal-tparam = 'MutableBufferSequence'"> <xsl:text>__MutableBufferSequence__</xsl:text></xsl:when>
|
||||
<xsl:when test="$normal-tparam = 'Allocator'"><xsl:text>__Allocator__</xsl:text></xsl:when>
|
||||
<xsl:when test="$normal-tparam = 'InputIterator'"><xsl:text>__InputIterator__</xsl:text></xsl:when>
|
||||
<xsl:when test="$normal-tparam = 'ConstBufferSequence'"><xsl:text>__ConstBufferSequence__</xsl:text></xsl:when>
|
||||
<xsl:when test="$normal-tparam = 'MutableBufferSequence'"><xsl:text>__MutableBufferSequence__</xsl:text></xsl:when>
|
||||
<!-- CLASS_DETAIL_TEMPLATE END -->
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -51,14 +51,11 @@ struct storage_adaptor
|
||||
{
|
||||
// VFALCO This is all public because msvc friend bugs
|
||||
|
||||
std::atomic<unsigned> count_;
|
||||
|
||||
explicit
|
||||
storage_adaptor(Allocator const& alloc)
|
||||
: boost::empty_value<
|
||||
allocator_of_char<Allocator>>(
|
||||
boost::empty_init_t{}, alloc)
|
||||
, count_(1)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <boost/json/value.hpp>
|
||||
#include <boost/core/exchange.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
|
||||
@@ -20,46 +21,38 @@ namespace json {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class array::table
|
||||
struct array::table
|
||||
{
|
||||
union
|
||||
struct data
|
||||
{
|
||||
std::size_t capacity_;
|
||||
value unused_; // for alignment
|
||||
size_type size;
|
||||
size_type capacity;
|
||||
};
|
||||
|
||||
static_assert(
|
||||
sizeof(value) >= sizeof(std::size_t), "");
|
||||
union
|
||||
{
|
||||
data d;
|
||||
value unused; // for alignment
|
||||
};
|
||||
|
||||
BOOST_JSON_DECL
|
||||
~table();
|
||||
~table() = delete;
|
||||
|
||||
public:
|
||||
size_type size = 0;
|
||||
|
||||
explicit
|
||||
table(size_type capacity)
|
||||
: capacity_(capacity)
|
||||
table()
|
||||
{
|
||||
}
|
||||
|
||||
size_type
|
||||
capacity() const noexcept
|
||||
{
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
value_type*
|
||||
value*
|
||||
begin() noexcept
|
||||
{
|
||||
return reinterpret_cast<
|
||||
value_type*>(this + 1);
|
||||
value*>(this + 1);
|
||||
}
|
||||
|
||||
value_type*
|
||||
value*
|
||||
end() noexcept
|
||||
{
|
||||
return begin() + size;
|
||||
return reinterpret_cast<
|
||||
value*>(this + 1) + d.size;
|
||||
}
|
||||
|
||||
BOOST_JSON_DECL
|
||||
@@ -74,7 +67,22 @@ public:
|
||||
void
|
||||
destroy(
|
||||
table* tab,
|
||||
storage_ptr const& sp);
|
||||
storage_ptr const& sp) noexcept;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
static
|
||||
void
|
||||
destroy(
|
||||
value* first,
|
||||
value* last) noexcept;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
static
|
||||
void
|
||||
relocate(
|
||||
value* dest,
|
||||
value* first,
|
||||
value* last) noexcept;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -124,6 +132,10 @@ array(
|
||||
first, last,
|
||||
default_storage())
|
||||
{
|
||||
static_assert(
|
||||
std::is_constructible<value,
|
||||
decltype(*first)>::value,
|
||||
"json::value is not constructible from the iterator's value type");
|
||||
}
|
||||
|
||||
template<class InputIt, class>
|
||||
@@ -136,17 +148,25 @@ array(
|
||||
std::move(store),
|
||||
iter_cat<InputIt>{})
|
||||
{
|
||||
static_assert(
|
||||
std::is_constructible<value,
|
||||
decltype(*first)>::value,
|
||||
"json::value is not constructible from the iterator's value type");
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
auto
|
||||
array::
|
||||
insert(
|
||||
const_iterator before,
|
||||
const_iterator pos,
|
||||
InputIt first, InputIt last) ->
|
||||
iterator
|
||||
{
|
||||
return insert(before, first, last,
|
||||
static_assert(
|
||||
std::is_constructible<value,
|
||||
decltype(*first)>::value,
|
||||
"json::value is not constructible from the iterator's value type");
|
||||
return insert(pos, first, last,
|
||||
iter_cat<InputIt>{});
|
||||
}
|
||||
|
||||
@@ -154,12 +174,12 @@ template<class Arg>
|
||||
auto
|
||||
array::
|
||||
emplace(
|
||||
const_iterator before,
|
||||
const_iterator pos,
|
||||
Arg&& arg) ->
|
||||
iterator
|
||||
{
|
||||
return emplace_impl(
|
||||
before, std::forward<Arg>(arg));
|
||||
pos, std::forward<Arg>(arg));
|
||||
}
|
||||
|
||||
template<class Arg>
|
||||
@@ -202,33 +222,33 @@ template<class InputIt>
|
||||
auto
|
||||
array::
|
||||
insert(
|
||||
const_iterator before,
|
||||
const_iterator pos,
|
||||
InputIt first, InputIt last,
|
||||
std::input_iterator_tag) ->
|
||||
iterator
|
||||
{
|
||||
auto pos = before - begin();
|
||||
auto d = pos - begin();
|
||||
while(first != last)
|
||||
before = insert(before, *first++) + 1;
|
||||
return begin() + pos;
|
||||
pos = insert(pos, *first++) + 1;
|
||||
return begin() + d;
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
auto
|
||||
array::
|
||||
insert(
|
||||
const_iterator before,
|
||||
const_iterator pos,
|
||||
InputIt first, InputIt last,
|
||||
std::forward_iterator_tag) ->
|
||||
iterator
|
||||
{
|
||||
auto count = std::distance(first, last);
|
||||
auto pos = before - begin();
|
||||
auto d = pos - begin();
|
||||
reserve(size() + count);
|
||||
cleanup_insert c(pos, count, *this);
|
||||
cleanup_insert c(d, count, *this);
|
||||
while(count--)
|
||||
{
|
||||
::new(&begin()[pos++]) value_type(
|
||||
::new(&begin()[d++]) value(
|
||||
*first++, sp_);
|
||||
++c.valid;
|
||||
}
|
||||
@@ -240,17 +260,17 @@ template<class Arg>
|
||||
auto
|
||||
array::
|
||||
emplace_impl(
|
||||
const_iterator before,
|
||||
const_iterator pos,
|
||||
Arg&& arg) ->
|
||||
iterator
|
||||
{
|
||||
auto const pos = before - begin();
|
||||
auto const d = pos - begin();
|
||||
reserve(size() + 1);
|
||||
cleanup_insert c(pos, 1, *this);
|
||||
::new(&tab_->begin()[pos]) value_type(
|
||||
cleanup_insert c(d, 1, *this);
|
||||
::new(&tab_->begin()[d]) value(
|
||||
std::forward<Arg>(arg), sp_);
|
||||
c.ok = true;
|
||||
return begin() + pos;
|
||||
return begin() + d;
|
||||
}
|
||||
|
||||
} // json
|
||||
|
||||
@@ -27,14 +27,6 @@ namespace json {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
array::
|
||||
table::
|
||||
~table()
|
||||
{
|
||||
while(size > 0)
|
||||
begin()[--size].~value();
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
table::
|
||||
@@ -43,10 +35,19 @@ create(
|
||||
storage_ptr const& sp) ->
|
||||
table*
|
||||
{
|
||||
return ::new(sp->allocate(
|
||||
// a reasonable minimum
|
||||
if( capacity < 3)
|
||||
capacity = 3;
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
sizeof(table) == sizeof(value));
|
||||
auto const p = ::new(sp->allocate(
|
||||
sizeof(table) +
|
||||
capacity * sizeof(value),
|
||||
sizeof(value))) table(capacity);
|
||||
alignof(value))) table;
|
||||
p->d.size = 0;
|
||||
p->d.capacity = capacity;
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -54,16 +55,52 @@ array::
|
||||
table::
|
||||
destroy(
|
||||
table* tab,
|
||||
storage_ptr const& sp)
|
||||
storage_ptr const& sp) noexcept
|
||||
{
|
||||
auto const capacity = tab->capacity();
|
||||
tab->~table();
|
||||
destroy(tab->begin(), tab->end());
|
||||
sp->deallocate(tab,
|
||||
sizeof(table) +
|
||||
capacity * sizeof(value),
|
||||
sizeof(value));
|
||||
tab->d.capacity * sizeof(value),
|
||||
alignof(value));
|
||||
}
|
||||
|
||||
void
|
||||
array::
|
||||
table::
|
||||
destroy(
|
||||
value* first,
|
||||
value* last) noexcept
|
||||
{
|
||||
while(last != first)
|
||||
(*--last).~value();
|
||||
}
|
||||
|
||||
void
|
||||
array::
|
||||
table::
|
||||
relocate(
|
||||
value* dest,
|
||||
value* first,
|
||||
value* last) noexcept
|
||||
{
|
||||
while(first != last)
|
||||
boost::relocate(dest++, *first++);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
struct array::undo
|
||||
{
|
||||
table* tab;
|
||||
storage_ptr const& sp;
|
||||
|
||||
~undo()
|
||||
{
|
||||
if(tab)
|
||||
table::destroy(tab, sp);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
array::
|
||||
@@ -118,7 +155,7 @@ cleanup_insert::
|
||||
{
|
||||
if(ok)
|
||||
{
|
||||
self.tab_->size += n;
|
||||
self.tab_->d.size += n;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -147,35 +184,14 @@ array::
|
||||
}
|
||||
|
||||
array::
|
||||
array()
|
||||
array() noexcept
|
||||
: sp_(default_storage())
|
||||
{
|
||||
}
|
||||
|
||||
array::
|
||||
array(storage_ptr store)
|
||||
: sp_(std::move(store))
|
||||
{
|
||||
}
|
||||
|
||||
array::
|
||||
array(
|
||||
size_type count)
|
||||
: array(
|
||||
count,
|
||||
value(kind::null),
|
||||
default_storage())
|
||||
{
|
||||
}
|
||||
|
||||
array::
|
||||
array(
|
||||
size_type count,
|
||||
storage_ptr store)
|
||||
: array(
|
||||
count,
|
||||
value(kind::null),
|
||||
std::move(store))
|
||||
array(storage_ptr sp) noexcept
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -194,34 +210,56 @@ array::
|
||||
array(
|
||||
size_type count,
|
||||
value const& v,
|
||||
storage_ptr store)
|
||||
: sp_(std::move(store))
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
if(count > 0)
|
||||
{
|
||||
undo u{table::create(
|
||||
count, sp_), sp_};
|
||||
while(count--)
|
||||
{
|
||||
::new(u.tab->end()) value(v, sp_);
|
||||
++u.tab->d.size;
|
||||
}
|
||||
std::swap(tab_, u.tab);
|
||||
}
|
||||
}
|
||||
|
||||
array::
|
||||
array(
|
||||
size_type count)
|
||||
: array(
|
||||
count,
|
||||
value(kind::null),
|
||||
default_storage())
|
||||
{
|
||||
}
|
||||
|
||||
array::
|
||||
array(
|
||||
size_type count,
|
||||
storage_ptr sp)
|
||||
: array(
|
||||
count,
|
||||
value(kind::null),
|
||||
std::move(sp))
|
||||
{
|
||||
resize(count, v);
|
||||
}
|
||||
|
||||
array::
|
||||
array(array const& other)
|
||||
: sp_(other.get_storage())
|
||||
: array(other, other.sp_)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
array::
|
||||
array(
|
||||
array const& other,
|
||||
storage_ptr store)
|
||||
: sp_(std::move(store))
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
array::
|
||||
array(array&& other) noexcept
|
||||
: tab_(boost::exchange(
|
||||
other.tab_, nullptr))
|
||||
, sp_(other.sp_)
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
copy(other);
|
||||
}
|
||||
|
||||
array::
|
||||
@@ -233,73 +271,78 @@ array(pilfered<array> other) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
array::
|
||||
array(array&& other) noexcept
|
||||
: tab_(boost::exchange(
|
||||
other.tab_, nullptr))
|
||||
, sp_(other.sp_)
|
||||
{
|
||||
}
|
||||
|
||||
array::
|
||||
array(
|
||||
array&& other,
|
||||
storage_ptr store)
|
||||
: sp_(std::move(store))
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
*this = std::move(other);
|
||||
if(*sp_ != *other.sp_)
|
||||
copy(other);
|
||||
else
|
||||
std::swap(tab_, other.tab_);
|
||||
}
|
||||
|
||||
array::
|
||||
array(
|
||||
std::initializer_list<value> list)
|
||||
: sp_(default_storage())
|
||||
std::initializer_list<value> init)
|
||||
: array(
|
||||
init,
|
||||
default_storage())
|
||||
{
|
||||
*this = list;
|
||||
}
|
||||
|
||||
array::
|
||||
array(
|
||||
std::initializer_list<value> list,
|
||||
storage_ptr store)
|
||||
: sp_(std::move(store))
|
||||
std::initializer_list<value> init,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
*this = list;
|
||||
assign(init);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
array&
|
||||
array::
|
||||
operator=(array const& other)
|
||||
{
|
||||
copy(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
array&
|
||||
array::
|
||||
operator=(array&& other)
|
||||
{
|
||||
if(*sp_ == *other.sp_)
|
||||
if(*sp_ != *other.sp_)
|
||||
{
|
||||
copy(other);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(tab_)
|
||||
table::destroy(tab_, sp_);
|
||||
tab_ = boost::exchange(
|
||||
other.tab_, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
array&
|
||||
array::
|
||||
operator=(array const& other)
|
||||
{
|
||||
cleanup_assign c(*this);
|
||||
reserve(other.size());
|
||||
for(auto const& v : other)
|
||||
emplace_impl(end(), v);
|
||||
c.ok = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
array&
|
||||
array::
|
||||
operator=(
|
||||
std::initializer_list<value> list)
|
||||
std::initializer_list<value> init)
|
||||
{
|
||||
cleanup_assign c(*this);
|
||||
reserve(list.size());
|
||||
for(auto it = list.begin();
|
||||
it != list.end(); ++it)
|
||||
emplace_impl(end(), std::move(*it));
|
||||
c.ok = true;
|
||||
assign(init);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -312,7 +355,7 @@ get_storage() const noexcept
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Elements
|
||||
// Element access
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -322,8 +365,8 @@ at(size_type pos) ->
|
||||
reference
|
||||
{
|
||||
if(pos >= size())
|
||||
throw std::out_of_range(
|
||||
"json::array index out of bounds");
|
||||
BOOST_THROW_EXCEPTION(std::out_of_range(
|
||||
"json::array index out of bounds"));
|
||||
return tab_->begin()[pos];
|
||||
}
|
||||
|
||||
@@ -333,8 +376,8 @@ at(size_type pos) const ->
|
||||
const_reference
|
||||
{
|
||||
if(pos >= size())
|
||||
throw std::out_of_range(
|
||||
"json::array index out of bounds");
|
||||
BOOST_THROW_EXCEPTION(std::out_of_range(
|
||||
"json::array index out of bounds"));
|
||||
return tab_->begin()[pos];
|
||||
}
|
||||
|
||||
@@ -470,7 +513,7 @@ bool
|
||||
array::
|
||||
empty() const noexcept
|
||||
{
|
||||
return ! tab_ || tab_->size == 0;
|
||||
return ! tab_ || tab_->d.size == 0;
|
||||
}
|
||||
|
||||
auto
|
||||
@@ -480,7 +523,7 @@ size() const noexcept ->
|
||||
{
|
||||
if(! tab_)
|
||||
return 0;
|
||||
return tab_->size;
|
||||
return tab_->d.size;
|
||||
}
|
||||
|
||||
auto
|
||||
@@ -500,39 +543,33 @@ reserve(size_type new_capacity)
|
||||
if(new_capacity == 0)
|
||||
return;
|
||||
|
||||
// a reasonable minimum
|
||||
if( new_capacity < 3)
|
||||
new_capacity = 3;
|
||||
|
||||
if(tab_)
|
||||
{
|
||||
// can only grow
|
||||
if(new_capacity <= tab_->capacity())
|
||||
// never shrink
|
||||
if(new_capacity <= tab_->d.capacity)
|
||||
return;
|
||||
|
||||
// grow at least 50%
|
||||
new_capacity = (std::max<size_type>)(
|
||||
(tab_->capacity() * 3 + 1) / 2,
|
||||
(tab_->d.capacity * 3 + 1) / 2,
|
||||
new_capacity);
|
||||
}
|
||||
|
||||
auto tab = table::create(new_capacity, sp_);
|
||||
auto tab =
|
||||
table::create(new_capacity, sp_);
|
||||
if(! tab_)
|
||||
{
|
||||
tab_ = tab;
|
||||
return;
|
||||
}
|
||||
|
||||
for(size_type i = 0; i < tab_->size; ++i)
|
||||
relocate(
|
||||
&tab->begin()[i],
|
||||
tab_->begin()[i]);
|
||||
tab->size = tab_->size;
|
||||
table::relocate(
|
||||
tab->begin(),
|
||||
tab_->begin(), tab_->end());
|
||||
tab->d.size = tab_->d.size;
|
||||
tab_->d.size = 0;
|
||||
std::swap(tab, tab_);
|
||||
{
|
||||
tab->size = 0; // VFALCO hack to make it work
|
||||
table::destroy(tab, sp_);
|
||||
}
|
||||
table::destroy(tab, sp_);
|
||||
}
|
||||
|
||||
auto
|
||||
@@ -542,21 +579,44 @@ capacity() const noexcept ->
|
||||
{
|
||||
if(! tab_)
|
||||
return 0;
|
||||
return tab_->capacity();
|
||||
return tab_->d.capacity;
|
||||
}
|
||||
|
||||
void
|
||||
array::
|
||||
shrink_to_fit() noexcept
|
||||
{
|
||||
if(! tab_ ||
|
||||
tab_->capacity() <= tab_->size)
|
||||
if(capacity() <= size())
|
||||
return;
|
||||
auto tab = table::create(tab_->size, sp_);
|
||||
for(size_type i = 0; i < tab_->size; ++i)
|
||||
::new(&tab->begin()[i]) value(
|
||||
std::move(tab_->begin()[i]));
|
||||
tab->size = tab_->size;
|
||||
table* tab;
|
||||
if(tab_->d.size == 0)
|
||||
{
|
||||
table::destroy(tab_, sp_);
|
||||
tab_ = nullptr;
|
||||
return;
|
||||
}
|
||||
if( size() < 3 &&
|
||||
capacity() <= 3)
|
||||
return;
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
#endif
|
||||
{
|
||||
tab = table::create(tab_->d.size, sp_);
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(...)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
table::relocate(
|
||||
tab->begin(),
|
||||
tab_->begin(), tab_->end());
|
||||
tab->d.size = tab_->d.size;
|
||||
tab_->d.size = 0;
|
||||
std::swap(tab, tab_);
|
||||
table::destroy(tab, sp_);
|
||||
}
|
||||
@@ -573,45 +633,47 @@ clear() noexcept
|
||||
{
|
||||
if(! tab_)
|
||||
return;
|
||||
destroy(begin(), end());
|
||||
tab_->size = 0;
|
||||
table::destroy(
|
||||
tab_->begin(),
|
||||
tab_->end());
|
||||
tab_->d.size = 0;
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
insert(
|
||||
const_iterator before,
|
||||
const_iterator pos,
|
||||
value const& v) ->
|
||||
iterator
|
||||
{
|
||||
return emplace_impl(before, v);
|
||||
return emplace_impl(pos, v);
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
insert(
|
||||
const_iterator before,
|
||||
const_iterator pos,
|
||||
value&& v) ->
|
||||
iterator
|
||||
{
|
||||
return emplace_impl(
|
||||
before, std::move(v));
|
||||
pos, std::move(v));
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
insert(
|
||||
const_iterator before,
|
||||
const_iterator pos,
|
||||
size_type count,
|
||||
value const& v) ->
|
||||
iterator
|
||||
{
|
||||
auto pos = before - begin();
|
||||
auto p = pos - begin();
|
||||
reserve(size() + count);
|
||||
cleanup_insert c(pos, count, *this);
|
||||
cleanup_insert c(p, count, *this);
|
||||
while(count--)
|
||||
{
|
||||
::new(&begin()[pos++])
|
||||
::new(&begin()[p++])
|
||||
value(v, sp_);
|
||||
++c.valid;
|
||||
}
|
||||
@@ -622,18 +684,18 @@ insert(
|
||||
auto
|
||||
array::
|
||||
insert(
|
||||
const_iterator before,
|
||||
std::initializer_list<value> list) ->
|
||||
const_iterator pos,
|
||||
std::initializer_list<value> init) ->
|
||||
iterator
|
||||
{
|
||||
auto pos = before - begin();
|
||||
reserve(size() + list.size());
|
||||
auto p = pos - begin();
|
||||
reserve(size() + init.size());
|
||||
cleanup_insert c(
|
||||
pos, list.size(), *this);
|
||||
for(auto it = list.begin();
|
||||
it != list.end(); ++it)
|
||||
p, init.size(), *this);
|
||||
for(auto it = init.begin();
|
||||
it != init.end(); ++it)
|
||||
{
|
||||
::new(&begin()[pos++]) value(
|
||||
::new(&begin()[p++]) value(
|
||||
std::move(*it), sp_);
|
||||
++c.valid;
|
||||
}
|
||||
@@ -643,29 +705,29 @@ insert(
|
||||
|
||||
auto
|
||||
array::
|
||||
erase(const_iterator pos) ->
|
||||
erase(const_iterator pos) noexcept ->
|
||||
iterator
|
||||
{
|
||||
auto it = data() + (pos - begin());
|
||||
destroy(it, it + 1);
|
||||
move(it, it + 1, 1);
|
||||
--tab_->size;
|
||||
return it;
|
||||
auto p = data() + (pos - begin());
|
||||
table::destroy(p, p + 1);
|
||||
move(p, p + 1, 1);
|
||||
--tab_->d.size;
|
||||
return p;
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
erase(
|
||||
const_iterator first,
|
||||
const_iterator last) ->
|
||||
const_iterator last) noexcept ->
|
||||
iterator
|
||||
{
|
||||
auto const n = last - first;
|
||||
auto it = data() + (first - begin());
|
||||
destroy(it, it + n);
|
||||
move(it, it + n, n);
|
||||
tab_->size -= n;
|
||||
return it;
|
||||
auto p = data() + (first - begin());
|
||||
table::destroy(p, p + n);
|
||||
move(p, p + n, n);
|
||||
tab_->d.size -= n;
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -684,19 +746,33 @@ push_back(value&& v)
|
||||
|
||||
void
|
||||
array::
|
||||
pop_back()
|
||||
pop_back() noexcept
|
||||
{
|
||||
back().~value();
|
||||
--tab_->size;
|
||||
--tab_->d.size;
|
||||
}
|
||||
|
||||
void
|
||||
array::
|
||||
resize(size_type count)
|
||||
{
|
||||
resize(
|
||||
count,
|
||||
value(kind::null));
|
||||
if(count <= size())
|
||||
{
|
||||
table::destroy(
|
||||
tab_->begin() + count,
|
||||
tab_->end());
|
||||
tab_->d.size = count;
|
||||
return;
|
||||
}
|
||||
|
||||
reserve(count);
|
||||
auto first = tab_->end();
|
||||
auto const last =
|
||||
tab_->begin() + count;
|
||||
while(first != last)
|
||||
::new(first++) value(
|
||||
json::kind::null, sp_);
|
||||
tab_->d.size = count;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -705,20 +781,40 @@ resize(
|
||||
size_type count,
|
||||
value const& v)
|
||||
{
|
||||
if(count > size())
|
||||
if(count <= size())
|
||||
{
|
||||
reserve(count);
|
||||
while(count--)
|
||||
emplace_impl(end(), v);
|
||||
table::destroy(
|
||||
tab_->begin() + count,
|
||||
tab_->end());
|
||||
tab_->d.size = count;
|
||||
return;
|
||||
}
|
||||
else if(count < size())
|
||||
|
||||
reserve(count);
|
||||
|
||||
struct revert
|
||||
{
|
||||
tab_->size = count;
|
||||
count = size() - count;
|
||||
for(size_type i = size() - 1;
|
||||
count-- > 0; --i)
|
||||
tab_->begin()[i].~value();
|
||||
value* it;
|
||||
table* tab;
|
||||
|
||||
~revert()
|
||||
{
|
||||
if(it != tab->end())
|
||||
table::destroy(
|
||||
tab->end(), it);
|
||||
}
|
||||
};
|
||||
|
||||
revert r{tab_->end(), tab_};
|
||||
auto const last =
|
||||
tab_->begin() + count;
|
||||
do
|
||||
{
|
||||
::new(r.it) value(v, sp_);
|
||||
++r.it;
|
||||
}
|
||||
while(r.it != last);
|
||||
tab_->d.size = count;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -745,12 +841,26 @@ release_storage() noexcept
|
||||
|
||||
void
|
||||
array::
|
||||
destroy(
|
||||
value* first,
|
||||
value* last)
|
||||
copy(array const& other)
|
||||
{
|
||||
while(first != last)
|
||||
(*first++).~value();
|
||||
if(other.empty())
|
||||
{
|
||||
if(tab_)
|
||||
{
|
||||
table::destroy(tab_, sp_);
|
||||
tab_ = nullptr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
undo u{table::create(
|
||||
other.size(), sp_), sp_};
|
||||
for(auto const& v : other)
|
||||
{
|
||||
::new(u.tab->end()) value(v, sp_);
|
||||
++u.tab->d.size;
|
||||
}
|
||||
std::swap(tab_, u.tab);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -766,23 +876,41 @@ move(
|
||||
to += n;
|
||||
from += n;
|
||||
while(n--)
|
||||
{
|
||||
::new(&*--to) value(
|
||||
std::move(*--from));
|
||||
from->~value();
|
||||
}
|
||||
boost::relocate(
|
||||
--to, *--from);
|
||||
}
|
||||
else
|
||||
{
|
||||
while(n--)
|
||||
{
|
||||
::new(&*to++) value(
|
||||
std::move(*from));
|
||||
(*from++).~value();
|
||||
}
|
||||
boost::relocate(
|
||||
to++, *from++);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
array::
|
||||
assign(std::initializer_list<value> init)
|
||||
{
|
||||
if(init.size() == 0)
|
||||
{
|
||||
if(tab_)
|
||||
{
|
||||
table::destroy(tab_, sp_);
|
||||
tab_ = nullptr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
undo u{table::create(
|
||||
init.size(), sp_), sp_};
|
||||
for(auto const& v : init)
|
||||
{
|
||||
::new(u.tab->end()) value(v, sp_);
|
||||
++u.tab->d.size;
|
||||
}
|
||||
std::swap(tab_, u.tab);
|
||||
}
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
|
||||
@@ -189,7 +189,6 @@ public:
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
constexpr
|
||||
std::pair<
|
||||
std::uint64_t,
|
||||
std::uint64_t>
|
||||
@@ -203,7 +202,6 @@ init(std::true_type) noexcept
|
||||
};
|
||||
}
|
||||
|
||||
constexpr
|
||||
std::pair<
|
||||
std::uint32_t,
|
||||
std::uint32_t>
|
||||
|
||||
@@ -362,6 +362,33 @@ public:
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
struct value::undo
|
||||
{
|
||||
union
|
||||
{
|
||||
value old;
|
||||
};
|
||||
value* cur;
|
||||
bool commit = false;
|
||||
|
||||
explicit
|
||||
undo(value* cur_)
|
||||
: cur(cur_)
|
||||
{
|
||||
relocate(&old, *cur);
|
||||
}
|
||||
|
||||
~undo()
|
||||
{
|
||||
if(commit)
|
||||
old.~value();
|
||||
else
|
||||
relocate(cur, old);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class M>
|
||||
auto
|
||||
value::
|
||||
|
||||
@@ -36,52 +36,90 @@ value(value&& other) noexcept
|
||||
switch(other.kind_)
|
||||
{
|
||||
case json::kind::object:
|
||||
::new(&obj_) object(
|
||||
std::move(other.obj_));
|
||||
other.obj_.~object();
|
||||
::new(&other.nat_.sp_)
|
||||
storage_ptr(obj_.get_storage());
|
||||
relocate(&obj_, other.obj_);
|
||||
::new(&other.nat_.sp_) storage_ptr(
|
||||
obj_.get_storage());
|
||||
break;
|
||||
|
||||
case json::kind::array:
|
||||
::new(&arr_) array(
|
||||
std::move(other.arr_));
|
||||
other.arr_.~array();
|
||||
::new(&other.nat_.sp_)
|
||||
storage_ptr(arr_.get_storage());
|
||||
relocate(&arr_, other.arr_);
|
||||
::new(&other.nat_.sp_) storage_ptr(
|
||||
arr_.get_storage());
|
||||
break;
|
||||
|
||||
case json::kind::string:
|
||||
::new(&str_) string(
|
||||
std::move(other.str_));
|
||||
other.str_.~string();
|
||||
relocate(&str_, other.str_);
|
||||
::new(&other.nat_.sp_) storage_ptr(
|
||||
str_.get_allocator().get_storage());
|
||||
break;
|
||||
|
||||
case json::kind::number:
|
||||
::new(&nat_.sp_)
|
||||
storage_ptr(other.nat_.sp_);
|
||||
::new(&nat_.num_) number(
|
||||
other.nat_.num_);
|
||||
other.nat_.num_.~number();
|
||||
relocate(&nat_.num_, other.nat_.num_);
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
other.nat_.sp_);
|
||||
break;
|
||||
|
||||
case json::kind::boolean:
|
||||
::new(&nat_.sp_)
|
||||
storage_ptr(other.nat_.sp_);
|
||||
nat_.bool_ = other.nat_.bool_;
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
other.nat_.sp_);
|
||||
break;
|
||||
|
||||
case json::kind::null:
|
||||
::new(&nat_.sp_)
|
||||
storage_ptr(other.nat_.sp_);
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
other.nat_.sp_);
|
||||
break;
|
||||
}
|
||||
kind_ = other.kind_;
|
||||
other.kind_ = json::kind::null;
|
||||
}
|
||||
|
||||
value::
|
||||
value(
|
||||
value&& other,
|
||||
storage_ptr sp)
|
||||
{
|
||||
switch(other.kind_)
|
||||
{
|
||||
case json::kind::object:
|
||||
::new(&obj_) object(
|
||||
std::move(other.obj_),
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::array:
|
||||
::new(&arr_) array(
|
||||
std::move(other.arr_),
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::string:
|
||||
::new(&str_) string(
|
||||
std::move(other.str_),
|
||||
string::allocator_type(
|
||||
std::move(sp)));
|
||||
break;
|
||||
|
||||
case json::kind::number:
|
||||
relocate(&nat_.num_, other.nat_.num_);
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::boolean:
|
||||
nat_.bool_ = other.nat_.bool_;
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::null:
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
std::move(sp));
|
||||
break;
|
||||
}
|
||||
kind_ = other.kind_;
|
||||
}
|
||||
|
||||
value::
|
||||
value(pilfered<value> p) noexcept
|
||||
{
|
||||
@@ -89,31 +127,30 @@ value(pilfered<value> p) noexcept
|
||||
switch(other.kind_)
|
||||
{
|
||||
case json::kind::object:
|
||||
::new(&obj_) object(
|
||||
pilfer(other.obj_));
|
||||
relocate(&obj_, other.obj_);
|
||||
::new(&other.nat_.sp_) storage_ptr;
|
||||
break;
|
||||
|
||||
case json::kind::array:
|
||||
::new(&arr_) array(
|
||||
pilfer(other.arr_));
|
||||
relocate(&arr_, other.arr_);
|
||||
::new(&other.nat_.sp_) storage_ptr;
|
||||
break;
|
||||
|
||||
case json::kind::string:
|
||||
::new(&str_) string(
|
||||
std::move(other.str_));
|
||||
relocate(&str_, other.str_);
|
||||
::new(&other.nat_.sp_) storage_ptr;
|
||||
break;
|
||||
|
||||
case json::kind::number:
|
||||
relocate(&nat_.num_, other.nat_.num_);
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
std::move(other.nat_.sp_));
|
||||
::new(&nat_.num_) number(
|
||||
std::move(other.nat_.num_));
|
||||
break;
|
||||
|
||||
case json::kind::boolean:
|
||||
nat_.bool_ = other.nat_.bool_;
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
std::move(other.nat_.sp_));
|
||||
nat_.bool_ = other.nat_.bool_;
|
||||
break;
|
||||
|
||||
case json::kind::null:
|
||||
@@ -122,35 +159,71 @@ value(pilfered<value> p) noexcept
|
||||
break;
|
||||
}
|
||||
kind_ = other.kind_;
|
||||
}
|
||||
|
||||
value::
|
||||
value(
|
||||
value&& other,
|
||||
storage_ptr store)
|
||||
{
|
||||
move(std::move(store), std::move(other));
|
||||
other.kind_ = json::kind::null;
|
||||
}
|
||||
|
||||
value::
|
||||
value(value const& other)
|
||||
: value(other, other.get_storage())
|
||||
: value(
|
||||
other,
|
||||
other.get_storage())
|
||||
{
|
||||
}
|
||||
|
||||
value::
|
||||
value(
|
||||
value const& other,
|
||||
storage_ptr store)
|
||||
storage_ptr sp)
|
||||
{
|
||||
copy(std::move(store), other);
|
||||
switch(other.kind_)
|
||||
{
|
||||
case json::kind::object:
|
||||
::new(&obj_) object(
|
||||
other.obj_, std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::array:
|
||||
::new(&arr_) array(
|
||||
other.arr_, std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::string:
|
||||
::new(&str_) string(
|
||||
other.str_,
|
||||
string::allocator_type(
|
||||
std::move(sp)));
|
||||
break;
|
||||
|
||||
case json::kind::number:
|
||||
::new(&nat_.num_) number(
|
||||
other.nat_.num_);
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::boolean:
|
||||
nat_.bool_ = other.nat_.bool_;
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::null:
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
std::move(sp));
|
||||
break;
|
||||
}
|
||||
kind_ = other.kind_;
|
||||
}
|
||||
|
||||
value&
|
||||
value::
|
||||
operator=(value&& other)
|
||||
{
|
||||
move(destroy(), std::move(other));
|
||||
undo u(this);
|
||||
move(
|
||||
std::move(other),
|
||||
u.old.get_storage());
|
||||
u.commit = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -158,8 +231,13 @@ value&
|
||||
value::
|
||||
operator=(value const& other)
|
||||
{
|
||||
if(this != &other)
|
||||
copy(destroy(), other);
|
||||
if(this == &other)
|
||||
return *this;
|
||||
|
||||
undo u(this);
|
||||
::new(this) value(
|
||||
other, u.old.get_storage());
|
||||
u.commit = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -178,10 +256,10 @@ value() noexcept
|
||||
}
|
||||
|
||||
value::
|
||||
value(storage_ptr store) noexcept
|
||||
value(storage_ptr sp) noexcept
|
||||
: value(
|
||||
json::kind::null,
|
||||
std::move(store))
|
||||
std::move(sp))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -196,9 +274,9 @@ value(json::kind k) noexcept
|
||||
value::
|
||||
value(
|
||||
json::kind k,
|
||||
storage_ptr store) noexcept
|
||||
storage_ptr sp) noexcept
|
||||
{
|
||||
construct(k, std::move(store));
|
||||
construct(k, std::move(sp));
|
||||
}
|
||||
|
||||
value::
|
||||
@@ -211,10 +289,10 @@ value(object obj) noexcept
|
||||
value::
|
||||
value(
|
||||
object obj,
|
||||
storage_ptr store)
|
||||
storage_ptr sp)
|
||||
: obj_(
|
||||
std::move(obj),
|
||||
std::move(store))
|
||||
std::move(sp))
|
||||
, kind_(json::kind::object)
|
||||
{
|
||||
}
|
||||
@@ -229,8 +307,8 @@ value(array arr) noexcept
|
||||
value::
|
||||
value(
|
||||
array arr,
|
||||
storage_ptr store)
|
||||
: arr_(std::move(arr), std::move(store))
|
||||
storage_ptr sp)
|
||||
: arr_(std::move(arr), std::move(sp))
|
||||
, kind_(json::kind::array)
|
||||
{
|
||||
}
|
||||
@@ -245,8 +323,8 @@ value(string str) noexcept
|
||||
value::
|
||||
value(
|
||||
string str,
|
||||
storage_ptr store)
|
||||
: str_(move_string(str, store))
|
||||
storage_ptr sp)
|
||||
: str_(move_string(str, sp))
|
||||
, kind_(json::kind::string)
|
||||
{
|
||||
}
|
||||
@@ -261,40 +339,14 @@ value(number num)
|
||||
value::
|
||||
value(
|
||||
number num,
|
||||
storage_ptr store)
|
||||
storage_ptr sp)
|
||||
: kind_(json::kind::number)
|
||||
{
|
||||
::new(&nat_.num_) number(num);
|
||||
::new(&nat_.sp_) storage_ptr(
|
||||
std::move(store));
|
||||
std::move(sp));
|
||||
}
|
||||
|
||||
#if 0
|
||||
value::
|
||||
value(
|
||||
std::initializer_list<std::pair<
|
||||
string_view, value>> init)
|
||||
: value(
|
||||
init,
|
||||
default_storage())
|
||||
{
|
||||
}
|
||||
|
||||
value::
|
||||
value(
|
||||
std::initializer_list<std::pair<
|
||||
string_view, value>> init,
|
||||
storage_ptr store)
|
||||
: value(
|
||||
json::kind::object,
|
||||
std::move(store))
|
||||
{
|
||||
for(auto& e : init)
|
||||
obj_.emplace(e.first,
|
||||
std::move(e.second));
|
||||
}
|
||||
#endif
|
||||
|
||||
value::
|
||||
value(std::initializer_list<value> init)
|
||||
: value(
|
||||
@@ -306,19 +358,19 @@ value(std::initializer_list<value> init)
|
||||
value::
|
||||
value(
|
||||
std::initializer_list<value> init,
|
||||
storage_ptr store)
|
||||
storage_ptr sp)
|
||||
{
|
||||
if(maybe_object(init))
|
||||
{
|
||||
kind_ = json::kind::object;
|
||||
::new(&obj_) object(
|
||||
init, std::move(store));
|
||||
init, std::move(sp));
|
||||
}
|
||||
else
|
||||
{
|
||||
kind_ = json::kind::array;
|
||||
::new(&arr_) array(
|
||||
init, std::move(store));
|
||||
init, std::move(sp));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -894,13 +946,13 @@ typename std::enable_if<
|
||||
typename string::allocator_type
|
||||
>::value, string>::type
|
||||
value::
|
||||
move_string(S& str, storage_ptr& store)
|
||||
move_string(S& str, storage_ptr& sp)
|
||||
{
|
||||
// workaround for missing std::string
|
||||
// ctors in some stdlib versions
|
||||
auto s = string(typename
|
||||
string::allocator_type(
|
||||
std::move(store)));
|
||||
std::move(sp)));
|
||||
s = std::move(str);
|
||||
return s;
|
||||
}
|
||||
@@ -911,11 +963,11 @@ typename std::enable_if<
|
||||
typename string::allocator_type
|
||||
>::value, string>::type
|
||||
value::
|
||||
move_string(S& str, storage_ptr& store)
|
||||
move_string(S& str, storage_ptr& sp)
|
||||
{
|
||||
return {std::move(str), typename
|
||||
string::allocator_type(
|
||||
std::move(store))};
|
||||
std::move(sp))};
|
||||
}
|
||||
|
||||
storage_ptr
|
||||
@@ -1030,8 +1082,7 @@ struct value::op_move_string
|
||||
void
|
||||
value::
|
||||
move(
|
||||
storage_ptr sp,
|
||||
value&& other)
|
||||
value&& other, storage_ptr sp)
|
||||
{
|
||||
switch(other.kind_)
|
||||
{
|
||||
@@ -1115,7 +1166,7 @@ move(
|
||||
::new(&nat_.num_) number(
|
||||
std::move(other.nat_.num_));
|
||||
kind_ = other.kind_;
|
||||
nat_.num_.~number();
|
||||
other.nat_.num_.~number();
|
||||
other.kind_ = json::kind::null;
|
||||
break;
|
||||
|
||||
@@ -1168,93 +1219,6 @@ struct value::op_copy_string
|
||||
}
|
||||
};
|
||||
|
||||
// unchecked
|
||||
void
|
||||
value::
|
||||
copy(
|
||||
storage_ptr sp,
|
||||
value const& other)
|
||||
{
|
||||
switch(other.kind_)
|
||||
{
|
||||
case json::kind::object:
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
::new(&obj_) object(
|
||||
other.obj_, sp);
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
kind_ = json::kind::null;
|
||||
::new(&nat_.sp_)
|
||||
storage_ptr(std::move(sp));
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case json::kind::array:
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
::new(&arr_) array(
|
||||
other.arr_, sp);
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
kind_ = json::kind::null;
|
||||
::new(&nat_.sp_)
|
||||
storage_ptr(std::move(sp));
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case json::kind::string:
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
op_copy_string{*this, sp}(other.str_);
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
kind_ = json::kind::null;
|
||||
::new(&nat_.sp_)
|
||||
storage_ptr(std::move(sp));
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case json::kind::number:
|
||||
::new(&nat_.sp_)
|
||||
storage_ptr(std::move(sp));
|
||||
::new(&nat_.num_) number(
|
||||
other.nat_.num_);
|
||||
break;
|
||||
|
||||
case json::kind::boolean:
|
||||
::new(&nat_.sp_)
|
||||
storage_ptr(std::move(sp));
|
||||
nat_.bool_ = other.nat_.bool_;
|
||||
break;
|
||||
|
||||
case json::kind::null:
|
||||
::new(&nat_.sp_)
|
||||
storage_ptr(std::move(sp));
|
||||
break;
|
||||
}
|
||||
kind_ = other.kind_;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// friends
|
||||
|
||||
@@ -57,14 +57,12 @@ public:
|
||||
{
|
||||
BOOST_JSON_DECL
|
||||
static
|
||||
constexpr
|
||||
std::pair<
|
||||
std::uint64_t, std::uint64_t>
|
||||
init(std::true_type) noexcept;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
static
|
||||
constexpr
|
||||
std::pair<
|
||||
std::uint32_t, std::uint32_t>
|
||||
init(std::false_type) noexcept;
|
||||
@@ -312,7 +310,7 @@ public:
|
||||
BOOST_JSON_DECL
|
||||
void
|
||||
insert(
|
||||
std::initializer_list<value> list);
|
||||
std::initializer_list<value> init);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
insert_return_type
|
||||
|
||||
@@ -94,6 +94,7 @@ using has_to_json =
|
||||
*/
|
||||
class value
|
||||
{
|
||||
struct undo;
|
||||
friend class value_test;
|
||||
|
||||
#ifndef GENERATING_DOCUMENTATION
|
||||
@@ -134,15 +135,15 @@ public:
|
||||
BOOST_JSON_DECL
|
||||
value(value&& other) noexcept;
|
||||
|
||||
/// Pilfer constructor
|
||||
BOOST_JSON_DECL
|
||||
value(pilfered<value> other) noexcept;
|
||||
|
||||
/// Move construct a value, using the specified storage
|
||||
/// Storage-extended move constructor
|
||||
BOOST_JSON_DECL
|
||||
value(
|
||||
value&& other,
|
||||
storage_ptr store);
|
||||
storage_ptr sp);
|
||||
|
||||
/// Pilfer constructor
|
||||
BOOST_JSON_DECL
|
||||
value(pilfered<value> other) noexcept;
|
||||
|
||||
/// Construct a copy of a value
|
||||
BOOST_JSON_DECL
|
||||
@@ -152,7 +153,7 @@ public:
|
||||
BOOST_JSON_DECL
|
||||
value(
|
||||
value const& other,
|
||||
storage_ptr store);
|
||||
storage_ptr sp);
|
||||
|
||||
/// Move-assign a value
|
||||
BOOST_JSON_DECL
|
||||
@@ -180,7 +181,7 @@ public:
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
explicit
|
||||
value(storage_ptr store) noexcept;
|
||||
value(storage_ptr sp) noexcept;
|
||||
|
||||
/** Construct a value using the default storage
|
||||
|
||||
@@ -203,7 +204,7 @@ public:
|
||||
BOOST_JSON_DECL
|
||||
value(
|
||||
json::kind k,
|
||||
storage_ptr store) noexcept;
|
||||
storage_ptr sp) noexcept;
|
||||
|
||||
/** Construct a value from an object.
|
||||
*/
|
||||
@@ -213,7 +214,7 @@ public:
|
||||
/** Construct a value from an object using the specified storage
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
value(object obj, storage_ptr store);
|
||||
value(object obj, storage_ptr sp);
|
||||
|
||||
/** Construct a value from an array.
|
||||
*/
|
||||
@@ -223,7 +224,7 @@ public:
|
||||
/** Construct a value from an array using the specified storage
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
value(array arr, storage_ptr store);
|
||||
value(array arr, storage_ptr sp);
|
||||
|
||||
/** Construct a value from a string.
|
||||
*/
|
||||
@@ -233,7 +234,7 @@ public:
|
||||
/** Construct a value from a string using the specified storage
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
value(string str, storage_ptr store);
|
||||
value(string str, storage_ptr sp);
|
||||
|
||||
/** Construct a value from a number
|
||||
*/
|
||||
@@ -243,24 +244,7 @@ public:
|
||||
/** Construct a value from a number using the specified storage
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
value(number num, storage_ptr store);
|
||||
|
||||
#if 0
|
||||
/** Construct an object from an initializer list.
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
value(
|
||||
std::initializer_list<std::pair<
|
||||
string_view, value>> init);
|
||||
|
||||
/** Construct an object from an initializer list using the specified storage
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
value(
|
||||
std::initializer_list<std::pair<
|
||||
string_view, value>> init,
|
||||
storage_ptr store);
|
||||
#endif
|
||||
value(number num, storage_ptr sp);
|
||||
|
||||
/** Construct an array from an initializer list.
|
||||
*/
|
||||
@@ -271,7 +255,7 @@ public:
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
value(std::initializer_list<value> init,
|
||||
storage_ptr store);
|
||||
storage_ptr sp);
|
||||
|
||||
/** Assign a value from an object
|
||||
*/
|
||||
@@ -383,6 +367,14 @@ public:
|
||||
reset(json::kind::null);
|
||||
}
|
||||
|
||||
/** Swap this value with another value.
|
||||
|
||||
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
void
|
||||
swap(value& other) noexcept;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Exchange
|
||||
@@ -410,8 +402,8 @@ public:
|
||||
has_to_json<T>::value>::type
|
||||
#endif
|
||||
>
|
||||
value(T const& t, storage_ptr store)
|
||||
: value(std::move(store))
|
||||
value(T const& t, storage_ptr sp)
|
||||
: value(std::move(sp))
|
||||
{
|
||||
value_exchange<
|
||||
detail::remove_cr<T>
|
||||
@@ -932,11 +924,7 @@ private:
|
||||
|
||||
BOOST_JSON_DECL
|
||||
void
|
||||
move(storage_ptr, value&&);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
void
|
||||
copy(storage_ptr, value const&);
|
||||
move(value&&, storage_ptr);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
friend
|
||||
|
||||
34
test/Jamfile
34
test/Jamfile
@@ -8,24 +8,24 @@
|
||||
#
|
||||
|
||||
local SOURCES =
|
||||
_detail_stack.cpp
|
||||
allocator.cpp
|
||||
#_detail_stack.cpp
|
||||
#allocator.cpp
|
||||
array.cpp
|
||||
assign_string.cpp
|
||||
assign_vector.cpp
|
||||
basic_parser.cpp
|
||||
error.cpp
|
||||
iterator.cpp
|
||||
json.cpp
|
||||
kind.cpp
|
||||
number.cpp
|
||||
object.cpp
|
||||
parse_file.cpp
|
||||
parser.cpp
|
||||
serializer.cpp
|
||||
storage.cpp
|
||||
string.cpp
|
||||
value.cpp
|
||||
#assign_string.cpp
|
||||
#assign_vector.cpp
|
||||
#basic_parser.cpp
|
||||
#error.cpp
|
||||
#iterator.cpp
|
||||
#json.cpp
|
||||
#kind.cpp
|
||||
#number.cpp
|
||||
#object.cpp
|
||||
#parse_file.cpp
|
||||
#parser.cpp
|
||||
#serializer.cpp
|
||||
#storage.cpp
|
||||
#string.cpp
|
||||
#value.cpp
|
||||
;
|
||||
|
||||
local RUN_TESTS ;
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,json,stack);
|
||||
BEAST_DEFINE_TESTSUITE(boost,json,stack);
|
||||
|
||||
} // detail
|
||||
} // json
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,json,allocator);
|
||||
BEAST_DEFINE_TESTSUITE(boost,json,allocator);
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
849
test/array.cpp
849
test/array.cpp
File diff suppressed because it is too large
Load Diff
@@ -41,7 +41,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,json,assign_string);
|
||||
BEAST_DEFINE_TESTSUITE(boost,json,assign_string);
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,json,assign_vector);
|
||||
BEAST_DEFINE_TESTSUITE(boost,json,assign_vector);
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
@@ -312,7 +312,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,json,basic_parser);
|
||||
BEAST_DEFINE_TESTSUITE(boost,json,basic_parser);
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
@@ -62,7 +62,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,json,error);
|
||||
BEAST_DEFINE_TESTSUITE(boost,json,error);
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,json,iterator);
|
||||
BEAST_DEFINE_TESTSUITE(boost,json,iterator);
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,json,kind);
|
||||
BEAST_DEFINE_TESTSUITE(boost,json,kind);
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
@@ -316,7 +316,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,json,number);
|
||||
BEAST_DEFINE_TESTSUITE(boost,json,number);
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
@@ -886,7 +886,7 @@ public:
|
||||
obj1 = obj;
|
||||
break;
|
||||
}
|
||||
catch(std::bad_alloc const&)
|
||||
catch(test_failure const&)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -911,7 +911,7 @@ public:
|
||||
obj1 = obj;
|
||||
break;
|
||||
}
|
||||
catch(std::bad_alloc const&)
|
||||
catch(test_failure const&)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -935,7 +935,7 @@ public:
|
||||
obj1 = obj;
|
||||
break;
|
||||
}
|
||||
catch(std::bad_alloc const&)
|
||||
catch(test_failure const&)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -958,7 +958,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,json,object);
|
||||
BEAST_DEFINE_TESTSUITE(boost,json,object);
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
@@ -76,7 +76,7 @@ R"xx({
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,json,parser);
|
||||
BEAST_DEFINE_TESTSUITE(boost,json,parser);
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,json,serializer);
|
||||
BEAST_DEFINE_TESTSUITE(boost,json,serializer);
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,json,storage);
|
||||
BEAST_DEFINE_TESTSUITE(boost,json,storage);
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
//obj1 = obj;
|
||||
break;
|
||||
}
|
||||
catch(std::bad_alloc const&)
|
||||
catch(test_failure const&)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,json,string);
|
||||
BEAST_DEFINE_TESTSUITE(boost,json,string);
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
@@ -10,57 +10,16 @@
|
||||
#ifndef BOOST_JSON_TEST_STORAGE_HPP
|
||||
#define BOOST_JSON_TEST_STORAGE_HPP
|
||||
|
||||
#include <boost/json/value.hpp>
|
||||
#include <boost/json/storage.hpp>
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
struct fail_storage : storage
|
||||
{
|
||||
std::size_t fail_max = 1;
|
||||
std::size_t fail = 0;
|
||||
|
||||
void*
|
||||
allocate(
|
||||
std::size_t n,
|
||||
std::size_t) override
|
||||
{
|
||||
if(++fail == fail_max)
|
||||
{
|
||||
++fail_max;
|
||||
fail = 0;
|
||||
throw std::bad_alloc{};
|
||||
}
|
||||
return std::allocator<
|
||||
char>{}.allocate(n);
|
||||
}
|
||||
|
||||
void
|
||||
deallocate(
|
||||
void* p,
|
||||
std::size_t n,
|
||||
std::size_t) noexcept override
|
||||
{
|
||||
auto cp =
|
||||
reinterpret_cast<char*>(p);
|
||||
return std::allocator<
|
||||
char>{}.deallocate(cp, n);
|
||||
}
|
||||
bool
|
||||
is_equal(
|
||||
storage const& other
|
||||
) const noexcept override
|
||||
{
|
||||
auto p = dynamic_cast<
|
||||
fail_storage const*>(&other);
|
||||
if(! p)
|
||||
return false;
|
||||
return this == p;
|
||||
}
|
||||
};
|
||||
|
||||
struct unique_storage : storage
|
||||
{
|
||||
void*
|
||||
@@ -85,17 +44,173 @@ struct unique_storage : storage
|
||||
}
|
||||
bool
|
||||
is_equal(
|
||||
storage const& other
|
||||
) const noexcept override
|
||||
storage const&) const noexcept override
|
||||
{
|
||||
auto p = dynamic_cast<
|
||||
unique_storage const*>(&other);
|
||||
if(! p)
|
||||
return false;
|
||||
return this == p;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct test_failure : std::exception
|
||||
{
|
||||
virtual
|
||||
char const*
|
||||
what() const noexcept override
|
||||
{
|
||||
return "test failure";
|
||||
}
|
||||
};
|
||||
|
||||
struct fail_storage : storage
|
||||
{
|
||||
std::size_t fail_max = 1;
|
||||
std::size_t fail = 0;
|
||||
|
||||
~fail_storage()
|
||||
{
|
||||
}
|
||||
|
||||
void*
|
||||
allocate(
|
||||
std::size_t n,
|
||||
std::size_t) override
|
||||
{
|
||||
if(++fail == fail_max)
|
||||
{
|
||||
++fail_max;
|
||||
fail = 0;
|
||||
throw test_failure{};
|
||||
}
|
||||
return std::allocator<
|
||||
char>{}.allocate(n);
|
||||
}
|
||||
|
||||
void
|
||||
deallocate(
|
||||
void* p,
|
||||
std::size_t n,
|
||||
std::size_t) noexcept override
|
||||
{
|
||||
auto cp =
|
||||
reinterpret_cast<char*>(p);
|
||||
return std::allocator<
|
||||
char>{}.deallocate(cp, n);
|
||||
}
|
||||
bool
|
||||
is_equal(
|
||||
storage const&) const noexcept override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class scoped_fail_storage
|
||||
{
|
||||
storage_ptr sp_;
|
||||
|
||||
public:
|
||||
scoped_fail_storage()
|
||||
: sp_(default_storage())
|
||||
{
|
||||
default_storage(
|
||||
make_storage<fail_storage>());
|
||||
}
|
||||
|
||||
~scoped_fail_storage()
|
||||
{
|
||||
default_storage(sp_);
|
||||
}
|
||||
};
|
||||
|
||||
template<class F>
|
||||
void
|
||||
fail_loop(F&& f)
|
||||
{
|
||||
auto sp = make_storage<fail_storage>();
|
||||
while(sp->fail < 200)
|
||||
{
|
||||
try
|
||||
{
|
||||
f(sp);
|
||||
}
|
||||
catch(test_failure const&)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
BEAST_EXPECT(sp->fail < 200);
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
equal_storage(
|
||||
value const& v,
|
||||
storage_ptr const& sp);
|
||||
|
||||
inline
|
||||
bool
|
||||
equal_storage(
|
||||
array const& a,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
if(*a.get_storage() != *sp)
|
||||
return false;
|
||||
for(auto const& v : a)
|
||||
if(! equal_storage(v, sp))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
equal_storage(
|
||||
value const& v,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
switch(v.kind())
|
||||
{
|
||||
case json::kind::object:
|
||||
if(*v.as_object().get_storage() != *sp)
|
||||
return false;
|
||||
for(auto const& e : v)
|
||||
if(! equal_storage(e.second, sp))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
case json::kind::array:
|
||||
if(*v.as_array().get_storage() != *sp)
|
||||
return false;
|
||||
return equal_storage(v.as_array(), sp);
|
||||
|
||||
case json::kind::string:
|
||||
return *v.as_string().get_allocator().get_storage() == *sp;
|
||||
|
||||
case json::kind::number:
|
||||
case json::kind::boolean:
|
||||
case json::kind::null:
|
||||
break;
|
||||
}
|
||||
|
||||
return *v.get_storage() == *sp;
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
check_storage(
|
||||
array const& a,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
BEAST_EXPECT(equal_storage(a, sp));
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
check_storage(
|
||||
value const& v,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
BEAST_EXPECT(equal_storage(v, sp));
|
||||
}
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
|
||||
@@ -656,7 +656,37 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,json,value);
|
||||
BEAST_DEFINE_TESTSUITE(boost,json,value);
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
#if 0
|
||||
|
||||
/** {brief}
|
||||
|
||||
{description}
|
||||
|
||||
@par Constraints
|
||||
|
||||
{constraints}
|
||||
|
||||
@par Requires
|
||||
|
||||
{requires}
|
||||
|
||||
@par Complexity
|
||||
|
||||
{complexity}
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
Strong guarantee.
|
||||
Calls to @ref storage::allocate may throw.
|
||||
|
||||
@param {name} {desc}
|
||||
|
||||
@tparam {type} {desc}
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user