|  | // Copyright 2017 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/containers/circular_deque.h" | 
|  |  | 
|  | #include "base/test/copy_only_int.h" | 
|  | #include "base/test/move_only_int.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | using base::internal::VectorBuffer; | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | circular_deque<int> MakeSequence(size_t max) { | 
|  | circular_deque<int> ret; | 
|  | for (size_t i = 0; i < max; i++) | 
|  | ret.push_back(i); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | // Cycles through the queue, popping items from the back and pushing items | 
|  | // at the front to validate behavior across different configurations of the | 
|  | // queue in relation to the underlying buffer. The tester closure is run for | 
|  | // each cycle. | 
|  | template <class QueueT, class Tester> | 
|  | void CycleTest(circular_deque<QueueT>& queue, const Tester& tester) { | 
|  | size_t steps = queue.size() * 2; | 
|  | for (size_t i = 0; i < steps; i++) { | 
|  | tester(queue, i); | 
|  | queue.pop_back(); | 
|  | queue.push_front(QueueT()); | 
|  | } | 
|  | } | 
|  |  | 
|  | class DestructorCounter { | 
|  | public: | 
|  | DestructorCounter(int* counter) : counter_(counter) {} | 
|  | ~DestructorCounter() { ++(*counter_); } | 
|  |  | 
|  | private: | 
|  | int* counter_; | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | TEST(CircularDeque, FillConstructor) { | 
|  | constexpr size_t num_elts = 9; | 
|  |  | 
|  | std::vector<int> foo(15); | 
|  | EXPECT_EQ(15u, foo.size()); | 
|  |  | 
|  | // Fill with default constructor. | 
|  | { | 
|  | circular_deque<int> buf(num_elts); | 
|  |  | 
|  | EXPECT_EQ(num_elts, buf.size()); | 
|  | EXPECT_EQ(num_elts, static_cast<size_t>(buf.end() - buf.begin())); | 
|  |  | 
|  | for (size_t i = 0; i < num_elts; i++) | 
|  | EXPECT_EQ(0, buf[i]); | 
|  | } | 
|  |  | 
|  | // Fill with explicit value. | 
|  | { | 
|  | int value = 199; | 
|  | circular_deque<int> buf(num_elts, value); | 
|  |  | 
|  | EXPECT_EQ(num_elts, buf.size()); | 
|  | EXPECT_EQ(num_elts, static_cast<size_t>(buf.end() - buf.begin())); | 
|  |  | 
|  | for (size_t i = 0; i < num_elts; i++) | 
|  | EXPECT_EQ(value, buf[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, CopyAndRangeConstructor) { | 
|  | int values[] = {1, 2, 3, 4, 5, 6}; | 
|  | circular_deque<CopyOnlyInt> first(std::begin(values), std::end(values)); | 
|  |  | 
|  | circular_deque<CopyOnlyInt> second(first); | 
|  | EXPECT_EQ(6u, second.size()); | 
|  | for (int i = 0; i < 6; i++) | 
|  | EXPECT_EQ(i + 1, second[i].data()); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, MoveConstructor) { | 
|  | int values[] = {1, 2, 3, 4, 5, 6}; | 
|  | circular_deque<MoveOnlyInt> first(std::begin(values), std::end(values)); | 
|  |  | 
|  | circular_deque<MoveOnlyInt> second(std::move(first)); | 
|  | EXPECT_TRUE(first.empty()); | 
|  | EXPECT_EQ(6u, second.size()); | 
|  | for (int i = 0; i < 6; i++) | 
|  | EXPECT_EQ(i + 1, second[i].data()); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, InitializerListConstructor) { | 
|  | circular_deque<int> empty({}); | 
|  | ASSERT_TRUE(empty.empty()); | 
|  |  | 
|  | circular_deque<int> first({1, 2, 3, 4, 5, 6}); | 
|  | EXPECT_EQ(6u, first.size()); | 
|  | for (int i = 0; i < 6; i++) | 
|  | EXPECT_EQ(i + 1, first[i]); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, Destructor) { | 
|  | int destruct_count = 0; | 
|  |  | 
|  | // Contiguous buffer. | 
|  | { | 
|  | circular_deque<DestructorCounter> q; | 
|  | q.resize(5, DestructorCounter(&destruct_count)); | 
|  |  | 
|  | EXPECT_EQ(1, destruct_count);  // The temporary in the call to resize(). | 
|  | destruct_count = 0; | 
|  | } | 
|  | EXPECT_EQ(5, destruct_count);  // One call for each. | 
|  |  | 
|  | // Force a wraparound buffer. | 
|  | { | 
|  | circular_deque<DestructorCounter> q; | 
|  | q.reserve(7); | 
|  | q.resize(5, DestructorCounter(&destruct_count)); | 
|  |  | 
|  | // Cycle throught some elements in our buffer to force a wraparound. | 
|  | destruct_count = 0; | 
|  | for (int i = 0; i < 4; i++) { | 
|  | q.emplace_back(&destruct_count); | 
|  | q.pop_front(); | 
|  | } | 
|  | EXPECT_EQ(4, destruct_count);  // One for each cycle. | 
|  | destruct_count = 0; | 
|  | } | 
|  | EXPECT_EQ(5, destruct_count);  // One call for each. | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, EqualsCopy) { | 
|  | circular_deque<int> first = {1, 2, 3, 4, 5, 6}; | 
|  | circular_deque<int> copy; | 
|  | EXPECT_TRUE(copy.empty()); | 
|  | copy = first; | 
|  | EXPECT_EQ(6u, copy.size()); | 
|  | for (int i = 0; i < 6; i++) { | 
|  | EXPECT_EQ(i + 1, first[i]); | 
|  | EXPECT_EQ(i + 1, copy[i]); | 
|  | EXPECT_NE(&first[i], ©[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, EqualsMove) { | 
|  | circular_deque<int> first = {1, 2, 3, 4, 5, 6}; | 
|  | circular_deque<int> move; | 
|  | EXPECT_TRUE(move.empty()); | 
|  | move = std::move(first); | 
|  | EXPECT_TRUE(first.empty()); | 
|  | EXPECT_EQ(6u, move.size()); | 
|  | for (int i = 0; i < 6; i++) | 
|  | EXPECT_EQ(i + 1, move[i]); | 
|  | } | 
|  |  | 
|  | // Tests that self-assignment is a no-op. | 
|  | TEST(CircularDeque, EqualsSelf) { | 
|  | circular_deque<int> q = {1, 2, 3, 4, 5, 6}; | 
|  | q = *&q;  // The *& defeats Clang's -Wself-assign warning. | 
|  | EXPECT_EQ(6u, q.size()); | 
|  | for (int i = 0; i < 6; i++) | 
|  | EXPECT_EQ(i + 1, q[i]); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, EqualsInitializerList) { | 
|  | circular_deque<int> q; | 
|  | EXPECT_TRUE(q.empty()); | 
|  | q = {1, 2, 3, 4, 5, 6}; | 
|  | EXPECT_EQ(6u, q.size()); | 
|  | for (int i = 0; i < 6; i++) | 
|  | EXPECT_EQ(i + 1, q[i]); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, AssignCountValue) { | 
|  | circular_deque<int> empty; | 
|  | empty.assign(0, 52); | 
|  | EXPECT_EQ(0u, empty.size()); | 
|  |  | 
|  | circular_deque<int> full; | 
|  | size_t count = 13; | 
|  | int value = 12345; | 
|  | full.assign(count, value); | 
|  | EXPECT_EQ(count, full.size()); | 
|  |  | 
|  | for (size_t i = 0; i < count; i++) | 
|  | EXPECT_EQ(value, full[i]); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, AssignIterator) { | 
|  | int range[8] = {11, 12, 13, 14, 15, 16, 17, 18}; | 
|  |  | 
|  | circular_deque<int> empty; | 
|  | empty.assign(std::begin(range), std::begin(range)); | 
|  | EXPECT_TRUE(empty.empty()); | 
|  |  | 
|  | circular_deque<int> full; | 
|  | full.assign(std::begin(range), std::end(range)); | 
|  | EXPECT_EQ(8u, full.size()); | 
|  | for (size_t i = 0; i < 8; i++) | 
|  | EXPECT_EQ(range[i], full[i]); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, AssignInitializerList) { | 
|  | circular_deque<int> empty; | 
|  | empty.assign({}); | 
|  | EXPECT_TRUE(empty.empty()); | 
|  |  | 
|  | circular_deque<int> full; | 
|  | full.assign({11, 12, 13, 14, 15, 16, 17, 18}); | 
|  | EXPECT_EQ(8u, full.size()); | 
|  | for (int i = 0; i < 8; i++) | 
|  | EXPECT_EQ(11 + i, full[i]); | 
|  | } | 
|  |  | 
|  | // Tests [] and .at(). | 
|  | TEST(CircularDeque, At) { | 
|  | circular_deque<int> q = MakeSequence(10); | 
|  | CycleTest(q, [](const circular_deque<int>& q, size_t cycle) { | 
|  | size_t expected_size = 10; | 
|  | EXPECT_EQ(expected_size, q.size()); | 
|  |  | 
|  | // A sequence of 0's. | 
|  | size_t index = 0; | 
|  | size_t num_zeros = std::min(expected_size, cycle); | 
|  | for (size_t i = 0; i < num_zeros; i++, index++) { | 
|  | EXPECT_EQ(0, q[index]); | 
|  | EXPECT_EQ(0, q.at(index)); | 
|  | } | 
|  |  | 
|  | // Followed by a sequence of increasing ints. | 
|  | size_t num_ints = expected_size - num_zeros; | 
|  | for (int i = 0; i < static_cast<int>(num_ints); i++, index++) { | 
|  | EXPECT_EQ(i, q[index]); | 
|  | EXPECT_EQ(i, q.at(index)); | 
|  | } | 
|  | }); | 
|  | } | 
|  |  | 
|  | // This also tests the copy constructor with lots of different types of | 
|  | // input configurations. | 
|  | TEST(CircularDeque, FrontBackPushPop) { | 
|  | circular_deque<int> q = MakeSequence(10); | 
|  |  | 
|  | int expected_front = 0; | 
|  | int expected_back = 9; | 
|  |  | 
|  | // Go in one direction. | 
|  | for (int i = 0; i < 100; i++) { | 
|  | const circular_deque<int> const_q(q); | 
|  |  | 
|  | EXPECT_EQ(expected_front, q.front()); | 
|  | EXPECT_EQ(expected_back, q.back()); | 
|  | EXPECT_EQ(expected_front, const_q.front()); | 
|  | EXPECT_EQ(expected_back, const_q.back()); | 
|  |  | 
|  | expected_front++; | 
|  | expected_back++; | 
|  |  | 
|  | q.pop_front(); | 
|  | q.push_back(expected_back); | 
|  | } | 
|  |  | 
|  | // Go back in reverse. | 
|  | for (int i = 0; i < 100; i++) { | 
|  | const circular_deque<int> const_q(q); | 
|  |  | 
|  | EXPECT_EQ(expected_front, q.front()); | 
|  | EXPECT_EQ(expected_back, q.back()); | 
|  | EXPECT_EQ(expected_front, const_q.front()); | 
|  | EXPECT_EQ(expected_back, const_q.back()); | 
|  |  | 
|  | expected_front--; | 
|  | expected_back--; | 
|  |  | 
|  | q.pop_back(); | 
|  | q.push_front(expected_front); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, ReallocateWithSplitBuffer) { | 
|  | // Tests reallocating a deque with an internal buffer that looks like this: | 
|  | //   4   5   x   x   0   1   2   3 | 
|  | //       end-^       ^-begin | 
|  | circular_deque<int> q; | 
|  | q.reserve(7);  // Internal buffer is always 1 larger than requested. | 
|  | q.push_back(-1); | 
|  | q.push_back(-1); | 
|  | q.push_back(-1); | 
|  | q.push_back(-1); | 
|  | q.push_back(0); | 
|  | q.pop_front(); | 
|  | q.pop_front(); | 
|  | q.pop_front(); | 
|  | q.pop_front(); | 
|  | q.push_back(1); | 
|  | q.push_back(2); | 
|  | q.push_back(3); | 
|  | q.push_back(4); | 
|  | q.push_back(5); | 
|  |  | 
|  | q.shrink_to_fit(); | 
|  | EXPECT_EQ(6u, q.size()); | 
|  |  | 
|  | EXPECT_EQ(0, q[0]); | 
|  | EXPECT_EQ(1, q[1]); | 
|  | EXPECT_EQ(2, q[2]); | 
|  | EXPECT_EQ(3, q[3]); | 
|  | EXPECT_EQ(4, q[4]); | 
|  | EXPECT_EQ(5, q[5]); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, Swap) { | 
|  | circular_deque<int> a = MakeSequence(10); | 
|  | circular_deque<int> b = MakeSequence(100); | 
|  |  | 
|  | a.swap(b); | 
|  | EXPECT_EQ(100u, a.size()); | 
|  | for (int i = 0; i < 100; i++) | 
|  | EXPECT_EQ(i, a[i]); | 
|  |  | 
|  | EXPECT_EQ(10u, b.size()); | 
|  | for (int i = 0; i < 10; i++) | 
|  | EXPECT_EQ(i, b[i]); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, Iteration) { | 
|  | circular_deque<int> q = MakeSequence(10); | 
|  |  | 
|  | int expected_front = 0; | 
|  | int expected_back = 9; | 
|  |  | 
|  | // This loop causes various combinations of begin and end to be tested. | 
|  | for (int i = 0; i < 30; i++) { | 
|  | // Range-based for loop going forward. | 
|  | int current_expected = expected_front; | 
|  | for (int cur : q) { | 
|  | EXPECT_EQ(current_expected, cur); | 
|  | current_expected++; | 
|  | } | 
|  |  | 
|  | // Manually test reverse iterators. | 
|  | current_expected = expected_back; | 
|  | for (auto cur = q.crbegin(); cur < q.crend(); cur++) { | 
|  | EXPECT_EQ(current_expected, *cur); | 
|  | current_expected--; | 
|  | } | 
|  |  | 
|  | expected_front++; | 
|  | expected_back++; | 
|  |  | 
|  | q.pop_front(); | 
|  | q.push_back(expected_back); | 
|  | } | 
|  |  | 
|  | // Go back in reverse. | 
|  | for (int i = 0; i < 100; i++) { | 
|  | const circular_deque<int> const_q(q); | 
|  |  | 
|  | EXPECT_EQ(expected_front, q.front()); | 
|  | EXPECT_EQ(expected_back, q.back()); | 
|  | EXPECT_EQ(expected_front, const_q.front()); | 
|  | EXPECT_EQ(expected_back, const_q.back()); | 
|  |  | 
|  | expected_front--; | 
|  | expected_back--; | 
|  |  | 
|  | q.pop_back(); | 
|  | q.push_front(expected_front); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, IteratorComparisons) { | 
|  | circular_deque<int> q = MakeSequence(10); | 
|  |  | 
|  | // This loop causes various combinations of begin and end to be tested. | 
|  | for (int i = 0; i < 30; i++) { | 
|  | EXPECT_LT(q.begin(), q.end()); | 
|  | EXPECT_LE(q.begin(), q.end()); | 
|  | EXPECT_LE(q.begin(), q.begin()); | 
|  |  | 
|  | EXPECT_GT(q.end(), q.begin()); | 
|  | EXPECT_GE(q.end(), q.begin()); | 
|  | EXPECT_GE(q.end(), q.end()); | 
|  |  | 
|  | EXPECT_EQ(q.begin(), q.begin()); | 
|  | EXPECT_NE(q.begin(), q.end()); | 
|  |  | 
|  | q.push_front(10); | 
|  | q.pop_back(); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, IteratorIncDec) { | 
|  | circular_deque<int> q; | 
|  |  | 
|  | // No-op offset computations with no capacity. | 
|  | EXPECT_EQ(q.end(), q.end() + 0); | 
|  | EXPECT_EQ(q.end(), q.end() - 0); | 
|  |  | 
|  | q = MakeSequence(10); | 
|  |  | 
|  | // Mutable preincrement, predecrement. | 
|  | { | 
|  | circular_deque<int>::iterator it = q.begin(); | 
|  | circular_deque<int>::iterator op_result = ++it; | 
|  | EXPECT_EQ(1, *op_result); | 
|  | EXPECT_EQ(1, *it); | 
|  |  | 
|  | op_result = --it; | 
|  | EXPECT_EQ(0, *op_result); | 
|  | EXPECT_EQ(0, *it); | 
|  | } | 
|  |  | 
|  | // Const preincrement, predecrement. | 
|  | { | 
|  | circular_deque<int>::const_iterator it = q.begin(); | 
|  | circular_deque<int>::const_iterator op_result = ++it; | 
|  | EXPECT_EQ(1, *op_result); | 
|  | EXPECT_EQ(1, *it); | 
|  |  | 
|  | op_result = --it; | 
|  | EXPECT_EQ(0, *op_result); | 
|  | EXPECT_EQ(0, *it); | 
|  | } | 
|  |  | 
|  | // Mutable postincrement, postdecrement. | 
|  | { | 
|  | circular_deque<int>::iterator it = q.begin(); | 
|  | circular_deque<int>::iterator op_result = it++; | 
|  | EXPECT_EQ(0, *op_result); | 
|  | EXPECT_EQ(1, *it); | 
|  |  | 
|  | op_result = it--; | 
|  | EXPECT_EQ(1, *op_result); | 
|  | EXPECT_EQ(0, *it); | 
|  | } | 
|  |  | 
|  | // Const postincrement, postdecrement. | 
|  | { | 
|  | circular_deque<int>::const_iterator it = q.begin(); | 
|  | circular_deque<int>::const_iterator op_result = it++; | 
|  | EXPECT_EQ(0, *op_result); | 
|  | EXPECT_EQ(1, *it); | 
|  |  | 
|  | op_result = it--; | 
|  | EXPECT_EQ(1, *op_result); | 
|  | EXPECT_EQ(0, *it); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, IteratorIntegerOps) { | 
|  | circular_deque<int> q = MakeSequence(10); | 
|  |  | 
|  | int expected_front = 0; | 
|  | int expected_back = 9; | 
|  |  | 
|  | for (int i = 0; i < 30; i++) { | 
|  | EXPECT_EQ(0, q.begin() - q.begin()); | 
|  | EXPECT_EQ(0, q.end() - q.end()); | 
|  | EXPECT_EQ(q.size(), static_cast<size_t>(q.end() - q.begin())); | 
|  |  | 
|  | // += | 
|  | circular_deque<int>::iterator eight = q.begin(); | 
|  | eight += 8; | 
|  | EXPECT_EQ(8, eight - q.begin()); | 
|  | EXPECT_EQ(expected_front + 8, *eight); | 
|  |  | 
|  | // -= | 
|  | eight -= 8; | 
|  | EXPECT_EQ(q.begin(), eight); | 
|  |  | 
|  | // + | 
|  | eight = eight + 8; | 
|  | EXPECT_EQ(8, eight - q.begin()); | 
|  |  | 
|  | // - | 
|  | eight = eight - 8; | 
|  | EXPECT_EQ(q.begin(), eight); | 
|  |  | 
|  | expected_front++; | 
|  | expected_back++; | 
|  |  | 
|  | q.pop_front(); | 
|  | q.push_back(expected_back); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, IteratorArrayAccess) { | 
|  | circular_deque<int> q = MakeSequence(10); | 
|  |  | 
|  | circular_deque<int>::iterator begin = q.begin(); | 
|  | EXPECT_EQ(0, begin[0]); | 
|  | EXPECT_EQ(9, begin[9]); | 
|  |  | 
|  | circular_deque<int>::iterator end = q.end(); | 
|  | EXPECT_EQ(0, end[-10]); | 
|  | EXPECT_EQ(9, end[-1]); | 
|  |  | 
|  | begin[0] = 100; | 
|  | EXPECT_EQ(100, end[-10]); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, ReverseIterator) { | 
|  | circular_deque<int> q; | 
|  | q.push_back(4); | 
|  | q.push_back(3); | 
|  | q.push_back(2); | 
|  | q.push_back(1); | 
|  |  | 
|  | circular_deque<int>::reverse_iterator iter = q.rbegin(); | 
|  | EXPECT_EQ(1, *iter); | 
|  | iter++; | 
|  | EXPECT_EQ(2, *iter); | 
|  | ++iter; | 
|  | EXPECT_EQ(3, *iter); | 
|  | iter++; | 
|  | EXPECT_EQ(4, *iter); | 
|  | ++iter; | 
|  | EXPECT_EQ(q.rend(), iter); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, CapacityReserveShrink) { | 
|  | circular_deque<int> q; | 
|  |  | 
|  | // A default constructed queue should have no capacity since it should waste | 
|  | // no space. | 
|  | EXPECT_TRUE(q.empty()); | 
|  | EXPECT_EQ(0u, q.size()); | 
|  | EXPECT_EQ(0u, q.capacity()); | 
|  |  | 
|  | size_t new_capacity = 100; | 
|  | q.reserve(new_capacity); | 
|  | EXPECT_EQ(new_capacity, q.capacity()); | 
|  |  | 
|  | // Adding that many items should not cause a resize. | 
|  | for (size_t i = 0; i < new_capacity; i++) | 
|  | q.push_back(i); | 
|  | EXPECT_EQ(new_capacity, q.size()); | 
|  | EXPECT_EQ(new_capacity, q.capacity()); | 
|  |  | 
|  | // Shrink to fit to a smaller size. | 
|  | size_t capacity_2 = new_capacity / 2; | 
|  | q.resize(capacity_2); | 
|  | q.shrink_to_fit(); | 
|  | EXPECT_EQ(capacity_2, q.size()); | 
|  | EXPECT_EQ(capacity_2, q.capacity()); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, CapacityAutoShrink) { | 
|  | size_t big_size = 1000u; | 
|  | circular_deque<int> q; | 
|  | q.resize(big_size); | 
|  |  | 
|  | size_t big_capacity = q.capacity(); | 
|  |  | 
|  | // Delete 3/4 of the items. | 
|  | for (size_t i = 0; i < big_size / 4 * 3; i++) | 
|  | q.pop_back(); | 
|  |  | 
|  | // The capacity should have shrunk by deleting that many items. | 
|  | size_t medium_capacity = q.capacity(); | 
|  | EXPECT_GT(big_capacity, medium_capacity); | 
|  |  | 
|  | // Using resize to shrink should keep some extra capacity. | 
|  | q.resize(1); | 
|  | EXPECT_LT(1u, q.capacity()); | 
|  |  | 
|  | q.resize(0); | 
|  | EXPECT_LT(0u, q.capacity()); | 
|  |  | 
|  | // Using clear() should delete everything. | 
|  | q.clear(); | 
|  | EXPECT_EQ(0u, q.capacity()); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, ClearAndEmpty) { | 
|  | circular_deque<int> q; | 
|  | EXPECT_TRUE(q.empty()); | 
|  |  | 
|  | q.resize(10); | 
|  | EXPECT_EQ(10u, q.size()); | 
|  | EXPECT_FALSE(q.empty()); | 
|  |  | 
|  | q.clear(); | 
|  | EXPECT_EQ(0u, q.size()); | 
|  | EXPECT_TRUE(q.empty()); | 
|  |  | 
|  | // clear() also should reset the capacity. | 
|  | EXPECT_EQ(0u, q.capacity()); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, Resize) { | 
|  | circular_deque<int> q; | 
|  |  | 
|  | // Resize with default constructor. | 
|  | size_t first_size = 10; | 
|  | q.resize(first_size); | 
|  | EXPECT_EQ(first_size, q.size()); | 
|  | for (size_t i = 0; i < first_size; i++) | 
|  | EXPECT_EQ(0, q[i]); | 
|  |  | 
|  | // Resize with different value. | 
|  | size_t second_expand = 10; | 
|  | q.resize(first_size + second_expand, 3); | 
|  | EXPECT_EQ(first_size + second_expand, q.size()); | 
|  | for (size_t i = 0; i < first_size; i++) | 
|  | EXPECT_EQ(0, q[i]); | 
|  | for (size_t i = 0; i < second_expand; i++) | 
|  | EXPECT_EQ(3, q[i + first_size]); | 
|  |  | 
|  | // Erase from the end and add to the beginning so resize is forced to cross | 
|  | // a circular buffer wrap boundary. | 
|  | q.shrink_to_fit(); | 
|  | for (int i = 0; i < 5; i++) { | 
|  | q.pop_back(); | 
|  | q.push_front(6); | 
|  | } | 
|  | q.resize(10); | 
|  |  | 
|  | EXPECT_EQ(6, q[0]); | 
|  | EXPECT_EQ(6, q[1]); | 
|  | EXPECT_EQ(6, q[2]); | 
|  | EXPECT_EQ(6, q[3]); | 
|  | EXPECT_EQ(6, q[4]); | 
|  | EXPECT_EQ(0, q[5]); | 
|  | EXPECT_EQ(0, q[6]); | 
|  | EXPECT_EQ(0, q[7]); | 
|  | EXPECT_EQ(0, q[8]); | 
|  | EXPECT_EQ(0, q[9]); | 
|  | } | 
|  |  | 
|  | // Tests destructor behavior of resize. | 
|  | TEST(CircularDeque, ResizeDelete) { | 
|  | int counter = 0; | 
|  | circular_deque<DestructorCounter> q; | 
|  | q.resize(10, DestructorCounter(&counter)); | 
|  | // The one temporary when calling resize() should be deleted, that's it. | 
|  | EXPECT_EQ(1, counter); | 
|  |  | 
|  | // The loops below assume the capacity will be set by resize(). | 
|  | EXPECT_EQ(10u, q.capacity()); | 
|  |  | 
|  | // Delete some via resize(). This is done so that the wasted items are | 
|  | // still greater than the size() so that auto-shrinking is not triggered | 
|  | // (which will mess up our destructor counting). | 
|  | counter = 0; | 
|  | q.resize(8, DestructorCounter(&counter)); | 
|  | // 2 deleted ones + the one temporary in the resize() call. | 
|  | EXPECT_EQ(3, counter); | 
|  |  | 
|  | // Cycle through some items so two items will cross the boundary in the | 
|  | // 11-item buffer (one more than the capacity). | 
|  | //   Before: x x x x x x x x . . . | 
|  | //   After:  x . . . x x x x x x x | 
|  | counter = 0; | 
|  | for (int i = 0; i < 4; i++) { | 
|  | q.emplace_back(&counter); | 
|  | q.pop_front(); | 
|  | } | 
|  | EXPECT_EQ(4, counter);  // Loop should have deleted 7 items. | 
|  |  | 
|  | // Delete two items with resize, these should be on either side of the | 
|  | // buffer wrap point. | 
|  | counter = 0; | 
|  | q.resize(6, DestructorCounter(&counter)); | 
|  | // 2 deleted ones + the one temporary in the resize() call. | 
|  | EXPECT_EQ(3, counter); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, InsertEraseSingle) { | 
|  | circular_deque<int> q; | 
|  | q.push_back(1); | 
|  | q.push_back(2); | 
|  |  | 
|  | // Insert at the beginning. | 
|  | auto result = q.insert(q.begin(), 0); | 
|  | EXPECT_EQ(q.begin(), result); | 
|  | EXPECT_EQ(3u, q.size()); | 
|  | EXPECT_EQ(0, q[0]); | 
|  | EXPECT_EQ(1, q[1]); | 
|  | EXPECT_EQ(2, q[2]); | 
|  |  | 
|  | // Erase at the beginning. | 
|  | result = q.erase(q.begin()); | 
|  | EXPECT_EQ(q.begin(), result); | 
|  | EXPECT_EQ(2u, q.size()); | 
|  | EXPECT_EQ(1, q[0]); | 
|  | EXPECT_EQ(2, q[1]); | 
|  |  | 
|  | // Insert at the end. | 
|  | result = q.insert(q.end(), 3); | 
|  | EXPECT_EQ(q.end() - 1, result); | 
|  | EXPECT_EQ(1, q[0]); | 
|  | EXPECT_EQ(2, q[1]); | 
|  | EXPECT_EQ(3, q[2]); | 
|  |  | 
|  | // Erase at the end. | 
|  | result = q.erase(q.end() - 1); | 
|  | EXPECT_EQ(q.end(), result); | 
|  | EXPECT_EQ(1, q[0]); | 
|  | EXPECT_EQ(2, q[1]); | 
|  |  | 
|  | // Insert in the middle. | 
|  | result = q.insert(q.begin() + 1, 10); | 
|  | EXPECT_EQ(q.begin() + 1, result); | 
|  | EXPECT_EQ(1, q[0]); | 
|  | EXPECT_EQ(10, q[1]); | 
|  | EXPECT_EQ(2, q[2]); | 
|  |  | 
|  | // Erase in the middle. | 
|  | result = q.erase(q.begin() + 1); | 
|  | EXPECT_EQ(q.begin() + 1, result); | 
|  | EXPECT_EQ(1, q[0]); | 
|  | EXPECT_EQ(2, q[1]); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, InsertFill) { | 
|  | circular_deque<int> q; | 
|  |  | 
|  | // Fill when empty. | 
|  | q.insert(q.begin(), 2, 1); | 
|  |  | 
|  | // 0's at the beginning. | 
|  | q.insert(q.begin(), 2, 0); | 
|  |  | 
|  | // 50's in the middle (now at offset 3). | 
|  | q.insert(q.begin() + 3, 2, 50); | 
|  |  | 
|  | // 200's at the end. | 
|  | q.insert(q.end(), 2, 200); | 
|  |  | 
|  | ASSERT_EQ(8u, q.size()); | 
|  | EXPECT_EQ(0, q[0]); | 
|  | EXPECT_EQ(0, q[1]); | 
|  | EXPECT_EQ(1, q[2]); | 
|  | EXPECT_EQ(50, q[3]); | 
|  | EXPECT_EQ(50, q[4]); | 
|  | EXPECT_EQ(1, q[5]); | 
|  | EXPECT_EQ(200, q[6]); | 
|  | EXPECT_EQ(200, q[7]); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, InsertEraseRange) { | 
|  | circular_deque<int> q; | 
|  |  | 
|  | // Erase nothing from an empty deque should work. | 
|  | q.erase(q.begin(), q.end()); | 
|  |  | 
|  | // Loop index used below to shift the used items in the buffer. | 
|  | for (int i = 0; i < 10; i++) { | 
|  | circular_deque<int> source; | 
|  |  | 
|  | // Fill empty range. | 
|  | q.insert(q.begin(), source.begin(), source.end()); | 
|  |  | 
|  | // Have some stuff to insert. | 
|  | source.push_back(1); | 
|  | source.push_back(2); | 
|  |  | 
|  | q.insert(q.begin(), source.begin(), source.end()); | 
|  |  | 
|  | // Shift the used items in the buffer by i which will place the two used | 
|  | // elements in different places in the buffer each time through this loop. | 
|  | for (int shift_i = 0; shift_i < i; shift_i++) { | 
|  | q.push_back(0); | 
|  | q.pop_front(); | 
|  | } | 
|  |  | 
|  | // Set the two items to notable values so we can check for them later. | 
|  | ASSERT_EQ(2u, q.size()); | 
|  | q[0] = 100; | 
|  | q[1] = 101; | 
|  |  | 
|  | // Insert at the beginning, middle (now at offset 3), and end. | 
|  | q.insert(q.begin(), source.begin(), source.end()); | 
|  | q.insert(q.begin() + 3, source.begin(), source.end()); | 
|  | q.insert(q.end(), source.begin(), source.end()); | 
|  |  | 
|  | ASSERT_EQ(8u, q.size()); | 
|  | EXPECT_EQ(1, q[0]); | 
|  | EXPECT_EQ(2, q[1]); | 
|  | EXPECT_EQ(100, q[2]);  // First inserted one. | 
|  | EXPECT_EQ(1, q[3]); | 
|  | EXPECT_EQ(2, q[4]); | 
|  | EXPECT_EQ(101, q[5]);  // First inserted second one. | 
|  | EXPECT_EQ(1, q[6]); | 
|  | EXPECT_EQ(2, q[7]); | 
|  |  | 
|  | // Now erase the inserted ranges. Try each subsection also with no items | 
|  | // being erased, which should be a no-op. | 
|  | auto result = q.erase(q.begin(), q.begin());  // No-op. | 
|  | EXPECT_EQ(q.begin(), result); | 
|  | result = q.erase(q.begin(), q.begin() + 2); | 
|  | EXPECT_EQ(q.begin(), result); | 
|  |  | 
|  | result = q.erase(q.begin() + 1, q.begin() + 1);  // No-op. | 
|  | EXPECT_EQ(q.begin() + 1, result); | 
|  | result = q.erase(q.begin() + 1, q.begin() + 3); | 
|  | EXPECT_EQ(q.begin() + 1, result); | 
|  |  | 
|  | result = q.erase(q.end() - 2, q.end() - 2);  // No-op. | 
|  | EXPECT_EQ(q.end() - 2, result); | 
|  | result = q.erase(q.end() - 2, q.end()); | 
|  | EXPECT_EQ(q.end(), result); | 
|  |  | 
|  | ASSERT_EQ(2u, q.size()); | 
|  | EXPECT_EQ(100, q[0]); | 
|  | EXPECT_EQ(101, q[1]); | 
|  |  | 
|  | // Erase everything. | 
|  | result = q.erase(q.begin(), q.end()); | 
|  | EXPECT_EQ(q.end(), result); | 
|  | EXPECT_TRUE(q.empty()); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, EmplaceMoveOnly) { | 
|  | int values[] = {1, 3}; | 
|  | circular_deque<MoveOnlyInt> q(std::begin(values), std::end(values)); | 
|  |  | 
|  | q.emplace(q.begin(), MoveOnlyInt(0)); | 
|  | q.emplace(q.begin() + 2, MoveOnlyInt(2)); | 
|  | q.emplace(q.end(), MoveOnlyInt(4)); | 
|  |  | 
|  | ASSERT_EQ(5u, q.size()); | 
|  | EXPECT_EQ(0, q[0].data()); | 
|  | EXPECT_EQ(1, q[1].data()); | 
|  | EXPECT_EQ(2, q[2].data()); | 
|  | EXPECT_EQ(3, q[3].data()); | 
|  | EXPECT_EQ(4, q[4].data()); | 
|  | } | 
|  |  | 
|  | TEST(CircularDeque, EmplaceFrontBackReturnsReference) { | 
|  | circular_deque<int> q; | 
|  | q.reserve(2); | 
|  |  | 
|  | int& front = q.emplace_front(1); | 
|  | int& back = q.emplace_back(2); | 
|  | ASSERT_EQ(2u, q.size()); | 
|  | EXPECT_EQ(1, q[0]); | 
|  | EXPECT_EQ(2, q[1]); | 
|  |  | 
|  | EXPECT_EQ(&front, &q.front()); | 
|  | EXPECT_EQ(&back, &q.back()); | 
|  |  | 
|  | front = 3; | 
|  | back = 4; | 
|  |  | 
|  | ASSERT_EQ(2u, q.size()); | 
|  | EXPECT_EQ(3, q[0]); | 
|  | EXPECT_EQ(4, q[1]); | 
|  |  | 
|  | EXPECT_EQ(&front, &q.front()); | 
|  | EXPECT_EQ(&back, &q.back()); | 
|  | } | 
|  |  | 
|  | /* | 
|  | This test should assert in a debug build. It tries to dereference an iterator | 
|  | after mutating the container. Uncomment to double-check that this works. | 
|  | TEST(CircularDeque, UseIteratorAfterMutate) { | 
|  | circular_deque<int> q; | 
|  | q.push_back(0); | 
|  |  | 
|  | auto old_begin = q.begin(); | 
|  | EXPECT_EQ(0, *old_begin); | 
|  |  | 
|  | q.push_back(1); | 
|  | EXPECT_EQ(0, *old_begin);  // Should DCHECK. | 
|  | } | 
|  | */ | 
|  |  | 
|  | }  // namespace base |