Commit bd1c3af4 authored by Kirk Shoop's avatar Kirk Shoop Committed by Facebook Github Bot

swap does not compile for Poly

Summary:
The issue is that std::swap must have the same type for both parameters but the member .swap() for PolyVal takes Poly and then uses std::swap(*this, that).

the fix uses static_cast to change the Poly to a PolyVal for std::swap

Reviewed By: ericniebler

Differential Revision: D7730948

fbshipit-source-id: 8dd93fc3c86b87938a7c0c12ccb3b5209a593730
parent 7aff1428
......@@ -99,12 +99,14 @@ inline void PolyVal<I>::swap(Poly<I>& that) noexcept {
break;
case State::eOnHeap:
if (State::eOnHeap == that.vptr_->state_) {
std::swap(_data_()->pobj_, _data_()->pobj_);
std::swap(_data_()->pobj_, that._data_()->pobj_);
std::swap(vptr_, that.vptr_);
return;
}
FOLLY_FALLTHROUGH;
case State::eInSitu:
std::swap(*this, that); // NOTE: qualified, not ADL
std::swap(
*this, static_cast<PolyVal<I>&>(that)); // NOTE: qualified, not ADL
}
}
......
......@@ -29,40 +29,45 @@ using namespace folly;
using namespace folly::poly;
namespace {
struct Big {
template <class T>
struct Big_t {
private:
std::array<char, sizeof(Poly<ISemiRegular>) + 1> data_;
int i_;
T t_;
public:
Big() : data_{}, i_(0) {
Big_t() : data_{}, t_() {
++s_count;
}
explicit Big(int i) : data_{}, i_(i) {
explicit Big_t(T t) : data_{}, t_(t) {
++s_count;
}
Big(Big const& that) : data_(that.data_), i_(that.i_) {
Big_t(Big_t const& that) : data_(that.data_), t_(that.t_) {
++s_count;
}
~Big() {
~Big_t() {
--s_count;
}
Big& operator=(Big const&) = default;
int value() const {
return i_;
Big_t& operator=(Big_t const&) = default;
T value() const {
return t_;
}
friend bool operator==(Big const& a, Big const& b) {
friend bool operator==(Big_t const& a, Big_t const& b) {
return a.value() == b.value();
}
friend bool operator!=(Big const& a, Big const& b) {
friend bool operator!=(Big_t const& a, Big_t const& b) {
return !(a == b);
}
friend bool operator<(Big const& a, Big const& b) {
friend bool operator<(Big_t const& a, Big_t const& b) {
return a.value() < b.value();
}
static std::ptrdiff_t s_count;
};
std::ptrdiff_t Big::s_count = 0;
template <class T>
std::ptrdiff_t Big_t<T>::s_count = 0;
using Big = Big_t<int>;
using BigDouble = Big_t<double>;
} // namespace
TEST(Poly, SemiRegular) {
......@@ -93,6 +98,141 @@ TEST(Poly, SemiRegular) {
EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
}
EXPECT_EQ(0, Big::s_count);
// four swap cases
//
{
// A small object, storable in-situ:
Poly<ISemiRegular> p = 42;
EXPECT_EQ(typeid(int), poly_type(p));
EXPECT_EQ(42, poly_cast<int>(p));
EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
// A small object, storable in-situ:
Poly<ISemiRegular> p2 = 4.2;
EXPECT_EQ(typeid(double), poly_type(p2));
EXPECT_EQ(4.2, poly_cast<double>(p2));
EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
std::swap(p, p2);
EXPECT_EQ(typeid(double), poly_type(p));
EXPECT_EQ(4.2, poly_cast<double>(p));
EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
EXPECT_EQ(typeid(int), poly_type(p2));
EXPECT_EQ(42, poly_cast<int>(p2));
EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
using std::swap;
swap(p, p2);
EXPECT_EQ(typeid(int), poly_type(p));
EXPECT_EQ(42, poly_cast<int>(p));
EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
EXPECT_EQ(typeid(double), poly_type(p2));
EXPECT_EQ(4.2, poly_cast<double>(p2));
EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
}
EXPECT_EQ(0, Big::s_count);
EXPECT_EQ(0, BigDouble::s_count);
{
// A big object, stored on the heap:
Poly<ISemiRegular> p = Big(42);
EXPECT_EQ(1, Big::s_count);
EXPECT_EQ(typeid(Big), poly_type(p));
EXPECT_EQ(42, poly_cast<Big>(p).value());
EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
// A big object, stored on the heap:
Poly<ISemiRegular> p2 = BigDouble(4.2);
EXPECT_EQ(1, BigDouble::s_count);
EXPECT_EQ(typeid(BigDouble), poly_type(p2));
EXPECT_EQ(4.2, poly_cast<BigDouble>(p2).value());
EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
std::swap(p, p2);
EXPECT_EQ(1, Big::s_count);
EXPECT_EQ(1, BigDouble::s_count);
EXPECT_EQ(typeid(BigDouble), poly_type(p));
EXPECT_EQ(4.2, poly_cast<BigDouble>(p).value());
EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
EXPECT_EQ(typeid(Big), poly_type(p2));
EXPECT_EQ(42, poly_cast<Big>(p2).value());
EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
using std::swap;
swap(p, p2);
EXPECT_EQ(1, Big::s_count);
EXPECT_EQ(1, BigDouble::s_count);
EXPECT_EQ(typeid(Big), poly_type(p));
EXPECT_EQ(42, poly_cast<Big>(p).value());
EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
EXPECT_EQ(typeid(BigDouble), poly_type(p2));
EXPECT_EQ(4.2, poly_cast<BigDouble>(p2).value());
EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
}
EXPECT_EQ(0, BigDouble::s_count);
EXPECT_EQ(0, Big::s_count);
EXPECT_EQ(0, Big::s_count);
{
// A big object, stored on the heap:
Poly<ISemiRegular> p = Big(42);
EXPECT_EQ(1, Big::s_count);
EXPECT_EQ(typeid(Big), poly_type(p));
EXPECT_EQ(42, poly_cast<Big>(p).value());
EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
// A small object, storable in-situ:
Poly<ISemiRegular> p2 = 4.2;
EXPECT_EQ(typeid(double), poly_type(p2));
EXPECT_EQ(4.2, poly_cast<double>(p2));
EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
std::swap(p, p2);
EXPECT_EQ(1, Big::s_count);
EXPECT_EQ(typeid(double), poly_type(p));
EXPECT_EQ(4.2, poly_cast<double>(p));
EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
EXPECT_EQ(typeid(Big), poly_type(p2));
EXPECT_EQ(42, poly_cast<Big>(p2).value());
EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
using std::swap;
swap(p, p2);
EXPECT_EQ(1, Big::s_count);
EXPECT_EQ(typeid(Big), poly_type(p));
EXPECT_EQ(42, poly_cast<Big>(p).value());
EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
EXPECT_EQ(typeid(double), poly_type(p2));
EXPECT_EQ(4.2, poly_cast<double>(p2));
EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
}
EXPECT_EQ(0, Big::s_count);
EXPECT_EQ(0, BigDouble::s_count);
{
// A small object, storable in-situ:
Poly<ISemiRegular> p = 42;
EXPECT_EQ(typeid(int), poly_type(p));
EXPECT_EQ(42, poly_cast<int>(p));
EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
// A big object, stored on the heap:
Poly<ISemiRegular> p2 = BigDouble(4.2);
EXPECT_EQ(1, BigDouble::s_count);
EXPECT_EQ(typeid(BigDouble), poly_type(p2));
EXPECT_EQ(4.2, poly_cast<BigDouble>(p2).value());
EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
std::swap(p, p2);
EXPECT_EQ(1, BigDouble::s_count);
EXPECT_EQ(typeid(BigDouble), poly_type(p));
EXPECT_EQ(4.2, poly_cast<BigDouble>(p).value());
EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
EXPECT_EQ(typeid(int), poly_type(p2));
EXPECT_EQ(42, poly_cast<int>(p2));
EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
using std::swap;
swap(p, p2);
EXPECT_EQ(1, BigDouble::s_count);
EXPECT_EQ(typeid(int), poly_type(p));
EXPECT_EQ(42, poly_cast<int>(p));
EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
EXPECT_EQ(typeid(BigDouble), poly_type(p2));
EXPECT_EQ(4.2, poly_cast<BigDouble>(p2).value());
EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
}
EXPECT_EQ(0, BigDouble::s_count);
}
TEST(Poly, EqualityComparable) {
......@@ -188,6 +328,22 @@ TEST(Poly, SemiRegularReference) {
EXPECT_EQ(42, poly_cast<int>(p));
EXPECT_EQ(&i, &poly_cast<int>(p));
EXPECT_THROW(poly_cast<short>(p), BadPolyCast);
Poly<ISemiRegular&> p2 = p;
EXPECT_EQ(typeid(int), poly_type(p2));
EXPECT_EQ(42, poly_cast<int>(p2));
EXPECT_EQ(&i, &poly_cast<int>(p2));
EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
std::swap(p, p2);
EXPECT_EQ(typeid(int), poly_type(p2));
EXPECT_EQ(42, poly_cast<int>(p2));
EXPECT_EQ(&i, &poly_cast<int>(p2));
EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
using std::swap;
swap(p, p2);
EXPECT_EQ(typeid(int), poly_type(p2));
EXPECT_EQ(42, poly_cast<int>(p2));
EXPECT_EQ(&i, &poly_cast<int>(p2));
EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
// Can't default-initialize reference-like Poly's:
static_assert(!std::is_default_constructible<Poly<ISemiRegular&>>::value, "");
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment