array coverage

This commit is contained in:
Vinnie Falco 2019-10-02 06:09:12 -07:00
parent 790b39b943
commit ec6e8c60b3
11 changed files with 259 additions and 282 deletions

View File

@ -74,14 +74,12 @@ class value;
class array
{
struct table;
struct undo;
friend class value;
table* tab_ = nullptr;
storage_ptr sp_;
struct cleanup_assign;
struct cleanup_insert;
struct undo;
struct undo_insert;
public:
/// The type of each element
@ -1642,10 +1640,6 @@ private:
const_iterator pos,
Arg&& arg);
BOOST_JSON_DECL
storage_ptr
release_storage() noexcept;
BOOST_JSON_DECL
void
copy(array const& other);

View File

@ -87,39 +87,26 @@ struct array::table
//------------------------------------------------------------------------------
struct array::cleanup_assign
struct array::undo_insert
{
value* it;
array& self;
table* tab;
bool ok = false;
size_type const pos;
size_type const n;
bool commit = false;
BOOST_JSON_DECL
explicit
cleanup_assign(
array& self);
BOOST_JSON_DECL
~cleanup_assign();
};
//------------------------------------------------------------------------------
struct array::cleanup_insert
{
array& self;
size_type pos;
size_type n;
size_type valid = 0;
bool ok = false;
BOOST_JSON_DECL
cleanup_insert(
size_type pos_,
inline
undo_insert(
value const* pos_,
size_type n_,
array& self_);
BOOST_JSON_DECL
~cleanup_insert();
inline
~undo_insert();
template<class Arg>
void
emplace(Arg&& arg);
};
//------------------------------------------------------------------------------
@ -242,18 +229,13 @@ insert(
std::forward_iterator_tag) ->
iterator
{
auto count = std::distance(first, last);
auto d = pos - begin();
reserve(size() + count);
cleanup_insert c(d, count, *this);
while(count--)
{
::new(&begin()[d++]) value(
*first++, sp_);
++c.valid;
}
c.ok = true;
return begin() + c.pos;
undo_insert u(
pos, std::distance(
first, last), *this);
while(first != last)
u.emplace(*first++);
u.commit = true;
return begin() + u.pos;
}
template<class Arg>
@ -264,13 +246,12 @@ emplace_impl(
Arg&& arg) ->
iterator
{
auto const d = pos - begin();
reserve(size() + 1);
cleanup_insert c(d, 1, *this);
::new(&tab_->begin()[d]) value(
std::forward<Arg>(arg), sp_);
c.ok = true;
return begin() + d;
undo_insert u(
pos, 1, *this);
u.emplace(
std::forward<Arg>(arg));
u.commit = true;
return begin() + u.pos;
}
} // json

View File

