2
0
mirror of https://github.com/boostorg/json.git synced 2026-01-19 04:12:14 +00:00

array work

This commit is contained in:
Vinnie Falco
2019-09-29 18:53:17 -07:00
parent 5c1b523702
commit 5f25cdff99
29 changed files with 2587 additions and 927 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -46,7 +46,7 @@ public:
}
};
BEAST_DEFINE_TESTSUITE(beast,json,stack);
BEAST_DEFINE_TESTSUITE(boost,json,stack);
} // detail
} // json

View File

@@ -43,7 +43,7 @@ public:
}
};
BEAST_DEFINE_TESTSUITE(beast,json,allocator);
BEAST_DEFINE_TESTSUITE(boost,json,allocator);
} // json
} // boost

File diff suppressed because it is too large Load Diff

View File

@@ -41,7 +41,7 @@ public:
}
};
BEAST_DEFINE_TESTSUITE(beast,json,assign_string);
BEAST_DEFINE_TESTSUITE(boost,json,assign_string);
} // json
} // boost

View File

@@ -50,7 +50,7 @@ public:
}
};
BEAST_DEFINE_TESTSUITE(beast,json,assign_vector);
BEAST_DEFINE_TESTSUITE(boost,json,assign_vector);
} // json
} // boost

View File

@@ -312,7 +312,7 @@ public:
}
};
BEAST_DEFINE_TESTSUITE(beast,json,basic_parser);
BEAST_DEFINE_TESTSUITE(boost,json,basic_parser);
} // json
} // boost

View File

@@ -62,7 +62,7 @@ public:
}
};
BEAST_DEFINE_TESTSUITE(beast,json,error);
BEAST_DEFINE_TESTSUITE(boost,json,error);
} // json
} // boost

View File

@@ -111,7 +111,7 @@ public:
}
};
BEAST_DEFINE_TESTSUITE(beast,json,iterator);
BEAST_DEFINE_TESTSUITE(boost,json,iterator);
} // json
} // boost

View File

@@ -35,7 +35,7 @@ public:
}
};
BEAST_DEFINE_TESTSUITE(beast,json,kind);
BEAST_DEFINE_TESTSUITE(boost,json,kind);
} // json
} // boost

View File

@@ -316,7 +316,7 @@ public:
}
};
BEAST_DEFINE_TESTSUITE(beast,json,number);
BEAST_DEFINE_TESTSUITE(boost,json,number);
} // json
} // boost

View File

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

View File

@@ -76,7 +76,7 @@ R"xx({
}
};
BEAST_DEFINE_TESTSUITE(beast,json,parser);
BEAST_DEFINE_TESTSUITE(boost,json,parser);
} // json
} // boost

View File

@@ -60,7 +60,7 @@ public:
}
};
BEAST_DEFINE_TESTSUITE(beast,json,serializer);
BEAST_DEFINE_TESTSUITE(boost,json,serializer);
} // json
} // boost

View File

@@ -32,7 +32,7 @@ public:
}
};
BEAST_DEFINE_TESTSUITE(beast,json,storage);
BEAST_DEFINE_TESTSUITE(boost,json,storage);
} // json
} // boost

View File

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

View File

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

View File

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