// 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_queue.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(InlineQueue, Construct_Sized) { InlineQueue queue; EXPECT_TRUE(queue.empty()); EXPECT_EQ(queue.size(), 0u); EXPECT_EQ(queue.max_size(), 3u); } TEST(InlineQueue, Construct_GenericSized) { InlineQueue sized_queue; InlineQueue& queue(sized_queue); EXPECT_TRUE(queue.empty()); EXPECT_EQ(queue.size(), 0u); EXPECT_EQ(queue.max_size(), 3u); } TEST(InlineQueue, Construct_CopySameCapacity) { InlineQueue queue(4, CopyOnly(123)); InlineQueue copied(queue); EXPECT_EQ(4u, queue.size()); EXPECT_EQ(123, queue[3].value); EXPECT_EQ(4u, copied.size()); EXPECT_EQ(123, copied[3].value); } TEST(InlineQueue, Construct_CopyLargerCapacity) { InlineQueue queue(4, CopyOnly(123)); InlineQueue copied(queue); EXPECT_EQ(4u, queue.size()); EXPECT_EQ(123, queue[3].value); EXPECT_EQ(4u, copied.size()); EXPECT_EQ(123, copied[3].value); } TEST(InlineQueue, Construct_CopySmallerCapacity) { InlineQueue queue(3, CopyOnly(123)); InlineQueue copied(queue); EXPECT_EQ(3u, queue.size()); EXPECT_EQ(123, queue[2].value); EXPECT_EQ(3u, copied.size()); EXPECT_EQ(123, copied[2].value); } TEST(InlineQueue, Construct_MoveSameCapacity) { InlineQueue queue; queue.emplace(MoveOnly(1)); queue.emplace(MoveOnly(2)); queue.emplace(MoveOnly(3)); queue.emplace(MoveOnly(4)); InlineQueue moved(std::move(queue)); // NOLINTNEXTLINE(bugprone-use-after-move) EXPECT_EQ(0u, queue.size()); ASSERT_EQ(4u, moved.size()); EXPECT_EQ(4, moved[3].value); } TEST(InlineQueue, Construct_MoveLargerCapacity) { InlineQueue queue; queue.emplace(MoveOnly(1)); queue.emplace(MoveOnly(2)); queue.emplace(MoveOnly(3)); queue.emplace(MoveOnly(4)); InlineQueue moved(std::move(queue)); // NOLINTNEXTLINE(bugprone-use-after-move) EXPECT_EQ(0u, queue.size()); ASSERT_EQ(4u, moved.size()); EXPECT_EQ(4, moved[3].value); } TEST(InlineQueue, Construct_MoveSmallerCapacity) { InlineQueue queue; queue.emplace(MoveOnly(1)); queue.emplace(MoveOnly(2)); queue.emplace(MoveOnly(3)); InlineQueue moved(std::move(queue)); // NOLINTNEXTLINE(bugprone-use-after-move) EXPECT_EQ(0u, queue.size()); ASSERT_EQ(3u, moved.size()); EXPECT_EQ(3, moved[2].value); } TEST(InlineQueue, Destruct_ZeroLength) { Counter::Reset(); { InlineQueue queue; EXPECT_EQ(queue.size(), 0u); } EXPECT_EQ(Counter::created, 0); EXPECT_EQ(Counter::destroyed, 0); } TEST(InlineQueue, Destruct_Empty) { Counter::Reset(); { InlineQueue queue; EXPECT_EQ(queue.size(), 0u); } EXPECT_EQ(Counter::created, 0); EXPECT_EQ(Counter::destroyed, 0); } TEST(InlineQueue, Destruct_MultipleEntries) { Counter value; Counter::Reset(); { InlineQueue queue(100, value); } EXPECT_EQ(Counter::created, 100); EXPECT_EQ(Counter::destroyed, 100); } TEST(InlineQueue, Assign_InitializerList) { InlineQueue queue = {1, 3, 5, 7}; EXPECT_EQ(4u, queue.size()); EXPECT_EQ(1, queue[0]); EXPECT_EQ(3, queue[1]); EXPECT_EQ(5, queue[2]); EXPECT_EQ(7, queue[3]); } TEST(InlineQueue, Assign_CopySameCapacity) { InlineQueue queue(4, CopyOnly(123)); InlineQueue copied = queue; EXPECT_EQ(4u, queue.size()); EXPECT_EQ(123, queue[3].value); EXPECT_EQ(4u, copied.size()); EXPECT_EQ(123, copied[3].value); } TEST(InlineQueue, Assign_CopyLargerCapacity) { InlineQueue queue(4, CopyOnly(123)); InlineQueue copied = queue; EXPECT_EQ(4u, queue.size()); EXPECT_EQ(123, queue[3].value); EXPECT_EQ(4u, copied.size()); EXPECT_EQ(123, copied[3].value); } TEST(InlineQueue, Assign_CopySmallerCapacity) { InlineQueue queue(3, CopyOnly(123)); InlineQueue copied = queue; EXPECT_EQ(3u, queue.size()); EXPECT_EQ(123, queue[2].value); EXPECT_EQ(3u, copied.size()); EXPECT_EQ(123, copied[2].value); } TEST(InlineQueue, Access_Iterator) { InlineQueue queue(2); for (Counter& item : queue) { EXPECT_EQ(item.value, 0); } for (const Counter& item : queue) { EXPECT_EQ(item.value, 0); } } TEST(InlineQueue, Access_ConstIterator) { const InlineQueue queue(2); for (const Counter& item : queue) { EXPECT_EQ(item.value, 0); } } TEST(InlineQueue, Access_ZeroLength) { InlineQueue queue; EXPECT_EQ(0u, queue.size()); EXPECT_EQ(0u, queue.max_size()); EXPECT_TRUE(queue.empty()); EXPECT_TRUE(queue.full()); for (Counter& item : queue) { (void)item; FAIL(); } } TEST(InlineQueue, Access_ContiguousData) { // Content = {}, Storage = [x, x] InlineQueue queue; { auto [first, second] = queue.contiguous_data(); EXPECT_EQ(first.size(), 0u); EXPECT_EQ(second.size(), 0u); } // Content = {1}, Storage = [1, x] queue.push(1); { auto [first, second] = queue.contiguous_data(); EXPECT_TRUE(Equal(first, std::array{1})); EXPECT_TRUE(Equal(second, std::array{})); } // Content = {1, 2}, Storage = [1, 2] queue.push(2); EXPECT_TRUE(queue.full()); { auto [first, second] = queue.contiguous_data(); EXPECT_TRUE(Equal(first, std::array{1, 2})); EXPECT_TRUE(Equal(second, std::array{})); } // Content = {2}, Storage = [x, 2] queue.pop(); { auto [first, second] = queue.contiguous_data(); EXPECT_TRUE(Equal(first, std::array{2})); EXPECT_TRUE(Equal(second, std::array{})); } // Content = {2, 1}, Storage = [1, 2] queue.push(1); { auto [first, second] = queue.contiguous_data(); EXPECT_TRUE(Equal(first, std::array{2})); EXPECT_TRUE(Equal(second, std::array{1})); } // Content = {1}, Storage = [1, x] queue.pop(); { auto [first, second] = queue.contiguous_data(); EXPECT_TRUE(Equal(first, std::array{1})); EXPECT_TRUE(Equal(second, std::array{})); } // Content = {1, 2}, Storage = [1, 2] queue.push(2); { auto [first, second] = queue.contiguous_data(); EXPECT_TRUE(Equal(first, std::array{1, 2})); EXPECT_TRUE(Equal(second, std::array{})); } } TEST(InlineQueue, Access_ConstContiguousData) { // Content = {1, 2}, Storage = [1, 2] const InlineQueue queue = {1, 2}; { auto [first, second] = queue.contiguous_data(); EXPECT_EQ(first.size(), 2u); EXPECT_EQ(second.size(), 0u); } } TEST(InlineQueue, Modify_Clear) { Counter::Reset(); InlineQueue queue; queue.emplace(); queue.emplace(); queue.emplace(); queue.clear(); EXPECT_EQ(3, Counter::created); EXPECT_EQ(3, Counter::destroyed); } TEST(InlineQueue, Modify_Push_Copy) { Counter value(99); Counter::Reset(); { InlineQueue queue; queue.push(value); EXPECT_EQ(queue.size(), 1u); EXPECT_EQ(queue.front().value, 99); } EXPECT_EQ(Counter::created, 1); EXPECT_EQ(Counter::destroyed, 1); } TEST(InlineQueue, Modify_Push_Move) { Counter::Reset(); { Counter value(99); InlineQueue queue; queue.push(std::move(value)); EXPECT_EQ(queue.size(), 1u); EXPECT_EQ(queue.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(InlineQueue, Modify_Emplace) { Counter::Reset(); { InlineQueue queue; queue.emplace(314); EXPECT_EQ(queue.size(), 1u); EXPECT_EQ(queue.front().value, 314); } EXPECT_EQ(Counter::created, 1); EXPECT_EQ(Counter::destroyed, 1); } TEST(InlineQueue, Modify_Overwrite) { Counter::Reset(); { InlineQueue queue(2); queue.push_overwrite(1); queue.emplace_overwrite(2); EXPECT_EQ(queue.size(), 2u); EXPECT_EQ(queue.front().value, 1); EXPECT_EQ(queue.back().value, 2); } } TEST(InlineQueue, Modify_Wrap) { Counter::Reset(); { InlineQueue queue; queue.emplace(1); queue.emplace(2); queue.emplace(3); ASSERT_EQ(queue.size(), 3u); EXPECT_EQ(queue[0].value, 1); EXPECT_EQ(queue[1].value, 2); EXPECT_EQ(queue[2].value, 3); queue.pop(); queue.emplace(4); ASSERT_EQ(queue.size(), 3u); EXPECT_EQ(queue[0].value, 2); EXPECT_EQ(queue[1].value, 3); EXPECT_EQ(queue[2].value, 4); } EXPECT_EQ(Counter::created, 4); EXPECT_EQ(Counter::destroyed, 4); } TEST(InlineQueue, Modify_Pop) { Counter::Reset(); InlineQueue queue; queue.emplace(0); queue.pop(); queue.emplace(0); queue.pop(); queue.emplace(1); // This wraps to the other end. queue.emplace(2); // This is the first entry in storage. queue.emplace(3); // Content = {1, 2, 3}, Storage = [2, 3, 1] ASSERT_EQ(queue.size(), 3u); EXPECT_EQ(queue[0].value, 1); EXPECT_EQ(queue[1].value, 2); EXPECT_EQ(queue[2].value, 3); // This wraps around queue.pop(); // Content = {2, 3}, Storage = [2, 3, x] EXPECT_EQ(queue.size(), 2u); EXPECT_EQ(queue[0].value, 2); EXPECT_EQ(queue[1].value, 3); queue.pop(); // Content = {3}, Storage = [x, 3, x] ASSERT_EQ(queue.size(), 1u); EXPECT_EQ(queue[0].value, 3); EXPECT_EQ(Counter::created, 5); EXPECT_EQ(Counter::destroyed, 4); } TEST(InlineQueue, Generic) { InlineQueue queue({1, 2, 3, 4, 5}); InlineQueue& generic_queue(queue); EXPECT_EQ(generic_queue.size(), queue.size()); EXPECT_EQ(generic_queue.max_size(), queue.max_size()); uint16_t i = 0; for (int value : queue) { EXPECT_EQ(value, generic_queue[i]); i += 1; } i = 0; for (int value : generic_queue) { EXPECT_EQ(queue[i], value); i += 1; } } TEST(InlineQueue, ConstexprMaxSize) { InlineQueue queue; constexpr size_t kMaxSize = queue.max_size(); EXPECT_EQ(queue.max_size(), kMaxSize); // Ensure the generic sized container does not have a constexpr max_size(). [[maybe_unused]] InlineQueue& generic_queue(queue); #if PW_NC_TEST(InlineQueue_GenericMaxSize_NotConstexpr) PW_NC_EXPECT_CLANG( "kGenericMaxSize.* must be initialized by a constant expression"); PW_NC_EXPECT_GCC("call to non-'constexpr' function .*InlineQueue.*max_size"); [[maybe_unused]] constexpr size_t kGenericMaxSize = generic_queue.max_size(); #endif // PW_NC_TEST } TEST(InlineQueue, StdMaxElement) { // Content = {1, 2, 3, 4}, Storage = [1, 2, 3, 4] InlineQueue queue = {1, 2, 3, 4}; auto max_element_it = std::max_element(queue.begin(), queue.end()); ASSERT_NE(max_element_it, queue.end()); EXPECT_EQ(*max_element_it, 4); // Content = {2, 3, 4, 5}, Storage = [5, 2, 3, 4] queue.push_overwrite(5); max_element_it = std::max_element(queue.begin(), queue.end()); ASSERT_NE(max_element_it, queue.end()); EXPECT_EQ(*max_element_it, 5); // Content = {3, 4, 5}, Storage = [5, x, 3, 4] queue.pop(); max_element_it = std::max_element(queue.begin(), queue.end()); ASSERT_NE(max_element_it, queue.end()); EXPECT_EQ(*max_element_it, 5); // Content = {}, Storage = [x, x, x, x] queue.clear(); max_element_it = std::max_element(queue.begin(), queue.end()); ASSERT_EQ(max_element_it, queue.end()); } TEST(InlineQueue, StdMaxElementConst) { // Content = {1, 2, 3, 4}, Storage = [1, 2, 3, 4] InlineQueue queue = {1, 2, 3, 4}; auto max_element_it = std::max_element(queue.cbegin(), queue.cend()); ASSERT_NE(max_element_it, queue.cend()); EXPECT_EQ(*max_element_it, 4); // Content = {2, 3, 4, 5}, Storage = [5, 2, 3, 4] queue.push_overwrite(5); max_element_it = std::max_element(queue.cbegin(), queue.cend()); ASSERT_NE(max_element_it, queue.cend()); EXPECT_EQ(*max_element_it, 5); // Content = {3, 4, 5}, Storage = [5, x, 3, 4] queue.pop(); max_element_it = std::max_element(queue.cbegin(), queue.cend()); ASSERT_NE(max_element_it, queue.cend()); EXPECT_EQ(*max_element_it, 5); // Content = {}, Storage = [x, x, x, x] queue.clear(); max_element_it = std::max_element(queue.cbegin(), queue.cend()); ASSERT_EQ(max_element_it, queue.cend()); } TEST(InlineQueue, OperatorPlus) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineQueue queue = {0, 0, 1, 2}; // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] queue.push_overwrite(3); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] queue.push_overwrite(4); for (int i = 0; i < 4; i++) { ASSERT_EQ(*(queue.begin() + i), static_cast(i + 1)); ASSERT_EQ(*(i + queue.begin()), static_cast(i + 1)); } ASSERT_EQ(queue.begin() + queue.size(), queue.end()); } TEST(InlineQueue, OperatorPlusPlus) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineQueue queue = {0, 0, 1, 2}; // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] queue.push_overwrite(3); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] queue.push_overwrite(4); auto it = queue.begin(); ASSERT_EQ(*it, 1); it++; ASSERT_EQ(*it, 2); it++; ASSERT_EQ(*it, 3); it++; ASSERT_EQ(*it, 4); it++; ASSERT_EQ(it, queue.end()); } TEST(InlineQueue, OperatorPlusEquals) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineQueue queue = {0, 0, 1, 2}; // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] queue.push_overwrite(3); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] queue.push_overwrite(4); auto it = queue.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, queue.end()); it = queue.begin(); ASSERT_EQ(*it, 1); it += 2; ASSERT_EQ(*it, 3); it += 2; ASSERT_EQ(it, queue.end()); it = queue.begin(); it += queue.size(); ASSERT_EQ(it, queue.end()); } TEST(InlineQueue, OpeartorMinus) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineQueue queue = {0, 0, 1, 2}; // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] queue.push_overwrite(3); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] queue.push_overwrite(4); for (int i = 1; i <= 4; i++) { ASSERT_EQ(*(queue.end() - i), static_cast(5 - i)); } ASSERT_EQ(queue.end() - queue.size(), queue.begin()); } TEST(InlineQueue, OperatorMinusMinus) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineQueue queue = {0, 0, 1, 2}; // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] queue.push_overwrite(3); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] queue.push_overwrite(4); auto it = queue.end(); it--; ASSERT_EQ(*it, 4); it--; ASSERT_EQ(*it, 3); it--; ASSERT_EQ(*it, 2); it--; ASSERT_EQ(*it, 1); ASSERT_EQ(it, queue.begin()); } TEST(InlineQueue, OperatorMinusEquals) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineQueue queue = {0, 0, 1, 2}; // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] queue.push_overwrite(3); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] queue.push_overwrite(4); auto it = queue.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, queue.begin()); it = queue.end(); it -= 2; ASSERT_EQ(*it, 3); it -= 2; ASSERT_EQ(*it, 1); ASSERT_EQ(it, queue.begin()); it = queue.end(); it -= queue.size(); ASSERT_EQ(it, queue.begin()); } TEST(InlineQueue, OperatorSquareBracket) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineQueue queue = {0, 0, 1, 2}; // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] queue.push_overwrite(3); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] queue.push_overwrite(4); for (unsigned short i = 0; i < queue.size(); i++) { ASSERT_EQ(queue.begin()[i], static_cast(i + 1)); } } TEST(InlineQueue, OperatorLessThan) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineQueue queue = {0, 0, 1, 2}; // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] queue.push_overwrite(3); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] queue.push_overwrite(4); for (int i = 0; i < queue.size(); i++) { for (int j = 0; j < i; j++) { ASSERT_TRUE((queue.begin() + j) < (queue.begin() + i)); } ASSERT_TRUE((queue.begin() + i) < queue.end()); } } TEST(InlineQueue, OperatorLessThanEqual) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineQueue queue = {0, 0, 1, 2}; // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] queue.push_overwrite(3); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] queue.push_overwrite(4); for (int i = 0; i < queue.size(); i++) { for (int j = 0; j <= i; j++) { ASSERT_TRUE((queue.begin() + j) <= (queue.begin() + i)); } ASSERT_TRUE((queue.begin() + i) <= queue.end()); } } TEST(InlineQueue, OperatorGreater) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineQueue queue = {0, 0, 1, 2}; // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] queue.push_overwrite(3); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] queue.push_overwrite(4); for (int i = 0; i < queue.size(); i++) { for (int j = i + 1; j < queue.size(); j++) { ASSERT_TRUE((queue.begin() + j) > (queue.begin() + i)); } ASSERT_TRUE(queue.end() > (queue.begin() + i)); } } TEST(InlineQueue, OperatorGreaterThanEqual) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineQueue queue = {0, 0, 1, 2}; // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] queue.push_overwrite(3); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] queue.push_overwrite(4); for (int i = 0; i < queue.size(); i++) { for (int j = i; j < queue.size(); j++) { ASSERT_TRUE((queue.begin() + j) >= (queue.begin() + i)); } ASSERT_TRUE(queue.end() >= (queue.begin() + i)); } } TEST(InlineQueue, DereferenceOperator) { // Content = {0, 0, 1, 2}, Storage = [0, 0, 1, 2] InlineQueue queue = {0, 0, 1, 2}; // Content = {0, 1, 2, 3}, Storage = [3, 0, 1, 2] queue.push_overwrite(3); // Content = {1, 2, 3, 4}, Storage = [3, 4, 1, 2] queue.push_overwrite(4); for (int i = 0; i < queue.size(); i++) { const auto it = queue.begin() + i; ASSERT_EQ(*(it.operator->()), static_cast(i + 1)); } } // Test that InlineQueue 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 queues cannot be constructed or destructed. static_assert(!std::is_constructible_v>); static_assert(!std::is_destructible_v>); // Tests that InlineQueue does not have any extra padding. static_assert(sizeof(InlineQueue) == sizeof(InlineQueue::size_type) * 4 + std::max(sizeof(InlineQueue::size_type), sizeof(uint8_t))); static_assert(sizeof(InlineQueue) == sizeof(InlineQueue::size_type) * 4 + 2 * sizeof(uint8_t)); static_assert(sizeof(InlineQueue) == sizeof(InlineQueue::size_type) * 4 + sizeof(uint16_t)); static_assert(sizeof(InlineQueue) == sizeof(InlineQueue::size_type) * 4 + sizeof(uint32_t)); static_assert(sizeof(InlineQueue) == sizeof(InlineQueue::size_type) * 4 + sizeof(uint64_t)); // Test that InlineQueue is copy assignable static_assert(std::is_copy_assignable_v::iterator>); static_assert(std::is_copy_assignable_v::iterator>); // Test that InlineQueue::iterator can be converted to a const_iterator static_assert(std::is_convertible::iterator, InlineQueue::const_iterator>::value); static_assert(std::is_convertible::iterator, InlineQueue::const_iterator>::value); // Test that InlineQueue::const_iterator can NOT be converted to a iterator static_assert(!std::is_convertible::const_iterator, InlineQueue::iterator>::value); static_assert(!std::is_convertible::const_iterator, InlineQueue::iterator>::value); } // namespace } // namespace pw::containers