variant fixes and tests

This commit is contained in:
Vinnie Falco
2017-07-25 11:20:01 -07:00
parent c831afd93b
commit 3cba28f308
6 changed files with 152 additions and 25 deletions

View File

@ -2,6 +2,7 @@ Version 87:
* Update appveyor for Boost branch
* Rename to BEAST_EXPECT
* variant fixes and tests
--------------------------------------------------------------------------------

View File

@ -82,6 +82,22 @@ max_sizeof()
max_sizeof<U0>() : max_sizeof<U1, Us...>();
}
template<class U>
std::size_t constexpr
max_alignof()
{
return alignof(U);
}
template<class U0, class U1, class... Us>
std::size_t constexpr
max_alignof()
{
return
max_alignof<U0>() > max_alignof<U1, Us...>() ?
max_alignof<U0>() : max_alignof<U1, Us...>();
}
template<unsigned N, class T, class... Tn>
struct repeat_tuple_impl
{

View File

@ -32,7 +32,9 @@ template<class... TN>
class variant
{
typename std::aligned_storage<
max_sizeof<TN...>()>::type buf_;
max_sizeof<TN...>(),
max_alignof<TN...>()
>::type buf_;
unsigned char i_ = 0;
template<std::size_t I>
@ -51,6 +53,14 @@ public:
destroy(C<0>{});
}
// 0 = empty
unsigned char
index() const
{
return i_;
}
// moved-from object becomes empty
variant(variant&& other)
{
i_ = other.move(&buf_, C<0>{});
@ -61,6 +71,7 @@ public:
i_ = other.copy(&buf_, C<0>{});
}
// moved-from object becomes empty
variant& operator=(variant&& other)
{
if(i_ != 0)
@ -83,7 +94,6 @@ public:
{
if(i_ != 0)
destroy(C<0>{});
i_ = 0;
new(&buf_) type<I-1>(
std::forward<Args>(args)...);
i_ = I;
@ -99,7 +109,7 @@ public:
}
template<std::size_t I>
type<I-1>&
type<I-1> const&
get() const
{
BOOST_ASSERT(i_ == I);
@ -130,6 +140,7 @@ private:
{
using T = type<I>;
get<I+1>().~T();
i_ = 0;
return;
}
destroy(C<I+1>{});
@ -153,7 +164,7 @@ private:
i_ = 0;
return I+1;
}
move(C<I+1>{});
return move(dest, C<I+1>{});
}
unsigned char
@ -173,7 +184,7 @@ private:
new(dest) T{t};
return I+1;
}
copy(C<I+1>{});
return copy(dest, C<I+1>{});
}
};

View File

@ -52,5 +52,6 @@ add_executable (core-tests
base64.cpp
empty_base_optimization.cpp
sha1.cpp
detail/variant.cpp
detail/varint.cpp
)

View File

@ -41,5 +41,6 @@ unit-test core-tests :
base64.cpp
empty_base_optimization.cpp
sha1.cpp
detail/variant.cpp
detail/varint.cpp
;

View File

