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 * Update appveyor for Boost branch
* Rename to BEAST_EXPECT * Rename to BEAST_EXPECT
* variant fixes and tests
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -82,6 +82,22 @@ max_sizeof()
max_sizeof<U0>() : max_sizeof<U1, Us...>(); 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> template<unsigned N, class T, class... Tn>
struct repeat_tuple_impl struct repeat_tuple_impl
{ {

View File

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

View File

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

View File

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