| // Copyright 2017 The Chromium Authors |
| // 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/memory/raw_ptr.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: |
| raw_ptr<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 |