Commit c5f5c10e authored by yutak's avatar yutak Committed by Commit bot

WTF: Implement move of Deques.

As always, move constructor and move assignment operator are implemented
in terms of swap().

Some existing tests are adjusted so CountCopy can count copies on
assignments, too.

BUG=567139, 582349

Review URL: https://codereview.chromium.org/1846473002

Cr-Commit-Position: refs/heads/master@{#383932}
parent 56aae832
...@@ -52,13 +52,15 @@ public: ...@@ -52,13 +52,15 @@ public:
typedef std::reverse_iterator<const_iterator> const_reverse_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
Deque(); Deque();
Deque(const Deque<T, inlineCapacity, Allocator>&); Deque(const Deque&);
Deque& operator=(const Deque&); Deque& operator=(const Deque&);
Deque(Deque&&);
Deque& operator=(Deque&&);
void finalize(); void finalize();
void finalizeGarbageCollectedObject() { finalize(); } void finalizeGarbageCollectedObject() { finalize(); }
void swap(Deque<T, inlineCapacity, Allocator>&); void swap(Deque&);
size_t size() const { return m_start <= m_end ? m_end - m_start : m_end + m_buffer.capacity() - m_start; } size_t size() const { return m_start <= m_end ? m_end - m_start : m_end + m_buffer.capacity() - m_start; }
bool isEmpty() const { return m_start == m_end; } bool isEmpty() const { return m_start == m_end; }
...@@ -110,6 +112,12 @@ public: ...@@ -110,6 +112,12 @@ public:
template <typename VisitorDispatcher> void trace(VisitorDispatcher); template <typename VisitorDispatcher> void trace(VisitorDispatcher);
static_assert(!std::is_polymorphic<T>::value || !VectorTraits<T>::canInitializeWithMemset, "Cannot initialize with memset if there is a vtable");
#if ENABLE(OILPAN)
static_assert(Allocator::isGarbageCollected || !AllowsOnlyPlacementNew<T>::value || !NeedsTracing<T>::value, "Cannot put DISALLOW_NEW_EXCEPT_PLACEMENT_NEW objects that have trace methods into an off-heap Deque");
#endif
static_assert(Allocator::isGarbageCollected || !IsPointerToGarbageCollectedType<T>::value, "Cannot put raw pointers to garbage-collected classes into a Deque. Use HeapDeque<Member<T>> instead.");
private: private:
friend class DequeIteratorBase<T, inlineCapacity, Allocator>; friend class DequeIteratorBase<T, inlineCapacity, Allocator>;
...@@ -237,15 +245,10 @@ inline Deque<T, inlineCapacity, Allocator>::Deque() ...@@ -237,15 +245,10 @@ inline Deque<T, inlineCapacity, Allocator>::Deque()
: m_start(0) : m_start(0)
, m_end(0) , m_end(0)
{ {
static_assert(!std::is_polymorphic<T>::value || !VectorTraits<T>::canInitializeWithMemset, "Cannot initialize with memset if there is a vtable");
#if ENABLE(OILPAN)
static_assert(Allocator::isGarbageCollected || !AllowsOnlyPlacementNew<T>::value || !NeedsTracing<T>::value, "Cannot put DISALLOW_NEW_EXCEPT_PLACEMENT_NEW objects that have trace methods into an off-heap Deque");
#endif
static_assert(Allocator::isGarbageCollected || !IsPointerToGarbageCollectedType<T>::value, "Cannot put raw pointers to garbage-collected classes into a Deque. Use HeapDeque<Member<T>> instead.");
} }
template <typename T, size_t inlineCapacity, typename Allocator> template <typename T, size_t inlineCapacity, typename Allocator>
inline Deque<T, inlineCapacity, Allocator>::Deque(const Deque<T, inlineCapacity, Allocator>& other) inline Deque<T, inlineCapacity, Allocator>::Deque(const Deque& other)
: m_buffer(other.m_buffer.capacity()) : m_buffer(other.m_buffer.capacity())
, m_start(other.m_start) , m_start(other.m_start)
, m_end(other.m_end) , m_end(other.m_end)
...@@ -267,6 +270,21 @@ inline Deque<T, inlineCapacity, Allocator>& Deque<T, inlineCapacity, Allocator>: ...@@ -267,6 +270,21 @@ inline Deque<T, inlineCapacity, Allocator>& Deque<T, inlineCapacity, Allocator>:
return *this; return *this;
} }
template <typename T, size_t inlineCapacity, typename Allocator>
inline Deque<T, inlineCapacity, Allocator>::Deque(Deque&& other)
: m_start(0)
, m_end(0)
{
swap(other);
}
template <typename T, size_t inlineCapacity, typename Allocator>
inline Deque<T, inlineCapacity, Allocator>& Deque<T, inlineCapacity, Allocator>::operator=(Deque&& other)
{
swap(other);
return *this;
}
template <typename T, size_t inlineCapacity, typename Allocator> template <typename T, size_t inlineCapacity, typename Allocator>
inline void Deque<T, inlineCapacity, Allocator>::destroyAll() inline void Deque<T, inlineCapacity, Allocator>::destroyAll()
{ {
......
...@@ -566,6 +566,46 @@ TEST(DequeTest, UniquePtr) ...@@ -566,6 +566,46 @@ TEST(DequeTest, UniquePtr)
deque.clear(); deque.clear();
} }
class CountCopy final {
public:
explicit CountCopy(int* counter = nullptr) : m_counter(counter) { }
CountCopy(const CountCopy& other)
: m_counter(other.m_counter)
{
if (m_counter)
++*m_counter;
}
CountCopy& operator=(const CountCopy& other)
{
m_counter = other.m_counter;
if (m_counter)
++*m_counter;
return *this;
}
private:
int* m_counter;
};
TEST(DequeTest, MoveShouldNotMakeCopy)
{
// Because data in inline buffer may be swapped or moved individually, we force the creation of out-of-line buffer
// so we can make sure there's no element-wise copy/move.
Deque<CountCopy, 1> deque;
int counter = 0;
deque.append(CountCopy(&counter));
deque.append(CountCopy(&counter));
Deque<CountCopy, 1> other(deque);
counter = 0;
deque = std::move(other); // Move assignment.
EXPECT_EQ(0, counter);
counter = 0;
Deque<CountCopy, 1> yetAnother(std::move(deque)); // Move construction.
EXPECT_EQ(0, counter);
}
} // anonymous namespace } // anonymous namespace
} // namespace WTF } // namespace WTF
...@@ -478,11 +478,19 @@ class CountCopy final { ...@@ -478,11 +478,19 @@ class CountCopy final {
public: public:
CountCopy() : m_counter(nullptr) { } CountCopy() : m_counter(nullptr) { }
explicit CountCopy(int& counter) : m_counter(&counter) { } explicit CountCopy(int& counter) : m_counter(&counter) { }
CountCopy(const CountCopy& other) : m_counter(other.m_counter) CountCopy(const CountCopy& other)
: m_counter(other.m_counter)
{ {
if (m_counter) if (m_counter)
++*m_counter; ++*m_counter;
} }
CountCopy& operator=(const CountCopy& other)
{
m_counter = other.m_counter;
if (m_counter)
++*m_counter;
return *this;
}
private: private:
int* m_counter; int* m_counter;
......
...@@ -208,11 +208,19 @@ public: ...@@ -208,11 +208,19 @@ public:
static int* const kDeletedValue; static int* const kDeletedValue;
explicit CountCopy(int* counter = nullptr) : m_counter(counter) { } explicit CountCopy(int* counter = nullptr) : m_counter(counter) { }
CountCopy(const CountCopy& other) : m_counter(other.m_counter) CountCopy(const CountCopy& other)
: m_counter(other.m_counter)
{ {
if (m_counter && m_counter != kDeletedValue) if (m_counter && m_counter != kDeletedValue)
++*m_counter; ++*m_counter;
} }
CountCopy& operator=(const CountCopy& other)
{
m_counter = other.m_counter;
if (m_counter && m_counter != kDeletedValue)
++*m_counter;
return *this;
}
const int* counter() const { return m_counter; } const int* counter() const { return m_counter; }
private: private:
......
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