// Copyright 2020 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #include "pw_containers/inline_deque.h" #include #include #include #include "pw_compilation_testing/negative_compilation.h" #include "pw_containers/algorithm.h" #include "pw_containers_private/test_helpers.h" #include "pw_unit_test/framework.h" namespace pw::containers { namespace { using namespace std::literals::string_view_literals; using test::CopyOnly; using test::Counter; using test::MoveOnly; TEST(InlineDeque, Construct_Sized) { InlineDeque deque; EXPECT_TRUE(deque.empty()); EXPECT_EQ(deque.size(), 0u); EXPECT_EQ(deque.max_size(), 3u); } TEST(InlineDeque, Construct_GenericSized) { InlineDeque sized_deque; InlineDeque& deque(sized_deque); EXPECT_TRUE(deque.empty()); EXPECT_EQ(deque.size(), 0u); EXPECT_EQ(deque.max_size(), 3u); } TEST(InlineDeque, Construct_CopySameCapacity) { InlineDeque deque(4, CopyOnly(123)); const auto& deque_ref = deque; InlineDeque copied(deque_ref); ASSERT_EQ(4u, deque.size()); EXPECT_EQ(123, deque[3].value); ASSERT_EQ(4u, copied.size()); EXPECT_EQ(123, copied[3].value); } TEST(InlineDeque, Construct_MoveSameCapacity) { InlineDeque deque; deque.emplace_back(MoveOnly(1)); deque.emplace_back(MoveOnly(2)); deque.emplace_back(MoveOnly(3)); deque.emplace_back(MoveOnly(4)); InlineDeque moved(std::move(deque)); // NOLINTNEXTLINE(bugprone-use-after-move) EXPECT_EQ(0u, deque.size()); ASSERT_EQ(4u, moved.size()); EXPECT_EQ(4, moved[3].value); } TEST(InlineDeque, Construct_CopyLargerCapacity) { InlineDeque deque(4, CopyOnly(123)); InlineDeque copied(deque); ASSERT_EQ(4u, deque.size()); EXPECT_EQ(123, deque[3].value); ASSERT_EQ(4u, copied.size()); EXPECT_EQ(123, copied[3].value); } TEST(InlineDeque, Construct_MoveLargerCapacity) { InlineDeque deque; deque.emplace_back(MoveOnly(1)); deque.emplace_back(MoveOnly(2)); deque.emplace_back(MoveOnly(3)); deque.emplace_back(MoveOnly(4)); InlineDeque moved(std::move(deque)); // NOLINTNEXTLINE(bugprone-use-after-move) EXPECT_EQ(0u, deque.size()); ASSERT_EQ(4u, moved.size()); EXPECT_EQ(4, moved[3].value); } TEST(InlineDeque, Construct_CopySmallerCapacity) { InlineDeque deque(3, CopyOnly(123)); InlineDeque copied(deque); ASSERT_EQ(3u, deque.size()); EXPECT_EQ(123, deque[2].value); ASSERT_EQ(3u, copied.size()); EXPECT_EQ(123, copied[2].value); } TEST(InlineDeque, Destruct_ZeroLength) { Counter::Reset(); { InlineDeque deque; EXPECT_EQ(deque.size(), 0u); } EXPECT_EQ(Counter::created, 0); EXPECT_EQ(Counter::destroyed, 0); } TEST(InlineDeque, Destruct_Empty) { Counter::Reset(); { InlineDeque deque; EXPECT_EQ(deque.size(), 0u); } EXPECT_EQ(Counter::created, 0); EXPECT_EQ(Counter::destroyed, 0); } TEST(InlineDeque, Destruct_MultipleEntries) { Counter value; Counter::Reset(); { InlineDeque deque(100, value); } EXPECT_EQ(Counter::created, 100); EXPECT_EQ(Counter::destroyed, 100); } TEST(InlineDeque, Assign_InitializerList) { InlineDeque deque = {1, 3, 5, 7}; ASSERT_EQ(4u, deque.size()); EXPECT_EQ(1, deque[0]); EXPECT_EQ(3, deque[1]); EXPECT_EQ(5, deque[2]); EXPECT_EQ(7, deque[3]); } TEST(InlineDeque, Assign_CopySameCapacity) { InlineDeque deque(4, CopyOnly(123)); InlineDeque copied = deque; ASSERT_EQ(4u, deque.size()); EXPECT_EQ(123, deque[3].value); ASSERT_EQ(4u, copied.size()); EXPECT_EQ(123, copied[3].value); } TEST(InlineDeque, Assign_CopyLargerCapacity) { InlineDeque deque(4, CopyOnly(123)); InlineDeque copied = deque; ASSERT_EQ(4u, deque.size()); EXPECT_EQ(123, deque[3].value); ASSERT_EQ(4u, copied.size()); EXPECT_EQ(123, copied[3].value); } TEST(InlineDeque, Assign_CopySmallerCapacity) { InlineDeque deque(3, CopyOnly(123)); InlineDeque copied = deque; ASSERT_EQ(3u, deque.size()); EXPECT_EQ(123, deque[2].value); ASSERT_EQ(3u, copied.size()); EXPECT_EQ(123, copied[2].value); } TEST(InlineDeque, Assign_MoveSameCapacity) { InlineDeque deque; deque.emplace_back(MoveOnly(1)); deque.emplace_back(MoveOnly(2)); deque.emplace_back(MoveOnly(3)); deque.emplace_back(MoveOnly(4)); InlineDeque moved = std::move(deque); // NOLINTNEXTLINE(bugprone-use-after-move) EXPECT_EQ(0u, deque.size()); ASSERT_EQ(4u, moved.size()); EXPECT_EQ(4, moved[3].value); } TEST(InlineDeque, Assign_MoveLargerCapacity) { InlineDeque deque; deque.emplace_back(MoveOnly(1)); deque.emplace_back(MoveOnly(2)); deque.emplace_back(MoveOnly(3)); deque.emplace_back(MoveOnly(4)); InlineDeque moved = std::move(deque); // NOLINTNEXTLINE(bugprone-use-after-move) EXPECT_EQ(0u, deque.size()); ASSERT_EQ(4u, moved.size()); EXPECT_EQ(4, moved[3].value); } TEST(InlineDeque, Assign_MoveSmallerCapacity) { InlineDeque deque; deque.emplace_back(MoveOnly(1)); deque.emplace_back(MoveOnly(2)); deque.emplace_back(MoveOnly(3)); InlineDeque moved = std::move(deque); // NOLINTNEXTLINE(bugprone-use-after-move) EXPECT_EQ(0u, deque.size()); ASSERT_EQ(3u, moved.size()); EXPECT_EQ(3, moved[2].value); } TEST(InlineDeque, Access_Iterator) { InlineDeque deque(2); for (Counter& item : deque) { EXPECT_EQ(item.value, 0); } for (const Counter& item : deque) { EXPECT_EQ(item.value, 0); } } TEST(InlineDeque, Access_ConstIterator) { const InlineDeque deque(2); for (const Counter& item : deque) { EXPECT_EQ(item.value, 0); } } TEST(InlineDeque, Access_ZeroLength) { InlineDeque deque; EXPECT_EQ(0u, deque.size()); EXPECT_EQ(0u, deque.max_size()); EXPECT_TRUE(deque.empty()); EXPECT_TRUE(deque.full()); for (Counter& item : deque) { (void)item; FAIL(); } } TEST(InlineDeque, Access_ContiguousData) { // Content = {}, Storage = [x, x] InlineDeque deque; { auto [first, second] = deque.contiguous_data(); EXPECT_EQ(first.size(), 0u); EXPECT_EQ(second.size(), 0u); } // Content = {1}, Storage = [1, x] deque.push_back(1); { auto [first, second] = deque.contiguous_data(); EXPECT_TRUE(Equal(first, std::array{1})); EXPECT_TRUE(Equal(second, std::array{})); } // Content = {1, 2}, Storage = [1, 2] deque.push_back(2); EXPECT_TRUE(deque.full()); { auto [first, second] = deque.contiguous_data(); EXPECT_TRUE(Equal(first, std::array{1, 2})); EXPECT_TRUE(Equal(second, std::array{})); } // Content = {2}, Storage = [x, 2] deque.pop_front(); { auto [first, second] = deque.contiguous_data(); EXPECT_TRUE(Equal(first, std::array{2})); EXPECT_TRUE(Equal(second, std::array{})); } // Content = {2, 1}, Storage = [1, 2] deque.push_back(1); { auto [first, second] = deque.contiguous_data(); EXPECT_TRUE(Equal(first, std::array{2})); EXPECT_TRUE(Equal(second, std::array{1})); } // Content = {1}, Storage = [1, x] deque.pop_front(); { auto [first, second] = deque.contiguous_data(); EXPECT_TRUE(Equal(first, std::array{1})); EXPECT_TRUE(Equal(second, std::array{})); } // Content = {1, 2}, Storage = [1, 2] deque.push_back(2); { auto [first, second] = deque.contiguous_data(); EXPECT_TRUE(Equal(first, std::array{1, 2})); EXPECT_TRUE(Equal(second, std::array{})); } } TEST(InlineDeque, Access_ConstContiguousData) { // Content = {1, 2}, Storage = [1, 2] const InlineDeque deque = {1, 2}; { auto [first, second] = deque.contiguous_data(); EXPECT_EQ(first.size(), 2u); EXPECT_EQ(second.size(), 0u); } } TEST(InlineDeque, Modify_Clear) { Counter::Reset(); InlineDeque deque; deque.emplace_back(); deque.emplace_back(); deque.emplace_back(); deque.clear(); EXPECT_EQ(3, Counter::created); EXPECT_EQ(3, Counter::destroyed); } TEST(InlineDeque, Modify_PushBack_Copy) { Counter value(99); Counter::Reset(); { InlineDeque deque; deque.push_back(value); ASSERT_EQ(deque.size(), 1u); EXPECT_EQ(deque.front().value, 99); } EXPECT_EQ(Counter::created, 1); EXPECT_EQ(Counter::destroyed, 1); } TEST(InlineDeque, Modify_PushBack_Move) { Counter::Reset(); { Counter value(99); InlineDeque deque; deque.push_back(std::move(value)); EXPECT_EQ(deque.size(), 1u); EXPECT_EQ(deque.front().value, 99); // NOLINTNEXTLINE(bugprone-use-after-move) EXPECT_EQ(value.value, 0); } EXPECT_EQ(Counter::created, 1); EXPECT_EQ(Counter::destroyed, 2); EXPECT_EQ(Counter::moved, 1); } TEST(InlineDeque, Modify_EmplaceBack) { Counter::Reset(); { InlineDeque deque; deque.emplace_back(314); ASSERT_EQ(deque.size(), 1u); EXPECT_EQ(deque.front().value, 314); } EXPECT_EQ(Counter::created, 1); EXPECT_EQ(Counter::destroyed, 1); } TEST(InlineDeque, Modify_WrapForwards) { Counter::Reset(); { InlineDeque deque; deque.emplace_back(1); deque.emplace_back(2); deque.emplace_back(3); ASSERT_EQ(deque.size(), 3u); EXPECT_EQ(deque[0].value, 1); EXPECT_EQ(deque.front().value, 1); EXPECT_EQ(deque[1].value, 2); EXPECT_EQ(deque[2].value, 3); EXPECT_EQ(deque.back().value, 3); deque.pop_front(); deque.emplace_back(4); ASSERT_EQ(deque.size(), 3u); EXPECT_EQ(deque[0].value, 2); EXPECT_EQ(deque.front().value, 2); EXPECT_EQ(deque[1].value, 3); EXPECT_EQ(deque[2].value, 4); EXPECT_EQ(deque.back().value, 4); } EXPECT_EQ(Counter::created, 4); EXPECT_EQ(Counter::destroyed, 4); } TEST(InlineDeque, Modify_WrapBackwards) { Counter::Reset(); { InlineDeque deque; deque.emplace_front(1); deque.emplace_front(2); deque.emplace_front(3); ASSERT_EQ(deque.size(), 3u); EXPECT_EQ(deque[0].value, 3); EXPECT_EQ(deque.front().value, 3); EXPECT_EQ(deque[1].value, 2); EXPECT_EQ(deque[2].value, 1); EXPECT_EQ(deque.back().value, 1); deque.pop_back(); deque.emplace_front(4); ASSERT_EQ(deque.size(), 3u); EXPECT_EQ(deque[0].value, 4); EXPECT_EQ(deque.front().value, 4); EXPECT_EQ(deque[1].value, 3); EXPECT_EQ(deque[2].value, 2); EXPECT_EQ(deque.back().value, 2); } EXPECT_EQ(Counter::created, 4); EXPECT_EQ(Counter::destroyed, 4); } TEST(InlineDeque, Modify_PushFront_Copy) { Counter value(99); Counter::Reset(); { InlineDeque deque; deque.push_front(value); EXPECT_EQ(deque.size(), 1u); EXPECT_EQ(deque.front().value, 99); } EXPECT_EQ(Counter::created, 1); EXPECT_EQ(Counter::destroyed, 1); } TEST(InlineDeque, Modify_PushFront_Move) { Counter::Reset(); { Counter value(99); InlineDeque deque; deque.push_front(std::move(value)); EXPECT_EQ(deque.size(), 1u); EXPECT_EQ(deque.front().value, 99); // NOLINTNEXTLINE(bugprone-use-after-move) EXPECT_EQ(value.value, 0); } EXPECT_EQ(Counter::created, 1); EXPECT_EQ(Counter::destroyed, 2); EXPECT_EQ(Counter::moved, 1); } TEST(InlineDeque, Modify_EmplaceFront) { Counter::Reset(); { InlineDeque deque; deque.emplace_front(314); EXPECT_EQ(deque.size(), 1u); EXPECT_EQ(deque.front().value, 314); } EXPECT_EQ(Counter::created, 1); EXPECT_EQ(Counter::destroyed, 1); } TEST(InlineDeque, Modify_PopBack) { Counter::Reset(); InlineDeque deque; deque.emplace_front(1); // This wraps to the other end. deque.emplace_back(2); // This is the first entry in storage. deque.emplace_back(3); // Content = {1, 2, 3}, Storage = [2, 3, 1] ASSERT_EQ(deque.size(), 3u); EXPECT_EQ(deque[0].value, 1); EXPECT_EQ(deque[1].value, 2); EXPECT_EQ(deque[2].value, 3); deque.pop_back(); // Content = {1, 2}, Storage = [2, x, 1] ASSERT_EQ(deque.size(), 2u); EXPECT_EQ(deque[0].value, 1); EXPECT_EQ(deque[1].value, 2); // This wraps around. deque.pop_back(); // Content = {1}, Storage = [x, x, 1] ASSERT_EQ(deque.size(), 1u); EXPECT_EQ(deque[0].value, 1); EXPECT_EQ(Counter::created, 3); EXPECT_EQ(Counter::destroyed, 2); } TEST(InlineDeque, Modify_PopFront) { Counter::Reset(); InlineDeque deque; deque.emplace_front(1); // This wraps to the other end. deque.emplace_back(2); // This is the first entry in storage. deque.emplace_back(3); // Content = {1, 2, 3}, Storage = [2, 3, 1] ASSERT_EQ(deque.size(), 3u); EXPECT_EQ(deque[0].value, 1); EXPECT_EQ(deque[1].value, 2); EXPECT_EQ(deque[2].value, 3); // This wraps around deque.pop_front(); // Content = {2, 3}, Storage = [2, 3, x] EXPECT_EQ(deque.size(), 2u); EXPECT_EQ(deque[0].value, 2); EXPECT_EQ(deque[1].value, 3); deque.pop_front(); // Content = {3}, Storage = [x, 3, x] ASSERT_EQ(deque.size(), 1u); EXPECT_EQ(deque[0].value, 3); EXPECT_EQ(Counter::created, 3); EXPECT_EQ(Counter::destroyed, 2); } TEST(InlineDeque, Modify_Resize_Larger) { InlineDeque deque(1, CopyOnly(123)); deque.resize(3, CopyOnly(123)); EXPECT_EQ(deque.size(), 3u); for (auto& i : deque) { EXPECT_EQ(i.value, 123); } } TEST(InlineDeque, Modify_Resize_LargerThanMax) { InlineDeque deque; deque.resize(1000, CopyOnly(123)); EXPECT_EQ(deque.size(), 10u); for (auto& i : deque) { EXPECT_EQ(i.value, 123); } } TEST(InlineDeque, Modify_Resize_Smaller) { InlineDeque deque(9, CopyOnly(123)); deque.resize(3, CopyOnly(123)); EXPECT_EQ(deque.size(), 3u); for (auto& i : deque) { EXPECT_EQ(i.value, 123); } } TEST(InlineDeque, Modify_Resize_Zero) { InlineDeque deque(10, CopyOnly(123)); deque.resize(0, CopyOnly(123)); EXPECT_EQ(deque.size(), 0u); } TEST(InlineDeque, Generic) { InlineDeque deque; InlineDeque& generic_deque(deque); generic_deque = {1, 2, 3, 4, 5}; EXPECT_EQ(generic_deque.size(), deque.size()); EXPECT_EQ(generic_deque.max_size(), deque.max_size()); unsigned short i = 0; for (int value : deque) { EXPECT_EQ(value, generic_deque[i]); i += 1; } i = 0; for (int value : generic_deque) { EXPECT_EQ(deque[i], value); i += 1; } } TEST(InlineDeque, ConstexprMaxSize) { InlineDeque deque; constexpr size_t kMaxSize = deque.max_size(); EXPECT_EQ(deque.max_size(), kMaxSize); // Ensure the generic sized container does not have a constexpr max_size(). [[maybe_unused]] InlineDeque& generic_deque(deque); #if PW_NC_TEST(InlineDeque_GenericMaxSize_NotConstexpr) PW_NC_EXPECT_CLANG( "kGenericMaxSize.* must be initialized by a constant expression"); PW_NC_EXPECT_GCC("call to non-'constexpr' function .*InlineDeque.*max_size"); [[maybe_unused]] constexpr size_t kGenericMaxSize = generic_deque.max_size(); #endif // PW_NC_TEST } TEST(InlineDeque, StdMaxElement) { // Content = {1, 2, 3, 4}, Storage = [1, 2, 3, 4] InlineDeque deque = {1, 2, 3, 4}; auto max_element_it = std::max_element(deque.begin(), deque.end()); ASSERT_NE(max_element_it, deque.end()); EXPECT_EQ(*max_element_it, 4); // Content = {2, 3, 4}, Storage = [x, 2, 3, 4] deque.pop_front(); max_element_it = std::max_element(deque.begin(), deque.end()); ASSERT_NE(max_element_it, deque.end()); EXPECT_EQ(*max_element_it, 4); // Content = {2, 3, 4, 5}, Storage = [5, 2, 3, 4] deque.push_back(5); max_element_it = std::max_element(deque.begin(), deque.end()); ASSERT_NE(max_element_it, deque.end()); EXPECT_EQ(*max_element_it, 5); // Content = {}, Storage = [x, x, x, x] deque.clear(); max_element_it = std::max_element(deque.begin(), deque.end()); ASSERT_EQ(max_element_it, deque.end()); } TEST(InlineDeque, StdMaxElementConst) { // Content = {1, 2, 3, 4}, Storage = [1, 2, 3, 4] InlineDeque deque = {1, 2, 3, 4}; auto max_element_it = std::max_element(deque.cbegin(), deque.cend()); ASSERT_NE(max_element_it, deque.cend()); EXPECT_EQ(*max_element_it, 4); // Content = {2, 3, 4}, Storage = [x, 2, 3, 4] deque.pop_front(); max_element_it = std::max_element(deque.cbegin(), deque.cend()); ASSERT_NE(max_element_it, deque.cend()); EXPECT_EQ(*max_element_it, 4); // Content = {2, 3, 4, 5}, Storage = [5, 2, 3, 4] deque.push_back(5); max_element_it = std::max_element(deque.cbegin(), deque.cend()); ASSERT_NE(max_element_it, deque.cend()); EXPECT_EQ(*max_element_it, 5); // Content = {}, Storage = [x, x, x, x] deque.clear(); max_element_it = std::max_element(deque.cbegin(), deque.cend()); ASSERT_EQ(max_element_it, deque.cend()); } TEST(InlineDeque, OperatorPlus) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineDeque deque = {0, 0, 1, 2}; // Content = {0, 1, 2}, Storage = [x, 0, 1, 2] deque.pop_front(); // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] deque.push_back(3); // Content = {1, 2, 3}, Storage = [3, x, 1, 2] deque.pop_front(); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] deque.push_back(4); for (int i = 0; i < 4; i++) { ASSERT_EQ(*(deque.begin() + i), static_cast(i + 1)); ASSERT_EQ(*(i + deque.begin()), static_cast(i + 1)); } ASSERT_EQ(deque.begin() + deque.size(), deque.end()); } TEST(InlineDeque, OperatorPlusPlus) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineDeque deque = {0, 0, 1, 2}; // Content = {0, 1, 2}, Storage = [x, 0, 1, 2] deque.pop_front(); // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] deque.push_back(3); // Content = {1, 2, 3}, Storage = [3, x, 1, 2] deque.pop_front(); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] deque.push_back(4); auto it = deque.begin(); ASSERT_EQ(*it, 1); it++; ASSERT_EQ(*it, 2); it++; ASSERT_EQ(*it, 3); it++; ASSERT_EQ(*it, 4); it++; ASSERT_EQ(it, deque.end()); } TEST(InlineDeque, OperatorPlusEquals) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineDeque deque = {0, 0, 1, 2}; // Content = {0, 1, 2}, Storage = [x, 0, 1, 2] deque.pop_front(); // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] deque.push_back(3); // Content = {1, 2, 3}, Storage = [3, x, 1, 2] deque.pop_front(); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] deque.push_back(4); auto it = deque.begin(); ASSERT_EQ(*it, 1); it += 1; ASSERT_EQ(*it, 2); it += 1; ASSERT_EQ(*it, 3); it += 1; ASSERT_EQ(*it, 4); it += 1; ASSERT_EQ(it, deque.end()); it = deque.begin(); ASSERT_EQ(*it, 1); it += 2; ASSERT_EQ(*it, 3); it += 2; ASSERT_EQ(it, deque.end()); it = deque.begin(); it += deque.size(); ASSERT_EQ(it, deque.end()); } TEST(InlineDeque, OpeartorMinus) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineDeque deque = {0, 0, 1, 2}; // Content = {0, 1, 2}, Storage = [x, 0, 1, 2] deque.pop_front(); // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] deque.push_back(3); // Content = {1, 2, 3}, Storage = [3, x, 1, 2] deque.pop_front(); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] deque.push_back(4); for (int i = 1; i <= 4; i++) { ASSERT_EQ(*(deque.end() - i), static_cast(5 - i)); } ASSERT_EQ(deque.end() - deque.size(), deque.begin()); } TEST(InlineDeque, OperatorMinusMinus) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineDeque deque = {0, 0, 1, 2}; // Content = {0, 1, 2}, Storage = [x, 0, 1, 2] deque.pop_front(); // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] deque.push_back(3); // Content = {1, 2, 3}, Storage = [3, x, 1, 2] deque.pop_front(); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] deque.push_back(4); auto it = deque.end(); it--; ASSERT_EQ(*it, 4); it--; ASSERT_EQ(*it, 3); it--; ASSERT_EQ(*it, 2); it--; ASSERT_EQ(*it, 1); ASSERT_EQ(it, deque.begin()); } TEST(InlineDeque, OperatorMinusEquals) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineDeque deque = {0, 0, 1, 2}; // Content = {0, 1, 2}, Storage = [x, 0, 1, 2] deque.pop_front(); // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] deque.push_back(3); // Content = {1, 2, 3}, Storage = [3, x, 1, 2] deque.pop_front(); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] deque.push_back(4); auto it = deque.end(); it -= 1; ASSERT_EQ(*it, 4); it -= 1; ASSERT_EQ(*it, 3); it -= 1; ASSERT_EQ(*it, 2); it -= 1; ASSERT_EQ(*it, 1); ASSERT_EQ(it, deque.begin()); it = deque.end(); it -= 2; ASSERT_EQ(*it, 3); it -= 2; ASSERT_EQ(*it, 1); ASSERT_EQ(it, deque.begin()); it = deque.end(); it -= deque.size(); ASSERT_EQ(it, deque.begin()); } TEST(InlineDeque, OperatorSquareBracket) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineDeque deque = {0, 0, 1, 2}; // Content = {0, 1, 2}, Storage = [x, 0, 1, 2] deque.pop_front(); // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] deque.push_back(3); // Content = {1, 2, 3}, Storage = [3, x, 1, 2] deque.pop_front(); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] deque.push_back(4); for (unsigned short i = 0; i < deque.size(); i++) { ASSERT_EQ(deque.begin()[i], static_cast(i + 1)); } } TEST(InlineDeque, OperatorLessThan) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineDeque deque = {0, 0, 1, 2}; // Content = {0, 1, 2}, Storage = [x, 0, 1, 2] deque.pop_front(); // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] deque.push_back(3); // Content = {1, 2, 3}, Storage = [3, x, 1, 2] deque.pop_front(); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] deque.push_back(4); for (int i = 0; i < deque.size(); i++) { for (int j = 0; j < i; j++) { ASSERT_TRUE((deque.begin() + j) < (deque.begin() + i)); } ASSERT_TRUE((deque.begin() + i) < deque.end()); } } TEST(InlineDeque, OperatorLessThanEqual) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineDeque deque = {0, 0, 1, 2}; // Content = {0, 1, 2}, Storage = [x, 0, 1, 2] deque.pop_front(); // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] deque.push_back(3); // Content = {1, 2, 3}, Storage = [3, x, 1, 2] deque.pop_front(); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] deque.push_back(4); for (int i = 0; i < deque.size(); i++) { for (int j = 0; j <= i; j++) { ASSERT_TRUE((deque.begin() + j) <= (deque.begin() + i)); } ASSERT_TRUE((deque.begin() + i) <= deque.end()); } } TEST(InlineDeque, OperatorGreater) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineDeque deque = {0, 0, 1, 2}; // Content = {0, 1, 2}, Storage = [x, 0, 1, 2] deque.pop_front(); // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] deque.push_back(3); // Content = {1, 2, 3}, Storage = [3, x, 1, 2] deque.pop_front(); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] deque.push_back(4); for (int i = 0; i < deque.size(); i++) { for (int j = i + 1; j < deque.size(); j++) { ASSERT_TRUE((deque.begin() + j) > (deque.begin() + i)); } ASSERT_TRUE(deque.end() > (deque.begin() + i)); } } TEST(InlineDeque, OperatorGreaterThanEqual) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineDeque deque = {0, 0, 1, 2}; // Content = {0, 1, 2}, Storage = [x, 0, 1, 2] deque.pop_front(); // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] deque.push_back(3); // Content = {1, 2, 3}, Storage = [3, x, 1, 2] deque.pop_front(); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] deque.push_back(4); for (int i = 0; i < deque.size(); i++) { for (int j = i; j < deque.size(); j++) { ASSERT_TRUE((deque.begin() + j) >= (deque.begin() + i)); } ASSERT_TRUE(deque.end() >= (deque.begin() + i)); } } TEST(InlineDeque, DereferenceOperator) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineDeque deque = {0, 0, 1, 2}; // Content = {0, 1, 2}, Storage = [x, 0, 1, 2] deque.pop_front(); // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] deque.push_back(3); // Content = {1, 2, 3}, Storage = [3, x, 1, 2] deque.pop_front(); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] deque.push_back(4); for (int i = 0; i < deque.size(); i++) { const auto it = deque.begin() + i; ASSERT_EQ(*(it.operator->()), static_cast(i + 1)); } } // Test that InlineDeque is trivially destructible when its type is. static_assert(std::is_trivially_destructible_v>); static_assert(std::is_trivially_destructible_v); static_assert(std::is_trivially_destructible_v>); static_assert(std::is_trivially_destructible_v); static_assert(std::is_trivially_destructible_v>); static_assert(!std::is_trivially_destructible_v); static_assert(!std::is_trivially_destructible_v>); // Generic-capacity deques cannot be constructed or destructed. static_assert(!std::is_constructible_v>); static_assert(!std::is_destructible_v>); // Tests that InlineDeque does not have any extra padding. static_assert(sizeof(InlineDeque) == sizeof(InlineDeque::size_type) * 4 + std::max(sizeof(InlineDeque::size_type), sizeof(uint8_t))); static_assert(sizeof(InlineDeque) == sizeof(InlineDeque::size_type) * 4 + 2 * sizeof(uint8_t)); static_assert(sizeof(InlineDeque) == sizeof(InlineDeque::size_type) * 4 + sizeof(uint16_t)); static_assert(sizeof(InlineDeque) == sizeof(InlineDeque::size_type) * 4 + sizeof(uint32_t)); static_assert(sizeof(InlineDeque) == sizeof(InlineDeque::size_type) * 4 + sizeof(uint64_t)); // Test that InlineDeque is copy constructible static_assert(std::is_copy_constructible_v::iterator>); // Test that InlineDeque is move constructible static_assert(std::is_move_constructible_v::iterator>); // Test that InlineDeque is copy assignable static_assert(std::is_copy_assignable_v::iterator>); static_assert(std::is_copy_assignable_v::iterator>); // Test that InlineDeque is move assignable static_assert(std::is_move_assignable_v>); static_assert(std::is_move_assignable_v>); // Test that InlineDeque::iterator can be converted to a const_iterator static_assert(std::is_convertible::iterator, InlineDeque::const_iterator>::value); static_assert(std::is_convertible::iterator, InlineDeque::const_iterator>::value); // Test that InlineDeque::const_iterator can NOT be converted to a iterator static_assert(!std::is_convertible::const_iterator, InlineDeque::iterator>::value); static_assert(!std::is_convertible::const_iterator, InlineDeque::iterator>::value); } // namespace } // namespace pw::containers