@ -9,6 +9,7 @@
#include <boost/beast/core/detail/variant.hpp>
#include <boost/beast/unit_test/suite.hpp>
#include <exception>
#include <string>
namespace boost {
@ -29,17 +30,44 @@ public:
return n;
}
int value = 0;
bool move = false;
bool copy = false;
bool move_assign = false;
bool copy_assign = false;
Q() { ++count(); }
~Q() { --count(); }
Q(Q&&) { ++count(); move = true; }
Q(Q const&) { ++count(); copy = true; }
Q& operator=(Q&&) { move_assign = true; return *this; }
Q& operator=(Q const&) { copy_assign = true; return *this; }
Q& operator=(Q&& q) = delete;
Q& operator=(Q const& q) = delete;
~Q()
{
--count();
}
Q()
{
++count();
}
Q(Q&& q)
{
if(q.value < 0)
throw std::exception{};
++count();
move = true;
}
Q(Q const& q)
{
if(q.value < 0)
throw std::exception{};
++count();
copy = true;
}
explicit Q(int value_)
: value(value_)
{
++count();
}
};
void
@ -58,6 +86,9 @@ public:
v.emplace<1>(10);
BEAST_EXPECT(v.index() == 1);
BEAST_EXPECT(v.get<1>() == 10);
v.emplace<1>(20);
BEAST_EXPECT(v.index() == 1);
BEAST_EXPECT(v.get<1>() == 20);
}
{
variant<std::string> v;
@ -70,6 +101,10 @@ public:
BEAST_EXPECT(Q<1>::count() == 0);
v.emplace<1>();
BEAST_EXPECT(Q<1>::count() == 1);
BEAST_EXPECT(v.get<1>().value == 0);
v.emplace<1>(42);
BEAST_EXPECT(Q<1>::count() == 1);
BEAST_EXPECT(v.get<1>().value == 42);
v.reset();
BEAST_EXPECT(Q<1>::count() == 0);
}
@ -200,40 +235,51 @@ public:
BEAST_EXPECT(v2.index() == 0);
BEAST_EXPECT(v3.get<1>() == "Hello");
}
{
variant<Q<1>, Q<2>> v1;
variant<Q<1>, Q<2>> v2;
v1.emplace<1>();
BEAST_EXPECT(v1.index() == 1);
BEAST_EXPECT(Q<1>::count() == 1);
v2.emplace<2>();
BEAST_EXPECT(v2.index() == 2);
BEAST_EXPECT(Q<2>::count() == 1);
v2 = std::move(v1);
BEAST_EXPECT(v1.index() == 0);
BEAST_EXPECT(v2.index() == 1);
BEAST_EXPECT(Q<1>::count() == 1);
BEAST_EXPECT(Q<2>::count() == 0);
}
BEAST_EXPECT(Q<1>::count() == 0);
BEAST_EXPECT(Q<2>::count() == 0);
{
variant<Q<1>> v1;
v1.emplace<1>();
BEAST_EXPECT(! v1.get<1>().move_assign);
BEAST_EXPECT(Q<1>::count() == 1);
variant<Q<1>> v2;
v2.emplace<1>();
BEAST_EXPECT(Q<1>::count() == 2);
BEAST_EXPECT(! v2.get<1>().move_assign);
v2 = std::move(v1);
BEAST_EXPECT(v1.index() == 0);
BEAST_EXPECT(v2.index() == 1);
BEAST_EXPECT(v2.get<1>().move);
BEAST_EXPECT(!v2.get<1>().move_assign);
BEAST_EXPECT(Q<1>::count() == 1);
}
BEAST_EXPECT(Q<1>::count() == 0);
{
variant<Q<1>, Q<2>, Q<3>> v1;
v1.emplace<2>();
BEAST_EXPECT(! v1.get<2>().move_assign);
BEAST_EXPECT(Q<1>::count() == 0);
BEAST_EXPECT(Q<2>::count() == 1);
BEAST_EXPECT(Q<3>::count() == 0);
variant<Q<1>, Q<2>, Q<3>> v2;
v2.emplace<2>();
BEAST_EXPECT(! v2.get<2>().move_assign);
BEAST_EXPECT(Q<1>::count() == 0);
BEAST_EXPECT(Q<2>::count() == 2);
BEAST_EXPECT(Q<3>::count() == 0);
v2 = std::move(v1);
BEAST_EXPECT(v1.index() == 0);
BEAST_EXPECT(v2.index() == 2);
BEAST_EXPECT(! v2.get<2>().move_assign);
BEAST_EXPECT(v2.get<2>().move);
BEAST_EXPECT(Q<1>::count() == 0);
BEAST_EXPECT(Q<2>::count() == 1);
@ -257,19 +303,31 @@ public:
BEAST_EXPECT(v2.get<1>() == "Hello");
BEAST_EXPECT(v3.get<1>() == "Hello");
}
{
variant<Q<1>, Q<2>> v1;
variant<Q<1>, Q<2>> v2;
v1.emplace<1>();
BEAST_EXPECT(v1.index() == 1);
BEAST_EXPECT(Q<1>::count() == 1);
v2.emplace<2>();
BEAST_EXPECT(v2.index() == 2);
BEAST_EXPECT(Q<2>::count() == 1);
v2 = v1;
BEAST_EXPECT(v1.index() == 1);
BEAST_EXPECT(v2.index() == 1);
BEAST_EXPECT(Q<1>::count() == 2);
BEAST_EXPECT(Q<2>::count() == 0);
}
{
variant<Q<1>> v1;
v1.emplace<1>();
BEAST_EXPECT(! v1.get<1>().copy_assign);
BEAST_EXPECT(Q<1>::count() == 1);
variant<Q<1>> v2;
v2.emplace<1>();
BEAST_EXPECT(Q<1>::count() == 2);
BEAST_EXPECT(! v2.get<1>().copy_assign);
v2 = v1;
BEAST_EXPECT(v1.index() == 1);
BEAST_EXPECT(v2.index() == 1);
BEAST_EXPECT(! v2.get<1>().copy_assign);
BEAST_EXPECT(v2.get<1>().copy);
BEAST_EXPECT(Q<1>::count() == 2);
}
@ -277,20 +335,17 @@ public:
{
variant<Q<1>, Q<2>, Q<3>> v1;
v1.emplace<2>();
BEAST_EXPECT(! v1.get<2>().copy_assign);
BEAST_EXPECT(Q<1>::count() == 0);
BEAST_EXPECT(Q<2>::count() == 1);
BEAST_EXPECT(Q<3>::count() == 0);
variant<Q<1>, Q<2>, Q<3>> v2;
v2.emplace<2>();
BEAST_EXPECT(! v2.get<2>().copy_assign);
BEAST_EXPECT(Q<1>::count() == 0);
BEAST_EXPECT(Q<2>::count() == 2);
BEAST_EXPECT(Q<3>::count() == 0);
v2 = v1;
BEAST_EXPECT(v1.index() == 2);
BEAST_EXPECT(v2.index() == 2);
BEAST_EXPECT(! v2.get<2>().copy_assign);
BEAST_EXPECT(v2.get<2>().copy);
BEAST_EXPECT(Q<1>::count() == 0);
BEAST_EXPECT(Q<2>::count() == 2);
@ -340,6 +395,48 @@ public:
BEAST_EXPECT(Q<1>::count() == 0);
BEAST_EXPECT(Q<2>::count() == 0);
BEAST_EXPECT(Q<3>::count() == 0);
// basic guarantee
{
// move
variant<Q<1>> v1;
v1.emplace<1>();
BEAST_EXPECT(Q<1>::count() == 1);
variant<Q<1>> v2;
v2.emplace<1>(-1);
BEAST_EXPECT(Q<1>::count() == 2);
try
{
v1 = std::move(v2);
fail();
}
catch(std::exception const&)
{
BEAST_EXPECT(v1.index() == 0);
BEAST_EXPECT(Q<1>::count() == 1);
}
}
BEAST_EXPECT(Q<1>::count() == 0);
{
// copy
variant<Q<1>> v1;
v1.emplace<1>();
BEAST_EXPECT(Q<1>::count() == 1);
variant<Q<1>> v2;
v2.emplace<1>(-1);
BEAST_EXPECT(Q<1>::count() == 2);
try
{
v1 = v2;
fail();
}
catch(std::exception const&)
{
BEAST_EXPECT(v1.index() == 0);
BEAST_EXPECT(Q<1>::count() == 1);
}
}
BEAST_EXPECT(Q<1>::count() == 0);
}
void