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 { ...@@ -99,12 +99,14 @@ inline void PolyVal<I>::swap(Poly<I>& that) noexcept {
break; break;
case State::eOnHeap: case State::eOnHeap:
if (State::eOnHeap == that.vptr_->state_) { if (State::eOnHeap == that.vptr_->state_) {
std::swap(_data_()->pobj_, _data_()->pobj_); std::swap(_data_()->pobj_, that._data_()->pobj_);
std::swap(vptr_, that.vptr_); std::swap(vptr_, that.vptr_);
return;
} }
FOLLY_FALLTHROUGH; FOLLY_FALLTHROUGH;
case State::eInSitu: 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; ...@@ -29,40 +29,45 @@ using namespace folly;
using namespace folly::poly; using namespace folly::poly;
namespace { namespace {
struct Big { template <class T>
struct Big_t {
private: private:
std::array<char, sizeof(Poly<ISemiRegular>) + 1> data_; std::array<char, sizeof(Poly<ISemiRegular>) + 1> data_;
int i_; T t_;
public: public:
Big() : data_{}, i_(0) { Big_t() : data_{}, t_() {
++s_count; ++s_count;
} }
explicit Big(int i) : data_{}, i_(i) { explicit Big_t(T t) : data_{}, t_(t) {
++s_count; ++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; ++s_count;
} }
~Big() { ~Big_t() {
--s_count; --s_count;
} }
Big& operator=(Big const&) = default; Big_t& operator=(Big_t const&) = default;
int value() const { T value() const {
return i_; 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(); 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); 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(); return a.value() < b.value();
} }
static std::ptrdiff_t s_count; 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 } // namespace
TEST(Poly, SemiRegular) { TEST(Poly, SemiRegular) {
...@@ -93,6 +98,141 @@ TEST(Poly, SemiRegular) { ...@@ -93,6 +98,141 @@ TEST(Poly, SemiRegular) {
EXPECT_THROW(poly_cast<short>(p2), BadPolyCast); EXPECT_THROW(poly_cast<short>(p2), BadPolyCast);
} }
EXPECT_EQ(0, Big::s_count); 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) { TEST(Poly, EqualityComparable) {
...@@ -188,6 +328,22 @@ TEST(Poly, SemiRegularReference) { ...@@ -188,6 +328,22 @@ TEST(Poly, SemiRegularReference) {
EXPECT_EQ(42, poly_cast<int>(p)); EXPECT_EQ(42, poly_cast<int>(p));
EXPECT_EQ(&i, &poly_cast<int>(p)); EXPECT_EQ(&i, &poly_cast<int>(p));
EXPECT_THROW(poly_cast<short>(p), BadPolyCast); 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: // Can't default-initialize reference-like Poly's:
static_assert(!std::is_default_constructible<Poly<ISemiRegular&>>::value, ""); 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