@ -104,72 +104,53 @@ struct array::undo
//------------------------------------------------------------------------------
array::
cleanup_assign::
cleanup_assign(
array& self_)
: self(self_)
, tab(boost::exchange(
self_.tab_, nullptr))
{
}
array::
cleanup_assign::
~cleanup_assign()
{
if(ok)
{
if(tab)
table::destroy(tab, self.sp_);
}
else
{
if(self.tab_)
table::destroy(
self.tab_, self.sp_);
self.tab_ = tab;
}
}
//------------------------------------------------------------------------------
array::
cleanup_insert::
cleanup_insert(
size_type pos_,
undo_insert::
undo_insert(
value const* pos_,
size_type n_,
array& self_)
: self(self_)
, pos(pos_)
, pos(pos_ - self_.begin())
, n(n_)
{
self.reserve(self.size() + n);
// (iterators invalidated now)
it = self.begin() + pos;
self.move(
self.data() + pos + n,
self.data() + pos,
it + n, it,
self.size() - pos);
self.tab_->d.size += n;
}
array::
cleanup_insert::
~cleanup_insert()
undo_insert::
~undo_insert()
{
if(ok)
if(! commit)
{
self.tab_->d.size += n;
}
else
{
for(size_type i = n;
valid--; ++i)
self[i].~value();
table::destroy(
self.begin() + pos, it);
self.tab_->d.size -= n;
auto const first =
self.begin() + pos;
self.move(
self.data() + pos,
self.data() + pos + n,
first, first + n,
self.size() - pos);
}
}
template<class Arg>
void
array::
undo_insert::
emplace(Arg&& arg)
{
::new(it) value(
std::forward<Arg>(arg),
self.sp_);
++it;
}
//------------------------------------------------------------------------------
//
// Special Members
@ -213,17 +194,17 @@ array(
storage_ptr sp)
: sp_(std::move(sp))
{
if(count > 0)
if(count == 0)
return;
undo u{table::create(
count, sp_), sp_};
while(count--)
{
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);
::new(u.tab->end()) value(v, sp_);
++u.tab->d.size;
}
std::swap(tab_, u.tab);
}
array::
@ -588,26 +569,27 @@ shrink_to_fit() noexcept
{
if(capacity() <= size())
return;
table* tab;
if(tab_->d.size == 0)
{
table::destroy(tab_, sp_);
tab_ = nullptr;
return;
}
if( size() < 3 &&
capacity() <= 3)
if(size() < 3 && capacity() <= 3)
return;
table* tab;
#ifndef BOOST_NO_EXCEPTIONS
try
#endif
{
tab = table::create(tab_->d.size, sp_);
}
#endif
tab = table::create(
tab_->d.size, sp_);
#ifndef BOOST_NO_EXCEPTIONS
}
catch(...)
{
// eat the exception
return;
}
#endif
@ -668,17 +650,11 @@ insert(
value const& v) ->
iterator
{
auto p = pos - begin();
reserve(size() + count);
cleanup_insert c(p, count, *this);
undo_insert u(pos, count, *this);
while(count--)
{
::new(&begin()[p++])
value(v, sp_);
++c.valid;
}
c.ok = true;
return begin() + c.pos;
u.emplace(v);
u.commit = true;
return begin() + u.pos;
}
auto
@ -688,19 +664,12 @@ insert(
std::initializer_list<value> init) ->
iterator
{
auto p = pos - begin();
reserve(size() + init.size());
cleanup_insert c(
p, init.size(), *this);
for(auto it = init.begin();
it != init.end(); ++it)
{
::new(&begin()[p++]) value(
std::move(*it), sp_);
++c.valid;
}
c.ok = true;
return begin() + c.pos;
undo_insert u(
pos, init.size(), *this);
for(auto& v : init)
u.emplace(std::move(v));
u.commit = true;
return begin() + u.pos;
}
auto
@ -725,7 +694,8 @@ erase(
auto const n = last - first;
auto p = data() + (first - begin());
table::destroy(p, p + n);
move(p, p + n, n);
move(p, p + n,
size() - (last - begin()));
tab_->d.size -= n;
return p;
}
@ -827,29 +797,16 @@ swap(array& other) noexcept
//------------------------------------------------------------------------------
storage_ptr
array::
release_storage() noexcept
{
if(tab_)
{
table::destroy(tab_, sp_);
tab_ = nullptr;
}
return std::move(sp_);
}
void
array::
copy(array const& other)
{
if(other.empty())
{
if(tab_)
{
table::destroy(tab_, sp_);
tab_ = nullptr;
}
if(! tab_)
return;
table::destroy(tab_, sp_);
tab_ = nullptr;
return;
}
@ -889,15 +846,15 @@ move(
void
array::
assign(std::initializer_list<value> init)
assign(
std::initializer_list<value> init)
{
if(init.size() == 0)
{
if(tab_)
{
table::destroy(tab_, sp_);
tab_ = nullptr;
}
if(! tab_)
return;
table::destroy(tab_, sp_);
tab_ = nullptr;
return;
}

View File

@ -1166,19 +1166,6 @@ reserve(size_type count)
//------------------------------------------------------------------------------
storage_ptr
object::
release_storage() noexcept
{
if(tab_)
{
table::destroy_list(tab_, sp_);
table::destroy(tab_, sp_);
tab_ = nullptr;
}
return std::move(sp_);
}
auto
object::
constrain_hash(

View File

@ -32,13 +32,13 @@ raw_default_storage() noexcept
} // detail
storage_ptr
default_storage()
default_storage() noexcept
{
return detail::raw_default_storage();
}
void
default_storage(storage_ptr sp)
default_storage(storage_ptr sp) noexcept
{
detail::raw_default_storage() = std::move(sp);
}

View File

@ -21,7 +21,29 @@ namespace json {
value::
~value()
{
destroy();
switch(kind_)
{
case json::kind::object:
obj_.~object();
break;
case json::kind::array:
arr_.~array();
break;
case json::kind::string:
str_.~string();
break;
case json::kind::number:
nat_.num_.~number();
BOOST_FALLTHROUGH;
case json::kind::boolean:
case json::kind::null:
nat_.sp_.~storage_ptr();
break;
}
}
value::
@ -932,41 +954,6 @@ pop_back()
// private
storage_ptr
value::
destroy() noexcept
{
storage_ptr sp;
switch(kind_)
{
case json::kind::object:
sp = obj_.release_storage();
obj_.~object();
break;
case json::kind::array:
sp = arr_.release_storage();
arr_.~array();
break;
case json::kind::string:
sp = str_.get_allocator().get_storage();
str_.~string();
break;
case json::kind::number:
nat_.num_.~number();
BOOST_FALLTHROUGH;
case json::kind::boolean:
case json::kind::null:
sp = std::move(nat_.sp_);
nat_.sp_.~storage_ptr();
break;
}
return sp;
}
template<class S>
auto
value::

View File

@ -570,10 +570,6 @@ private:
key_type key,
Arg&& arg);
BOOST_JSON_DECL
storage_ptr
release_storage() noexcept;
BOOST_JSON_DECL
static
size_type

View File

@ -241,7 +241,7 @@ make_storage_adaptor(Allocator const& a);
*/
BOOST_JSON_DECL
storage_ptr
default_storage();
default_storage() noexcept;
/** Set the current default storage
@ -250,7 +250,7 @@ default_storage();
*/
BOOST_JSON_DECL
void
default_storage(storage_ptr sp);
default_storage(storage_ptr sp) noexcept;
} // json
} // boost

View File

@ -889,10 +889,6 @@ public:
//--------------------------------------------------------------------------
private:
BOOST_JSON_DECL
storage_ptr
destroy() noexcept;
BOOST_JSON_DECL
void
construct(

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

@ -71,12 +71,18 @@ public:
}
// array(size_type, value, storage)
fail_loop([](storage_ptr const& sp)
{
array a(3, true, sp);
BEAST_EXPECT(a.size() == 3);
check_storage(a, sp);
});
{
array(0, true);
}
fail_loop([](storage_ptr const& sp)
{
array a(3, true, sp);
BEAST_EXPECT(a.size() == 3);
check_storage(a, sp);
});
}
// array(size_type)
{
@ -116,12 +122,25 @@ public:
// array(array const&)
{
std::initializer_list<value> init =
{ 1, true, "hello" };
array a1(init.begin(), init.end());
array a2(a1);
check(a2);
check_storage(a2, default_storage());
{
array a1;
array a2(a1);
}
{
array a1;
array a2({ 1, true, "hello" });
a2 = a1;
}
{
std::initializer_list<value> init =
{ 1, true, "hello" };
array a1(init.begin(), init.end());
array a2(a1);
check(a2);
check_storage(a2, default_storage());
}
}
// array(array const&, storage)
@ -159,17 +178,31 @@ public:
}
// array(array&&, storage)
fail_loop([this](storage_ptr const& sp)
{
std::initializer_list<value> init =
{ 1, true, "hello" };
array a1(init.begin(), init.end());
array a2(std::move(a1), sp);
BEAST_EXPECT(! a1.empty());
check(a2);
check_storage(a1, default_storage());
check_storage(a2, sp);
});
{
std::initializer_list<value> init =
{ 1, true, "hello" };
array a1(init.begin(), init.end());
array a2(
std::move(a1), default_storage());
BEAST_EXPECT(a1.empty());
check(a2);
check_storage(a1, default_storage());
check_storage(a2, default_storage());
}
fail_loop([this](storage_ptr const& sp)
{
std::initializer_list<value> init =
{ 1, true, "hello" };
array a1(init.begin(), init.end());
array a2(std::move(a1), sp);
BEAST_EXPECT(! a1.empty());
check(a2);
check_storage(a1, default_storage());
check_storage(a2, sp);
});
}
// array(init_list)
{
@ -234,6 +267,16 @@ public:
// operator=(init_list)
{
{
array a;
a = {};
}
{
array a({ 1, true, "hello" });
a = {};
}
{
std::initializer_list<value> init =
{ 1, true, "hello" };
@ -504,9 +547,26 @@ public:
// reserve()
{
array a;
a.reserve(50);
BEAST_EXPECT(a.capacity() >= 50);
{
array a;
a.reserve(0);
}
{
array a(3);
a.reserve(1);
}
{
array a(3);
a.reserve(0);
}
{
array a;
a.reserve(50);
BEAST_EXPECT(a.capacity() >= 50);
}
}
// capacity()
@ -517,6 +577,13 @@ public:
// shrink_to_fit()
{
{
array a(1);
a.shrink_to_fit();
BEAST_EXPECT(a.size() == 1);
BEAST_EXPECT(a.capacity() >= 1);
}
fail_loop([](storage_ptr const& sp)
{
array a(1, sp);
@ -567,7 +634,7 @@ public:
}
}
// insert(before, value_type const&)
// insert(const_iterator, value_type const&)
fail_loop([this](storage_ptr const& sp)
{
array a({1, "hello"}, sp);
@ -577,28 +644,31 @@ public:
check_storage(a, sp);
});
// insert(before, value_type const&)
// insert(const_iterator, value_type&&)
fail_loop([this](storage_ptr const& sp)
{
array a({1, "hello"}, sp);
a.insert(a.begin() + 1, true);
value v(true);
a.insert(
a.begin() + 1, std::move(v));
check(a);
check_storage(a, sp);
});
// insert(before, size_type, value_type const&)
// insert(const_iterator, size_type, value_type const&)
fail_loop([this](storage_ptr const& sp)
{
value v({1,2,3});
array a({1, "hello"}, sp);
a.insert(a.begin() + 1, 3, true);
a.insert(a.begin() + 1, 3, v);
BEAST_EXPECT(a[0].is_number());
BEAST_EXPECT(a[1].is_bool());
BEAST_EXPECT(a[2].is_bool());
BEAST_EXPECT(a[3].is_bool());
BEAST_EXPECT(a[1].size() == 3);
BEAST_EXPECT(a[2].size() == 3);
BEAST_EXPECT(a[3].size() == 3);
BEAST_EXPECT(a[4].is_string());
});
// insert(before, InputIt, InputIt)
// insert(const_iterator, InputIt, InputIt)
fail_loop([this](storage_ptr const& sp)
{
std::initializer_list<
@ -609,7 +679,7 @@ public:
check(a);
});
// insert(before, init_list)
// insert(const_iterator, init_list)
fail_loop([this](storage_ptr const& sp)
{
array a({"hello"}, sp);
@ -617,7 +687,7 @@ public:
check(a);
});
// emplace(before, arg)
// emplace(const_iterator, arg)
fail_loop([this](storage_ptr const& sp)
{
array a({1, "hello"}, sp);
@ -634,6 +704,15 @@ public:
check(a);
}
// erase(first, last)
{
array a({1, true, nullptr, 1.f, "hello"});
a.erase(
a.begin() + 2,
a.begin() + 4);
check(a);
}
// push_back(value const&)
fail_loop([this](storage_ptr const& sp)
{
@ -786,7 +865,7 @@ public:
check(a1);
}
// insert(before, count, value_type const&)
// insert(const_iterator, count, value_type const&)
{
auto sp = make_storage<fail_storage>();
array a1;
@ -813,7 +892,7 @@ public:
}
#if _ITERATOR_DEBUG_LEVEL == 0
// insert(before, InputIt, InputIt)
// insert(const_iterator, InputIt, InputIt)
{
std::initializer_list<value> init(
{1, true, "hello"});
@ -837,7 +916,7 @@ public:
}
#endif
// emplace(before, arg)
// emplace(const_iterator, arg)
{
auto sp = make_storage<fail_storage>();
array a1;
@ -861,7 +940,7 @@ public:
}
#if _ITERATOR_DEBUG_LEVEL == 0
// emplace(before, arg)
// emplace(const_iterator, arg)
{
auto sp = make_storage<fail_storage>();
array a1;