Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
deque.hpp
Go to the documentation of this file.
1// Copyright 2026, Toyota Motor Corporation
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_INLINE_CONTAINER_TESTING_DEQUE_HPP_
6#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_INLINE_CONTAINER_TESTING_DEQUE_HPP_
7
8#include <gtest/gtest.h>
9
10#include "arene/base/algorithm/equal.hpp"
11#include "arene/base/array/array.hpp"
12#include "arene/base/compiler_support/diagnostics.hpp"
13#include "arene/base/constraints/constraints.hpp"
14#include "arene/base/inline_container/deque.hpp"
15#include "arene/base/inline_container/testing/customization.hpp"
16#include "arene/base/iterator/distance.hpp"
17#include "arene/base/iterator/next.hpp"
18#include "arene/base/stdlib_choice/addressof.hpp"
19#include "arene/base/stdlib_choice/conditional.hpp"
20#include "arene/base/stdlib_choice/cstddef.hpp"
21#include "arene/base/stdlib_choice/declval.hpp"
22#include "arene/base/stdlib_choice/forward.hpp"
23#include "arene/base/stdlib_choice/ignore.hpp"
24#include "arene/base/stdlib_choice/initializer_list.hpp"
25#include "arene/base/stdlib_choice/integer_sequence.hpp"
26#include "arene/base/stdlib_choice/is_assignable.hpp"
27#include "arene/base/stdlib_choice/is_constructible.hpp"
28#include "arene/base/stdlib_choice/is_copy_assignable.hpp"
29#include "arene/base/stdlib_choice/is_copy_constructible.hpp"
30#include "arene/base/stdlib_choice/is_default_constructible.hpp"
31#include "arene/base/stdlib_choice/is_move_assignable.hpp"
32#include "arene/base/stdlib_choice/is_move_constructible.hpp"
33#include "arene/base/stdlib_choice/is_trivially_copyable.hpp"
34#include "arene/base/stdlib_choice/iterator_tags.hpp"
35#include "arene/base/stdlib_choice/move.hpp"
36#include "arene/base/stdlib_choice/numeric_limits.hpp"
37#include "arene/base/testing/gtest.hpp"
38#include "arene/base/type_traits/is_copyable.hpp"
39#include "arene/base/type_traits/is_implicitly_constructible.hpp"
40#include "arene/base/type_traits/is_invocable.hpp"
41#include "arene/base/type_traits/is_movable.hpp"
42#include "arene/base/type_traits/iterator_category_traits.hpp"
43#include "testlibs/utilities/iterator_types.hpp"
44#include "testlibs/utilities/throws_on.hpp"
45
46namespace arene {
47namespace base {
48namespace testing {
49
51ARENE_IGNORE_ALL("-Wfloat-equal", "These tests don't perform arithmetic, so equality is OK even for floating point");
52
53/// @brief Create a test deque containing a range of test values
54/// @tparam T The deque type to create an instance of
55/// @param begin The first index of test value to put in the deque
56/// @param end The after-end index of test value to put in the deque
57/// @return An inline_deque<T, Capacity> containing [test_value(begin), test_value(end))
58template <typename T>
59constexpr auto test_deque(std::size_t begin, std::size_t end) noexcept(
61) -> T {
62 T deque;
63 for (std::size_t i = begin; i < end; i++) {
64 deque.push_back(test_value<typename T::value_type>(i));
65 }
66 return deque;
67}
68
69/// @brief A type trait to check if a type is list-initializable using a brace-enclosed list of values with a given type
70/// @tparam T Type to check
71/// @tparam ElementType Type to use for the elements of the brace-enclosed initializer list
72/// @{
73template <typename T, typename ElementType, typename = constraints<>>
74constexpr bool is_list_initializable_v{false};
75
76template <typename T, typename ElementType>
77constexpr bool is_list_initializable_v<
78 T,
80 constraints<decltype(T{std::declval<ElementType&>(), std::declval<ElementType&>()})>>{true};
81/// @}
82
83/////////////////////////
84// Parameterized tests //
85/////////////////////////
86
87/// @brief Test fixture for all type-parameterized @c inline_deque tests
88/// @tparam Deque The type parameter currently being used for tests; filled in by Google Test as @c TypeParam
89template <typename Deque>
90class InlineDequeTest : public ::testing::Test {
91 using T = typename Deque::value_type;
92
93 public:
94 /// @brief Whether the type parameter is constexpr compatible for this test
95 static constexpr bool constexpr_compatible =
97 static_assert(
99 "Constexpr-compatible types must have constexpr specializations of test_value_array or test_value"
100 );
101
102 protected:
103 /// @brief Return the @c idx 'th test value of the current @c T , parameterized by test suite users
104 /// @param idx The index of the test value to get
105 /// @return The @c idx 'th test value of the current @c T
106 static constexpr auto test_value(std::size_t idx) noexcept(noexcept(::arene::base::testing::test_value<T>(idx)))
107 -> decltype(::arene::base::testing::test_value<T>(idx)) {
108 return ::arene::base::testing::test_value<T>(idx);
109 }
110
111 /// @brief Return an empty @c Deque, allowing to call as this->construct,
112 /// which becomes useful with the ...STATIC_ASSERT... macros
113 static constexpr auto construct() noexcept(noexcept(Deque())) -> Deque { return Deque(); }
114
115 /// @brief Return a @c Deque containing the test values @c [begin,end) of @c T
116 /// @param begin The index of the first test value to put into the test deque
117 /// @param end The index after that of the last test value to put into the test deque
118 /// @return A test deque holding the test values determined by the indices
119 static constexpr auto test_deque(std::size_t begin, std::size_t end) noexcept(
120 noexcept(::arene::base::testing::test_deque<Deque>(begin, end))
121 ) -> Deque {
122 return ::arene::base::testing::test_deque<Deque>(begin, end);
123 }
124
125 /// @brief Return a @c Deque containing the test values @c [0,size) of @c T
126 /// @param size The number of test values to put into the test deque
127 /// @return A test deque holding the test values determined by the size
128 static constexpr auto test_deque(std::size_t size) noexcept(noexcept(test_deque(0, size))) -> Deque {
129 return test_deque(0, size);
130 }
131
132 /// @brief Return a @c Deque containing the test values @c [0,capacity/2) of @c T
133 /// @return A test deque holding the test values determined by the capacity
134 static constexpr auto half_test_deque() noexcept(noexcept(test_deque(Deque::capacity))) -> Deque {
135 return test_deque(Deque::capacity / 2U);
136 }
137
138 /// @brief Return a @c Deque containing the test values @c [0,capacity) of @c T
139 /// @return A test deque holding the test values determined by the capacity
140 static constexpr auto full_test_deque() noexcept(noexcept(test_deque(Deque::capacity))) -> Deque {
141 return test_deque(Deque::capacity);
142 }
143
144 /// @brief Return a @c Deque containing the test values <c>[capacity/2, 3*capacity/2)<c> of @c T
145 /// @return A test deque holding the test values, wrapped around so they start in the middle
146 /// @note This is useful for testing that functions aren't accidentally assuming the data starts at buffer index 0
147 static constexpr auto wrapped_test_deque() noexcept(noexcept(test_deque(Deque::capacity))) -> Deque {
148 Deque deque = test_deque(Deque::capacity);
149 for (std::size_t i{}; i < Deque::capacity / 2U; ++i) {
150 deque.pop_front();
151 deque.push_back(::arene::base::testing::test_value<T>(Deque::capacity + i));
152 }
153 return deque;
154 }
155
156 /// @brief Return a @c std::initializer_list containing user-parameterized <c>test_value</c>s
157 /// @tparam Indices A pack of indices, one for each test value in the initializer list
158 /// @return A copy of a statically-allocated @c std::initializer_list<T> containing one test value per index
159 template <std::size_t... Indices>
160 static constexpr auto test_initializer_list(std::index_sequence<Indices...>) noexcept -> std::initializer_list<T> {
161 return ::arene::base::testing::test_initializer_list<T, Indices...>();
162 }
163
164 /// @brief Return a @c std::initializer_list containing user-parameterized <c>test_value</c>s
165 /// @tparam Size The number of values in the @c std::initializer_list
166 /// @return A copy of a statically-allocated @c std::initializer_list<T> containing one test value per index
167 template <std::size_t Size>
168 static constexpr auto test_initializer_list() noexcept -> std::initializer_list<T> {
169 return test_initializer_list(std::make_index_sequence<Size>{});
170 }
171
172 /// @brief Return a @c std::initializer_list containing @c Deque::capacity user-parameterized <c>test_value</c>s
173 /// @return A copy of a statically-allocated @c std::initializer_list<T> containing @c Deque::capacity entries
174 static constexpr auto full_test_initializer_list() noexcept -> std::initializer_list<T> {
175 return test_initializer_list<Deque::capacity>();
176 }
177};
178
179/// @brief The death tests use the same fixture as the non-death tests, but as a distinct type to improve log output
180/// @tparam Deque The @c inline_deque type to test
181template <typename Deque>
182class InlineDequeDeathTest : public InlineDequeTest<Deque> {};
183
184/// @brief Type trait to see if a particular @c TypeParam is double-ended or not; used to exclude some tests
185/// @tparam TypeParam The queue/deque type to check
186/// @note This implementation works kind of by coincidence, because currently the only queue with wrapping allowed
187/// happens to be single-ended. There's no inherent relationship between wrapping being allowed and being double-ended.
188template <typename TypeParam>
190
191// Declare the test suite(s) where test cases will be added.
194
195/// @test A default-constructed `inline_deque` has size equal to zero
196TYPED_TEST_P(InlineDequeTest, CanConstruct) {
197 TypeParam const deque;
198 EXPECT_EQ(deque.size(), 0);
199
200 auto maybe_deque = TypeParam::try_construct();
201 ASSERT_TRUE(maybe_deque.has_value());
202 EXPECT_EQ(maybe_deque->size(), 0);
203}
204
205/// @test The capacity of a default-constructed `inline_deque` is equal to the supplied template parameter
207 COND_STATIC_ASSERT_EQ(TestFixture::construct().capacity(), TypeParam::capacity);
208}
209
210/// @test The `capacity` member function of `inline_deque` is declared `noexcept`
211TYPED_TEST_P(InlineDequeTest, CapacityIsNoexcept) { STATIC_ASSERT_TRUE(noexcept(TestFixture::construct().capacity())); }
212
213/// @test The `size` member function of `inline_deque` is declared `noexcept`
214TYPED_TEST_P(InlineDequeTest, SizeIsNoexcept) { STATIC_ASSERT_TRUE(noexcept(TestFixture::construct().size())); }
215
216/// @test Given a default-constructed `inline_deque` with plenty of capacity,
217/// an element can be inserted via `push_front`, which causes a size increase
219 TypeParam deque;
220 deque.push_front(TestFixture::test_value(0));
221 EXPECT_EQ(deque.size(), 1);
222}
223
224/// @test Given a default-constructed `inline_deque` with plenty of capacity,
225/// an element can be inserted via `push_back`, which causes a size increase
227 TypeParam deque;
228 deque.push_back(TestFixture::test_value(0));
229 EXPECT_EQ(deque.size(), 1);
230}
231
232/// @test Emplacing an element into the front of an `inline_deque` returns a reference to the emplaced element
234 TypeParam deque;
235 auto& front_ref = deque.emplace_front(TestFixture::test_value(0));
236 EXPECT_EQ(std::addressof(front_ref), std::addressof(deque.front()));
237}
238
239/// @test Emplacing an element into the back of an `inline_deque` returns a reference to the emplaced element
241 TypeParam deque;
242 auto& back_ref = deque.emplace_back(TestFixture::test_value(0));
243 EXPECT_EQ(std::addressof(back_ref), std::addressof(deque.back()));
244}
245
246/// @test Given a default-constructed `inline_deque` with plenty of capacity,
247/// an element can be inserted via `push_front` and then inspected
249 TypeParam deque;
250 deque.push_front(TestFixture::test_value(0));
251 ASSERT_EQ(deque.size(), 1);
252 EXPECT_EQ(deque.front(), TestFixture::test_value(0));
253 EXPECT_EQ(deque.back(), TestFixture::test_value(0));
254
255 TypeParam const& as_const(deque);
256 EXPECT_EQ(as_const.front(), TestFixture::test_value(0));
257 EXPECT_EQ(as_const.back(), TestFixture::test_value(0));
258}
259
260/// @test Given a default-constructed `inline_deque` with plenty of capacity,
261/// an element can be inserted via `push_back` and then inspected
263 TypeParam deque;
264 deque.push_back(TestFixture::test_value(0));
265 ASSERT_EQ(deque.size(), 1);
266 EXPECT_EQ(deque.back(), TestFixture::test_value(0));
267 EXPECT_EQ(deque.front(), TestFixture::test_value(0));
268
269 TypeParam const& as_const(deque);
270 EXPECT_EQ(as_const.back(), TestFixture::test_value(0));
271 EXPECT_EQ(as_const.front(), TestFixture::test_value(0));
272}
273
274/// @test Given a default-constructed `inline_deque`, elements can be inserted
275/// via `push_front` within its capacity, making the size be equal to capacity
277 TypeParam deque;
278 for (typename TypeParam::size_type i = 0; i < TypeParam::capacity(); i++) {
279 deque.push_front(TestFixture::test_value(i));
280 }
281 EXPECT_EQ(deque.size(), TypeParam::capacity());
282}
283
284/// @test Given a default-constructed `inline_deque`, elements can be inserted
285/// via `push_back` within its capacity, making the size be equal to capacity
287 TypeParam deque;
288 for (typename TypeParam::size_type i = 0; i < TypeParam::capacity(); i++) {
289 deque.push_back(TestFixture::test_value(i));
290 }
291 EXPECT_EQ(deque.size(), TypeParam::capacity());
292}
293
294/// @test Inserting any element beyond an `inline_deque`'s capacity terminates
295/// the application with a precondition violation or wraps, depending on its parameters
297 TypeParam deque;
298 for (typename TypeParam::size_type i = 0; i < TypeParam::capacity(); i++) {
299 deque.push_front(TestFixture::test_value(i));
300 }
301
302 ASSERT_DEATH(deque.push_front(TestFixture::test_value(TypeParam::capacity())), "Precondition violation");
303}
304
305/// @test For deques with a single-ended public interface, the unexposed functions in the other direction still work.
306/// This test is needed for coverage purposes.
308 using deque_impl = arene::base::inline_deque_detail::inline_deque_impl< //
309 typename TypeParam::value_type, //
310 TypeParam::capacity(), //
311 TypeParam::wrapping_allowed //
312 >;
313
314 deque_impl deque;
315 for (typename TypeParam::size_type i = 0; i < TypeParam::capacity(); i++) {
316 deque.push_front(TestFixture::test_value(i));
317 }
318
319 if (deque.wrapping_allowed()) {
320 EXPECT_EQ(deque.front(), TestFixture::test_value(TypeParam::capacity() - 1U));
321 EXPECT_EQ(deque.back(), TestFixture::test_value(0));
322 deque.push_front(TestFixture::test_value(TypeParam::capacity()));
323 EXPECT_EQ(deque.front(), TestFixture::test_value(TypeParam::capacity()));
324 EXPECT_EQ(deque.back(), TestFixture::test_value(1));
325 } else {
326 ASSERT_DEATH(deque.push_front(TestFixture::test_value(TypeParam::capacity())), "Precondition violation");
327 }
328}
329
330/// @test Inserting any element beyond an `inline_deque`'s capacity terminates
331/// the application with a precondition violation or wraps, depending on its parameters
333 TypeParam deque;
334 for (typename TypeParam::size_type i = 0; i < TypeParam::capacity(); i++) {
335 deque.push_back(TestFixture::test_value(i));
336 }
337
338 if (deque.wrapping_allowed()) {
339 EXPECT_EQ(deque.back(), TestFixture::test_value(TypeParam::capacity() - 1U));
340 EXPECT_EQ(deque.front(), TestFixture::test_value(0));
341 deque.push_back(TestFixture::test_value(TypeParam::capacity()));
342 EXPECT_EQ(deque.back(), TestFixture::test_value(TypeParam::capacity()));
343 EXPECT_EQ(deque.front(), TestFixture::test_value(1));
344 } else {
345 ASSERT_DEATH(deque.push_back(TestFixture::test_value(TypeParam::capacity())), "Precondition violation");
346 }
347}
348
349/// @test The constraints and exception specifications for the `insert` functions are correct
351 using value_type = typename TypeParam::value_type;
352
353 auto inserter = [](auto& deque,
354 auto&& value) noexcept(noexcept(deque.insert(deque.begin(), std::forward<decltype(value)>(value)))
355 ) -> decltype(deque.insert(deque.begin(), std::forward<decltype(value)>(value))) { return {}; };
356
357 constexpr bool shift_ok = std::is_move_assignable<value_type>::value && std::is_move_constructible<value_type>::value;
358 constexpr bool copy_insert_ok = shift_ok && std::is_copy_assignable<value_type>::value;
359 constexpr bool move_insert_ok = shift_ok;
360
361 STATIC_ASSERT_EQ((arene::base::is_invocable_v<decltype(inserter), TypeParam&, value_type const&>), copy_insert_ok);
362 STATIC_ASSERT_EQ((arene::base::is_invocable_v<decltype(inserter), TypeParam&, value_type&&>), move_insert_ok);
363
364 constexpr bool shift_noexcept =
365 std::is_nothrow_move_constructible<value_type>::value && std::is_nothrow_move_assignable<value_type>::value;
366 constexpr bool copy_insert_noexcept =
367 copy_insert_ok && shift_noexcept && std::is_nothrow_copy_constructible<value_type>::value;
368 constexpr bool move_insert_noexcept = move_insert_ok && shift_noexcept;
369
370 STATIC_ASSERT_EQ(
371 (arene::base::is_nothrow_invocable_v<decltype(inserter), TypeParam&, value_type const&>),
372 copy_insert_noexcept
373 );
374 STATIC_ASSERT_EQ(
375 (arene::base::is_nothrow_invocable_v<decltype(inserter), TypeParam&, value_type&&>),
376 move_insert_noexcept
377 );
378}
379
380/// @test The copy-based one-element version of `insert` inserts a copy of the value at the requested position
382 InlineDequeTest,
386) {
387 using index_type = typename TypeParam::iterator::difference_type;
388
389 TypeParam deque = TestFixture::half_test_deque();
390 for (typename TypeParam::size_type i = 0U; i < TypeParam::capacity() / 2U; ++i) {
391 // We need a new iterator every time because insert() invalidates all iterators. Each prior index has two entries.
392 auto const pos = next(deque.cbegin(), static_cast<index_type>(2U * i));
393
394 typename TypeParam::value_type const new_value = TestFixture::test_value((TypeParam::capacity() / 2U) + i);
395 auto new_iter = deque.insert(pos, new_value);
396
397 // The new iterator should have the same distance from `begin()` as `pos`, even though `pos` is now invalid.
398 EXPECT_EQ(distance(deque.begin(), new_iter), static_cast<index_type>(2U * i));
399 }
400
401 for (typename TypeParam::size_type i = 0U; i < TypeParam::capacity() / 2U; ++i) {
402 EXPECT_EQ(deque[static_cast<index_type>(2U * i)], TestFixture::test_value(TypeParam::capacity() / 2U + i));
403 EXPECT_EQ(deque[static_cast<index_type>((2U * i) + 1U)], TestFixture::test_value(i));
404 }
405}
406
407/// @test The move-based one-element version of `insert` inserts the value at the requested position
409 InlineDequeTest,
413) {
414 using index_type = typename TypeParam::iterator::difference_type;
415
416 TypeParam deque = TestFixture::half_test_deque();
417 for (typename TypeParam::size_type i = 0U; i < TypeParam::capacity() / 2U; ++i) {
418 // We need a new iterator every time because insert() invalidates all iterators. Each prior index has two entries.
419 auto const pos = next(deque.cbegin(), static_cast<index_type>(2U * i));
420
421 deque.insert(pos, TestFixture::test_value((TypeParam::capacity() / 2U) + i));
422 }
423
424 for (typename TypeParam::size_type i = 0U; i < TypeParam::capacity() / 2U; ++i) {
425 EXPECT_EQ(deque[static_cast<index_type>(2U * i)], TestFixture::test_value(TypeParam::capacity() / 2U + i));
426 EXPECT_EQ(deque[static_cast<index_type>((2U * i) + 1U)], TestFixture::test_value(i));
427 }
428}
429
430/// @test The copy-based one-element version of `insert` can insert a value at the end
432 InlineDequeTest,
436) {
437 typename TypeParam::value_type const value = TestFixture::test_value(TypeParam::capacity() / 2U);
438
439 TypeParam deque = TestFixture::half_test_deque();
440 typename TypeParam::size_type expected_size = deque.size();
441
442 if (deque.size() == deque.capacity()) {
443 deque.pop_front();
444 } else {
445 ++expected_size;
446 }
447 deque.insert(deque.cend(), value);
448 EXPECT_EQ(deque.size(), expected_size);
449 EXPECT_EQ(deque.back(), value);
450}
451
452/// @test The move-based one-element version of `insert` can insert a value at the end
454 InlineDequeTest,
458) {
459 typename TypeParam::value_type const value = TestFixture::test_value(TypeParam::capacity() / 2U);
460 typename TypeParam::value_type value_again = TestFixture::test_value(TypeParam::capacity() / 2U);
461
462 TypeParam deque = TestFixture::half_test_deque();
463 typename TypeParam::size_type expected_size = deque.size();
464
465 if (deque.size() == deque.capacity()) {
466 deque.pop_front();
467 } else {
468 ++expected_size;
469 }
470 deque.insert(deque.cend(), std::move(value_again));
471 EXPECT_EQ(deque.size(), expected_size);
472 EXPECT_EQ(deque.back(), value);
473}
474
475/// @test Calling the one-element version of `insert` when a non-wrapping deque is full terminates the application
477 InlineDequeDeathTest,
481) {
482 TypeParam deque = TestFixture::full_test_deque();
483
484 auto pos = next(deque.begin());
485 for (typename TypeParam::size_type i{0U}; i <= deque.capacity(); ++i) {
486 ASSERT_DEATH(deque.insert(pos, TestFixture::test_value(TypeParam::capacity() + i)), "Precondition violation");
487 ++pos;
488 }
489}
490
491/// @test `inline_deque` has circular or ring-buffer behavior, such that when
492/// previously inserted elements via `push_front` are removed via `pop_back`,
493/// then space in the fixed-capacity storage of the deque is made available
494/// for new elements to be inserted
496 TypeParam deque;
497 for (std::size_t i = 0; i < 2 * TypeParam::capacity(); i++) {
498 deque.push_front(TestFixture::test_value(i));
499 EXPECT_EQ(deque.back(), TestFixture::test_value(i));
500 deque.pop_back();
501 }
502}
503
504/// @test `inline_deque` has circular or ring-buffer behavior, such that when
505/// previously inserted elements via `push_back` are removed via `pop_front`,
506/// then space in the fixed-capacity storage of the deque is made available
507/// for new elements to be inserted
509 TypeParam deque;
510 for (std::size_t i = 0; i < 2 * TypeParam::capacity(); i++) {
511 deque.push_back(TestFixture::test_value(i));
512 EXPECT_EQ(deque.front(), TestFixture::test_value(i));
513 deque.pop_front();
514 }
515}
516
517/// @test basic `inline_deque` functionality, inserting elements via
518/// `push_front` observing them with `back`, verifying that it doesn't remove
519/// elements, removing with `pop_back`, and checking the correct dequeing order
520/// (namely, FIFO) is preserved with the operations
522 InlineDequeTest,
525) {
526 TypeParam deque;
527 // Push an element and check it.
528 deque.push_front(TestFixture::test_value(0));
529 EXPECT_EQ(deque.back(), TestFixture::test_value(0));
530 // Check that the element is still there after observing it.
531 EXPECT_EQ(deque.back(), TestFixture::test_value(0));
532 // Push a second element.
533 deque.push_front(TestFixture::test_value(1));
534 EXPECT_EQ(deque.size(), 2);
535 // Check that the first pushed element is still "at the back".
536 EXPECT_EQ(deque.back(), TestFixture::test_value(0));
537 deque.pop_back();
538 EXPECT_EQ(deque.back(), TestFixture::test_value(1));
539 EXPECT_EQ(deque.size(), 1);
540}
541
542/// @test basic `inline_deque` functionality, inserting elements via
543/// `push_back` observing them with `front`, verifying that it doesn't remove
544/// elements, removing with `pop_front`, and checking the correct dequeing order
545/// (namely, FIFO) is preserved with the operations
547 TypeParam deque;
548 // Push an element and check it.
549 deque.push_back(TestFixture::test_value(0));
550 EXPECT_EQ(deque.front(), TestFixture::test_value(0));
551 // Check that the element is still there after observing it.
552 EXPECT_EQ(deque.front(), TestFixture::test_value(0));
553 // Push a second element.
554 deque.push_back(TestFixture::test_value(1));
555 EXPECT_EQ(deque.size(), 2);
556 // Check that the first pushed element is still "at the back".
557 EXPECT_EQ(deque.front(), TestFixture::test_value(0));
558 deque.pop_front();
559 EXPECT_EQ(deque.front(), TestFixture::test_value(1));
560 EXPECT_EQ(deque.size(), 1);
561}
562
563/// @test `inline_deque`'s `back` can also be used to modify the least-recently
564/// inserted element inplace
566 InlineDequeTest,
569) {
570 TypeParam deque;
571 deque.push_front(TestFixture::test_value(0));
572 deque.push_front(TestFixture::test_value(1));
573 EXPECT_EQ(deque.back(), TestFixture::test_value(0));
574 deque.back() = TestFixture::test_value(2);
575 EXPECT_EQ(deque.back(), TestFixture::test_value(2));
576 EXPECT_EQ(deque.size(), 2);
577 deque.pop_back();
578 EXPECT_EQ(deque.back(), TestFixture::test_value(1));
579}
580
581/// @test `inline_deque`'s `front` can also be used to modify the least-recently
582/// inserted element inplace
584 TypeParam deque;
585 deque.push_back(TestFixture::test_value(0));
586 deque.push_back(TestFixture::test_value(1));
587 EXPECT_EQ(deque.front(), TestFixture::test_value(0));
588 deque.front() = TestFixture::test_value(2);
589 EXPECT_EQ(deque.front(), TestFixture::test_value(2));
590 EXPECT_EQ(deque.size(), 2);
591 deque.pop_front();
592 EXPECT_EQ(deque.front(), TestFixture::test_value(1));
593}
594
595/// @test Pushing lvalue data onto the front of an `inline_deque` copies it
597 InlineDequeTest,
600) {
601 auto deque = TestFixture::construct();
602 auto const value = TestFixture::test_value(0);
603 deque.push_front(value);
604 EXPECT_EQ(deque.front(), value);
605 EXPECT_NE(std::addressof(deque.front()), std::addressof(value));
606}
607
608/// @test Pushing lvalue data onto the back of an `inline_deque` copies it
609CONDITIONAL_TYPED_TEST_P(InlineDequeTest, PushBackCopiesLvalues, std::is_copy_constructible<TypeParam>::value) {
610 auto deque = TestFixture::construct();
611 auto const value = TestFixture::test_value(0);
612 deque.push_back(value);
613 EXPECT_EQ(deque.back(), value);
614 EXPECT_NE(std::addressof(deque.back()), std::addressof(value));
615}
616
617/// @test when the `inline_deque` is empty, `back` terminates the application with a precondition violation
618TYPED_TEST_P(InlineDequeDeathTest, BackWhenEmpty) {
619 TypeParam deque;
620 ASSERT_DEATH(deque.back(), "Precondition violation");
621}
622
623/// @test when the `inline_deque` is empty, the `const` overload of `back` terminates the application with
624/// a precondition violation
625TYPED_TEST_P(InlineDequeDeathTest, ConstBackWhenEmpty) {
626 TypeParam const deque;
627 ASSERT_DEATH(deque.back(), "Precondition violation");
628}
629
630/// @test when the `inline_deque` is empty, `pop_front` terminates the application with a precondition violation
631TYPED_TEST_P(InlineDequeDeathTest, PopFrontWhenEmpty) {
632 TypeParam deque;
633 ASSERT_DEATH(deque.pop_front(), "Precondition violation");
634}
635
636/// @test when the `inline_deque` is empty, `pop_back` terminates the application with a precondition violation
638 TypeParam deque;
639 ASSERT_DEATH(deque.pop_back(), "Precondition violation");
640}
641
642/// @test when the `inline_deque` is empty, `front` terminates the application with a precondition violation
643TYPED_TEST_P(InlineDequeDeathTest, FrontWhenEmpty) {
644 TypeParam deque;
645 ASSERT_DEATH(deque.front(), "Precondition violation");
646}
647
648/// @test when the `inline_deque` is empty, the `const` overload of `front` terminates the application with
649/// a precondition violation
650TYPED_TEST_P(InlineDequeDeathTest, ConstFrontWhenEmpty) {
651 TypeParam const deque;
652 ASSERT_DEATH(deque.front(), "Precondition violation");
653}
654
655/// @test `inline_deque` is not copy-constructible if the data type is not copy-constructible
657 constexpr bool copy_ok = std::is_copy_constructible<typename TypeParam::value_type>::value;
658 static_assert(
659 (std::is_constructible<TypeParam, TypeParam const&>::value) == copy_ok,
660 "inline_deque<T> should be copy-constructible if and only if T is"
661 );
662}
663
664/// @test `inline_deque` is not move-constructible if the data type is not move-constructible
666 constexpr bool move_ok = std::is_move_constructible<typename TypeParam::value_type>::value;
667 static_assert(
668 (std::is_constructible<TypeParam, TypeParam&&>::value) == move_ok,
669 "inline_deque<T> should be move-constructible if and only if T is"
670 );
671}
672
673/// @test `inline_deque` is not copy-assignable if the data type is not copy-constructible
675 static_assert(
676 (std::is_assignable<TypeParam, TypeParam const&>::value) == arene::base::is_copyable_v<TypeParam>,
677 "inline_deque<T> should be copy-assignable if and only if T is copy-constructible and -assignable"
678 );
679}
680
681/// @test `inline_deque` is not move-assignable if the data type is not move-constructible
683 static_assert(
684 (std::is_assignable<TypeParam, TypeParam&&>::value) == arene::base::is_movable_v<TypeParam>,
685 "inline_deque<T> should be move-assignable if and only if T is move-constructible and -assignable"
686 );
687}
688
689/// @test `inline_deque` can be used at compile-time, asserting properties statically
691 constexpr auto deque = TestFixture::full_test_deque();
692 STATIC_ASSERT_EQ(deque.size(), deque.capacity());
693 STATIC_ASSERT_EQ(deque.front(), TestFixture::test_value(0));
694 STATIC_ASSERT_EQ(deque.back(), TestFixture::test_value(deque.size() - 1U));
695}
696
697/// @test `inline_deque` range construction is enabled or disabled appropriately based on the arguments
699 using random_access_it = typename TypeParam::value_type const*;
700 using bidirectional_it = ::testing::demoted_iterator<random_access_it, std::bidirectional_iterator_tag>;
701 using forward_it = ::testing::demoted_iterator<random_access_it, std::forward_iterator_tag>;
702 using input_it = ::testing::demoted_iterator<random_access_it, std::input_iterator_tag>;
703
704 STATIC_ASSERT_EQ(
705 (std::is_constructible<TypeParam, random_access_it, random_access_it>::value),
706 std::is_copy_constructible<typename TypeParam::value_type>::value
707 );
708 STATIC_ASSERT_EQ(
709 (std::is_constructible<TypeParam, bidirectional_it, bidirectional_it>::value),
710 std::is_copy_constructible<typename TypeParam::value_type>::value
711 );
712 STATIC_ASSERT_EQ(
713 (std::is_constructible<TypeParam, forward_it, forward_it>::value),
714 std::is_copy_constructible<typename TypeParam::value_type>::value
715 );
716 STATIC_ASSERT_FALSE(std::is_constructible<TypeParam, input_it, input_it>::value);
717}
718
719/// @test `inline_deque` range construction has the correct noexcept specification
721 using ::testing::throws_on;
722 using value_type = typename TypeParam::value_type;
723
724 using normal_it = ::testing::noexcept_configurable_random_access_iterator<throws_on::nothing, value_type>;
725 using rvalue_it = testing::rvalue_iterator<value_type>;
726 using throwing_it = ::testing::noexcept_configurable_random_access_iterator<throws_on::minus_self, value_type>;
727
728 STATIC_ASSERT_EQ(
729 (std::is_nothrow_constructible<TypeParam, normal_it, normal_it>::value),
730 std::is_nothrow_copy_constructible<value_type>::value
731 );
732 STATIC_ASSERT_EQ(
733 (std::is_nothrow_constructible<TypeParam, rvalue_it, rvalue_it>::value),
734 std::is_nothrow_move_constructible<value_type>::value
735 );
736 STATIC_ASSERT_FALSE(std::is_nothrow_constructible<TypeParam, throwing_it, throwing_it>::value);
737}
738
739/// @test `inline_deque` can be constructed from a range of `T` using iterators
740CONDITIONAL_TYPED_TEST_P(InlineDequeTest, CopyConstructFromRange, std::is_copy_constructible<TypeParam>::value) {
741 auto const init_list = TestFixture::full_test_initializer_list();
742 TypeParam const deque(init_list.begin(), init_list.end());
743
744 ASSERT_EQ(deque.size(), init_list.size());
745 EXPECT_TRUE(::arene::base::equal(deque.begin(), deque.end(), init_list.begin()));
746
747 auto const try_deque = TypeParam::try_construct(init_list.begin(), init_list.end());
748 ASSERT_TRUE(try_deque.has_value());
749 EXPECT_TRUE(::arene::base::equal(try_deque->begin(), try_deque->end(), init_list.begin()));
750}
751
752/// @test `inline_deque` can be constructed from a range of `T` using iterators
754 TypeParam const deque(
755 arene::base::testing::rvalue_iterator<typename TypeParam::value_type>(0),
756 arene::base::testing::rvalue_iterator<typename TypeParam::value_type>(TypeParam::capacity())
757 );
758
759 // Make an initializer list here just to make it easier to compare the contents
760 auto const init_list = TestFixture::full_test_initializer_list();
761 ASSERT_EQ(deque.size(), init_list.size());
762 EXPECT_TRUE(::arene::base::equal(deque.begin(), deque.end(), init_list.begin()));
763
764 auto const try_deque = TypeParam::try_construct(
765 arene::base::testing::rvalue_iterator<typename TypeParam::value_type>(0),
766 arene::base::testing::rvalue_iterator<typename TypeParam::value_type>(TypeParam::capacity())
767 );
768 ASSERT_TRUE(try_deque.has_value());
769 EXPECT_TRUE(::arene::base::equal(try_deque->begin(), try_deque->end(), init_list.begin()));
770}
771
772/// @test `inline_deque` initializer list construction is enabled or disabled appropriately based on the value type
774 STATIC_ASSERT_EQ(
775 (std::is_constructible<TypeParam, std::initializer_list<typename TypeParam::value_type>>::value),
776 std::is_copy_constructible<typename TypeParam::value_type>::value
777 );
778
779 STATIC_ASSERT_EQ(
780 (is_list_initializable_v<TypeParam, typename TypeParam::value_type>),
781 std::is_copy_constructible<typename TypeParam::value_type>::value
782 );
783}
784
785/// @test `inline_deque` initializer list construction has the correct noexcept specification
787 STATIC_ASSERT_EQ(
788 (std::is_nothrow_constructible<TypeParam, std::initializer_list<typename TypeParam::value_type>>::value),
789 std::is_nothrow_copy_constructible<typename TypeParam::value_type>::value
790 );
791}
792
793/// @test `inline_deque` can be constructed from an initializer list of `T`
794CONDITIONAL_TYPED_TEST_P(InlineDequeTest, ConstructFromInitializerList, std::is_copy_constructible<TypeParam>::value) {
795 auto const init_list = TestFixture::full_test_initializer_list();
796 TypeParam const deque(init_list);
797
798 ASSERT_EQ(deque.size(), init_list.size());
799 EXPECT_TRUE(::arene::base::equal(deque.begin(), deque.end(), init_list.begin()));
800
801 auto const try_deque = TypeParam::try_construct(init_list);
802 ASSERT_TRUE(try_deque.has_value());
803 EXPECT_TRUE(::arene::base::equal(try_deque->begin(), try_deque->end(), init_list.begin()));
804}
805
806/// @test `inline_deque` can be constructed from an empty initializer list
807CONDITIONAL_TYPED_TEST_P(InlineDequeTest, ConstructFromEmptyList, std::is_copy_constructible<TypeParam>::value) {
808 auto const init_list = TestFixture::template test_initializer_list<0U>();
809
810 TypeParam const deque_from_ilist(init_list);
811 EXPECT_EQ(deque_from_ilist.size(), 0U);
812
813 TypeParam const deque_from_range(init_list.begin(), init_list.end());
814 EXPECT_EQ(deque_from_range.size(), 0U);
815
816 auto const try_deque_from_ilist = TypeParam::try_construct(init_list);
817 ASSERT_TRUE(try_deque_from_ilist.has_value());
818 EXPECT_EQ(try_deque_from_ilist->size(), 0U);
819
820 auto const try_deque_from_range = TypeParam::try_construct(init_list.begin(), init_list.end());
821 ASSERT_TRUE(try_deque_from_range.has_value());
822 EXPECT_EQ(try_deque_from_range->size(), 0U);
823}
824
825/// @test `inline_deque` crashes when copy constructed from a random-access range in the wrong order
827 InlineDequeDeathTest,
829 std::is_copy_constructible<TypeParam>::value
830) {
831 auto const init_list = TestFixture::full_test_initializer_list();
832 ASSERT_DEATH(TypeParam(init_list.end(), init_list.begin()), "Precondition");
833}
834
835/// @test `try_construct` returns empty when copy constructing from a random-access range in the wrong order
837 InlineDequeTest,
839 std::is_copy_constructible<TypeParam>::value
840) {
841 auto const init_list = TestFixture::full_test_initializer_list();
842 EXPECT_FALSE(TypeParam::try_construct(init_list.end(), init_list.begin()).has_value());
843}
844
845/// @test `inline_deque` crashes when copy constructed from a range that's too large to fit within the capacity
847 InlineDequeDeathTest,
849 std::is_copy_constructible<TypeParam>::value
850) {
851 auto const init_list = TestFixture::template test_initializer_list<TypeParam::capacity() + 1U>();
852 ASSERT_DEATH(TypeParam(init_list.begin(), init_list.end()), "Precondition");
853}
854
855/// @test `try_construct` returns empty when copy constructing from a range that's too large to fit within the capacity
857 InlineDequeTest,
859 std::is_copy_constructible<TypeParam>::value
860) {
861 auto const init_list = TestFixture::template test_initializer_list<TypeParam::capacity() + 1U>();
862 EXPECT_FALSE(TypeParam::try_construct(init_list.begin(), init_list.end()).has_value());
863}
864
865/// @test `inline_deque` crashes when move constructed from a range with the iterators in the wrong order
867 ASSERT_DEATH(
868 TypeParam(
869 arene::base::testing::rvalue_iterator<typename TypeParam::value_type>(TypeParam::capacity()),
870 arene::base::testing::rvalue_iterator<typename TypeParam::value_type>(0)
871 ),
872 "Precondition"
873 );
874}
875
876/// @test `try_construct` returns empty when move constructing from a range with the iterators in the wrong order
878 EXPECT_FALSE(TypeParam::try_construct(
879 arene::base::testing::rvalue_iterator<typename TypeParam::value_type>(TypeParam::capacity()),
880 arene::base::testing::rvalue_iterator<typename TypeParam::value_type>(0)
881 )
882 .has_value());
883}
884
885/// @test `inline_deque` crashes when move constructed from a range that's too large to fit within the capacity
887 ASSERT_DEATH(
888 TypeParam(
889 arene::base::testing::rvalue_iterator<typename TypeParam::value_type>(0),
890 arene::base::testing::rvalue_iterator<typename TypeParam::value_type>(TypeParam::capacity() + 1U)
891 ),
892 "Precondition"
893 );
894}
895
896/// @test `try_construct` returns empty when move constructing from a range that's too large to fit within the capacity
898 EXPECT_FALSE(TypeParam::try_construct(
899 arene::base::testing::rvalue_iterator<typename TypeParam::value_type>(0),
900 arene::base::testing::rvalue_iterator<typename TypeParam::value_type>(TypeParam::capacity() + 1U)
901 )
902 .has_value());
903}
904
905/// @test `inline_deque` crashes when copy constructed from an initializer list that's too large to fit in the capacity
907 InlineDequeDeathTest,
909 std::is_copy_constructible<TypeParam>::value
910) {
911 auto const init_list = TestFixture::template test_initializer_list<TypeParam::capacity() + 1U>();
912 ASSERT_DEATH(static_cast<void>(TypeParam(init_list)), "Precondition");
913}
914
915/// @test `try_construct` returns empty when constructing from an initializer list that's too large for the capacity
917 InlineDequeTest,
919 std::is_copy_constructible<TypeParam>::value
920) {
921 auto const init_list = TestFixture::template test_initializer_list<TypeParam::capacity() + 1U>();
922 EXPECT_FALSE(TypeParam::try_construct(init_list).has_value());
923}
924
925/// @test `inline_deque` copy-construction works as expected
926CONDITIONAL_TYPED_TEST_P(InlineDequeTest, CanCopyConstruct, std::is_copy_constructible<TypeParam>::value) {
927 auto org = TestFixture::full_test_deque();
928 auto dst(org);
929 EXPECT_EQ(org.size(), org.capacity());
930 EXPECT_EQ(org.size(), dst.size());
931 for (std::size_t i = 0; i < org.capacity(); i++) {
932 EXPECT_EQ(TestFixture::test_value(i), dst.front());
933 EXPECT_EQ(org.front(), dst.front());
934 org.pop_front();
935 dst.pop_front();
936 }
937 EXPECT_TRUE(org.empty());
938 EXPECT_TRUE(dst.empty());
939}
940
941/// @test `inline_deque` copy-construction works as expected when invoked via `try_construct`
942CONDITIONAL_TYPED_TEST_P(InlineDequeTest, CanCopyTryConstruct, std::is_copy_constructible<TypeParam>::value) {
943 auto org = TestFixture::full_test_deque();
944 auto dst = TypeParam::try_construct(org);
945
946 ASSERT_TRUE(dst.has_value());
947 EXPECT_TRUE(::arene::base::equal(org.begin(), org.end(), dst->begin()));
948}
949
950/// @test `inline_deque` move-construction works as expected
952 auto org = TestFixture::full_test_deque();
953 EXPECT_EQ(org.size(), org.capacity());
954 TypeParam dst(std::move(org));
955 EXPECT_EQ(dst.size(), dst.capacity());
956 for (std::size_t i = 0; i < dst.capacity(); i++) {
957 EXPECT_EQ(TestFixture::test_value(i), dst.front());
958 dst.pop_front();
959 }
960 EXPECT_TRUE(dst.empty());
961}
962
963/// @test `inline_deque` move-construction works as expected when invoked via `try_construct`
965 auto org = TestFixture::full_test_deque();
966 auto tmp = TestFixture::full_test_deque();
967 auto dst = TypeParam::try_construct(std::move(tmp));
968
969 ASSERT_TRUE(dst.has_value());
970 EXPECT_TRUE(::arene::base::equal(org.begin(), org.end(), dst->begin()));
971}
972
973/// @test `inline_deque` copy-assignment works as expected
974CONDITIONAL_TYPED_TEST_P(InlineDequeTest, CanCopyAssign, std::is_copy_assignable<TypeParam>::value) {
975 auto org = TestFixture::full_test_deque();
976 TypeParam dst;
977 EXPECT_EQ(org.size(), org.capacity());
978 EXPECT_EQ(dst.size(), 0);
979 dst = org;
980 EXPECT_EQ(org.size(), org.capacity());
981 EXPECT_EQ(dst.size(), org.capacity());
982 for (std::size_t i = 0; i < org.capacity(); i++) {
983 EXPECT_EQ(TestFixture::test_value(i), dst.front());
984 EXPECT_EQ(org.front(), dst.front());
985 org.pop_front();
986 dst.pop_front();
987 }
988 EXPECT_TRUE(org.empty());
989 EXPECT_TRUE(dst.empty());
990}
991
992/// @test `inline_deque` self copy-assignment does nothing
993CONDITIONAL_TYPED_TEST_P(InlineDequeTest, SelfCopyAssign, std::is_copy_assignable<TypeParam>::value) {
994 TypeParam deque = TestFixture::full_test_deque();
995
997 ARENE_IGNORE_CLANG("-Wself-assign-overloaded", "We're specifically testing self assignment");
998 // NOLINTNEXTLINE(misc-redundant-expression)
999 deque = deque;
1000 ASSERT_EQ(deque.size(), deque.capacity());
1001 ARENE_IGNORE_END();
1002
1003 for (std::size_t i = 0; i < deque.size(); ++i) {
1004 EXPECT_EQ(deque.front(), TestFixture::test_value(i));
1005 deque.pop_front();
1006 }
1007}
1008
1009/// @test `inline_deque` move-assignment works as expected
1010TYPED_TEST_P(InlineDequeTest, CanMoveAssign) {
1011 auto org = TestFixture::full_test_deque();
1012 TypeParam dst;
1013 ASSERT_EQ(org.size(), org.capacity());
1014 ASSERT_EQ(dst.size(), 0);
1015
1016 dst = std::move(org);
1017 ASSERT_EQ(dst.size(), org.capacity());
1018 for (std::size_t i = 0; i < org.capacity(); i++) {
1019 EXPECT_EQ(TestFixture::test_value(i), dst.front());
1020 dst.pop_front();
1021 }
1022 EXPECT_TRUE(dst.empty());
1023}
1024
1025/// @test `inline_deque` self move-assignment does nothing
1026TYPED_TEST_P(InlineDequeTest, SelfMoveAssign) {
1027 TypeParam deque = TestFixture::full_test_deque();
1028
1029 deque = std::move(deque);
1030 ASSERT_EQ(deque.size(), deque.capacity());
1031
1032 for (std::size_t i = 0; i < deque.size(); ++i) {
1033 EXPECT_EQ(deque.front(), TestFixture::test_value(i));
1034 deque.pop_front();
1035 }
1036}
1037
1038/// @test Copy assignment works into a partially full target
1039CONDITIONAL_TYPED_TEST_P(InlineDequeTest, CopyAssignIntoPartiallyFull, std::is_copy_assignable<TypeParam>::value) {
1040 auto org = TestFixture::full_test_deque();
1041 auto dst = TestFixture::full_test_deque();
1042
1043 // Remove half of the elements of dst
1044 while (dst.size() > dst.capacity() / 2U) {
1045 dst.pop_front();
1046 }
1047
1048 dst = org;
1049 ASSERT_EQ(dst.size(), org.capacity());
1050 for (std::size_t i = 0; i < org.capacity(); i++) {
1051 EXPECT_EQ(TestFixture::test_value(i), dst.front());
1052 dst.pop_front();
1053 }
1054}
1055
1056/// @test Copy assignment works from a partially full input
1057CONDITIONAL_TYPED_TEST_P(InlineDequeTest, CopyAssignFromPartiallyFull, std::is_copy_assignable<TypeParam>::value) {
1058 auto org = TestFixture::full_test_deque();
1059 auto dst = TestFixture::full_test_deque();
1060
1061 // Remove half of the elements of org
1062 std::size_t removed_count{};
1063 while (org.size() > org.capacity() / 2U) {
1064 org.pop_front();
1065 ++removed_count;
1066 }
1067
1068 dst = org;
1069 ASSERT_EQ(dst.size(), org.capacity() / 2U);
1070 for (std::size_t i = 0; i < org.capacity() / 2U; i++) {
1071 EXPECT_EQ(TestFixture::test_value(i + removed_count), dst.front());
1072 dst.pop_front();
1073 }
1074}
1075
1076/// @test Move assignment works into a partially full target
1078 auto org = TestFixture::full_test_deque();
1079 auto dst = TestFixture::full_test_deque();
1080
1081 // Remove half of the elements of dst
1082 while (dst.size() > dst.capacity() / 2U) {
1083 dst.pop_front();
1084 }
1085
1086 dst = std::move(org);
1087 ASSERT_EQ(dst.size(), org.capacity());
1088 for (std::size_t i = 0; i < org.capacity(); i++) {
1089 EXPECT_EQ(TestFixture::test_value(i), dst.front());
1090 dst.pop_front();
1091 }
1092}
1093
1094/// @test Move assignment works from a partially full input
1096 auto org = TestFixture::full_test_deque();
1097 auto dst = TestFixture::full_test_deque();
1098
1099 // Remove half of the elements of org
1100 std::size_t removed_count{};
1101 while (org.size() > org.capacity() / 2U) {
1102 org.pop_front();
1103 ++removed_count;
1104 }
1105
1106 dst = std::move(org);
1107 ASSERT_EQ(dst.size(), org.capacity() / 2U);
1108 for (std::size_t i = 0; i < org.capacity() / 2U; i++) {
1109 EXPECT_EQ(TestFixture::test_value(i + removed_count), dst.front());
1110 dst.pop_front();
1111 }
1112}
1113
1114/// @test Both const and non-const iterator types for a deque are random access, and creating them is noexcept
1116 STATIC_ASSERT_TRUE(arene::base::is_random_access_iterator_v<typename TypeParam::iterator>);
1117 STATIC_ASSERT_TRUE(arene::base::is_random_access_iterator_v<typename TypeParam::const_iterator>);
1118 STATIC_ASSERT_TRUE(noexcept(std::declval<TypeParam&>().begin()));
1119 STATIC_ASSERT_TRUE(noexcept(std::declval<TypeParam&>().cbegin()));
1120 STATIC_ASSERT_TRUE(noexcept(std::declval<TypeParam&>().rbegin()));
1121 STATIC_ASSERT_TRUE(noexcept(std::declval<TypeParam&>().crbegin()));
1122 STATIC_ASSERT_TRUE(noexcept(std::declval<TypeParam&>().end()));
1123 STATIC_ASSERT_TRUE(noexcept(std::declval<TypeParam&>().cend()));
1124 STATIC_ASSERT_TRUE(noexcept(std::declval<TypeParam&>().rend()));
1125 STATIC_ASSERT_TRUE(noexcept(std::declval<TypeParam&>().crend()));
1126}
1127
1128/// @test Non-const iterators are implicitly convertible to the corresponding const iterator, but not vice versa
1130 using iterator = typename TypeParam::iterator;
1131 using const_iterator = typename TypeParam::const_iterator;
1132
1133 STATIC_ASSERT_TRUE(arene::base::is_implicitly_constructible_v<const_iterator, iterator>);
1134 STATIC_ASSERT_FALSE(arene::base::is_implicitly_constructible_v<iterator, const_iterator>);
1135
1136 TypeParam deque = TestFixture::full_test_deque();
1137 EXPECT_EQ(std::addressof(*deque.begin()), std::addressof(*deque.cbegin()));
1138 EXPECT_EQ(deque.begin(), deque.cbegin());
1139}
1140
1141/// @test Inspecting a deque using its iterators yields the elements from front to back
1143 TypeParam const deque = TestFixture::full_test_deque();
1144
1145 std::size_t value_idx{0U};
1146 for (auto const& element : deque) {
1147 EXPECT_EQ(element, TestFixture::test_value(value_idx));
1148 ++value_idx;
1149 }
1150}
1151
1152/// @test Inspecting a deque using its iterators yields the elements from front to back, even when wrapping around
1154 TypeParam const deque = TestFixture::wrapped_test_deque();
1155
1156 // The wrapped deque contains the elements [capacity/2, 3*capacity/2).
1157 std::size_t value_idx{(deque.capacity() / 2U)};
1158 for (auto const& element : deque) {
1159 EXPECT_EQ(element, TestFixture::test_value(value_idx));
1160 ++value_idx;
1161 }
1162}
1163
1164/// @test The elements of a deque can be changed using its mutable iterators
1166 // As confirmed in the above test, this contains the elements [capacity/2, 3*capacity/2), arranged backwards.
1167 TypeParam deque = TestFixture::wrapped_test_deque();
1168
1169 // Use the mutable iterators to change the elements to [0, capacity), arranged forwards
1170 std::size_t value_idx{};
1171 for (auto& element : deque) {
1172 element = TestFixture::test_value(value_idx);
1173 ++value_idx;
1174 }
1175
1176 // Use the constant iterators to inspect that the entries have the right values in the same order
1177 value_idx = {};
1178 for (auto itr = deque.cbegin(); itr != deque.cend(); ++itr) {
1179 EXPECT_EQ(*itr, TestFixture::test_value(value_idx));
1180 ++value_idx;
1181 }
1182}
1183
1184/// @test Inspecting a deque using its reverse iterators yields the elements from back to front
1186 TypeParam const deque = TestFixture::wrapped_test_deque();
1187
1188 // The wrapped deque contains the elements [capacity/2, 3*capacity/2).
1189 std::size_t idx{deque.capacity() + (deque.capacity() / 2U) - 1U};
1190 for (auto itr = deque.crbegin(); itr != deque.crend(); ++itr) {
1191 EXPECT_EQ(*itr, TestFixture::test_value(idx));
1192 --idx;
1193 }
1194}
1195
1196/// @test The elements of a deque can be changed using its mutable reverse iterators
1198 // As confirmed in the above test, this contains the elements [capacity/2, 3*capacity/2), arranged backwards.
1199 TypeParam deque = TestFixture::wrapped_test_deque();
1200
1201 // Use the mutable reverse iterators to change the elements to [0, capacity), in reverse
1202 std::size_t value_idx{};
1203 for (auto itr = deque.rbegin(); itr != deque.rend(); ++itr) {
1204 *itr = TestFixture::test_value(value_idx);
1205 ++value_idx;
1206 }
1207
1208 // Use the forward iterators to inspect that the entries have the right values in the opposite order
1209 for (auto const& element : deque) {
1210 --value_idx;
1211 EXPECT_EQ(element, TestFixture::test_value(value_idx));
1212 }
1213}
1214
1215/// @test Using `pop_front()` only invalidates iterators and references to the first element
1216CONDITIONAL_TYPED_TEST_P(InlineDequeTest, IteratorsNotInvalidatedByPopFront, TypeParam::capacity() >= 2U) {
1217 // The normal TestFixture::test_deque is populated front-to-back, but we want back-to-front for this test.
1218 TypeParam deque = TestFixture::test_deque(2U);
1219
1220 auto itr = deque.cbegin();
1221 for (std::size_t value_idx{}; value_idx / 3U < TypeParam::capacity(); ++value_idx) {
1222 EXPECT_EQ(*itr, TestFixture::test_value(value_idx));
1223 ++itr;
1224 deque.pop_front(); // remove the element that was just inspected
1225 deque.push_back(TestFixture::test_value(value_idx + 2U)); // add the element we'll inspect 2 iterations from now
1226 }
1227}
1228
1229/// @test Using `pop_back()` only invalidates iterators and references to the last element and `end()`
1231 InlineDequeTest,
1234) {
1235 // This test requires capacity 3 or more because a reverse iterator is invalidated by removing the element it points
1236 // to *or* the one after (reverse-before) it. To prevent this we need to advance the iterator twice before popping.
1237 //
1238 // The above test using a forward iterator and pop_front()/push_back() works with only 2 elements in the queue,
1239 // because the forward iterator is only invalidated if the element it points to is.
1240
1241 TypeParam deque = TestFixture::construct();
1242 deque.push_front(TestFixture::test_value(0U));
1243 deque.push_front(TestFixture::test_value(1U));
1244 deque.push_front(TestFixture::test_value(2U));
1245
1246 auto itr = deque.crbegin();
1247 ++itr; // advance the iterator to ensure the element being popped is *two* elements behind the iterator
1248 for (std::size_t value_idx{1U}; value_idx / 3U < TypeParam::capacity(); ++value_idx) {
1249 EXPECT_EQ(*itr, TestFixture::test_value(value_idx));
1250 ++itr;
1251 deque.pop_back(); // remove the element that was just inspected
1252 deque.push_front(TestFixture::test_value(value_idx + 2U)); // add the element we'll inspect 2 iterations from now
1253 }
1254}
1255
1256/// @test Using binary `operator+` on an iterator gives the same result as using `operator+=` on a copy of it
1258 using difference_type = typename TypeParam::iterator::difference_type;
1259
1260 TypeParam deque = TestFixture::full_test_deque();
1261
1262 // Taking this difference out to size() so we can test the cases where the iterator falls off the edge as well
1263 for (difference_type diff{}; diff <= static_cast<difference_type>(deque.size()); ++diff) {
1264 auto begin_copy = deque.begin();
1265 begin_copy += diff;
1266 EXPECT_EQ(begin_copy, deque.begin() + diff);
1267 EXPECT_EQ(begin_copy, diff + deque.begin());
1268
1269 auto cbegin_copy = deque.cbegin();
1270 cbegin_copy += diff;
1271 EXPECT_EQ(cbegin_copy, deque.cbegin() + diff);
1272 EXPECT_EQ(cbegin_copy, diff + deque.cbegin());
1273 }
1274}
1275
1276/// @test Using binary `operator-` on an iterator and a difference gives the same result as using `operator-=` on them
1278 using difference_type = typename TypeParam::iterator::difference_type;
1279
1280 TypeParam deque = TestFixture::full_test_deque();
1281
1282 // Taking this difference out to size() so we can test the cases where the iterator falls off the edge as well
1283 for (difference_type diff{}; diff <= static_cast<difference_type>(deque.size()); ++diff) {
1284 auto end_copy = deque.end();
1285 end_copy -= diff;
1286 EXPECT_EQ(end_copy, deque.end() - diff);
1287
1288 auto cend_copy = deque.cend();
1289 cend_copy -= diff;
1290 EXPECT_EQ(cend_copy, deque.cend() - diff);
1291 }
1292}
1293
1294/// @test Using `operator[]` on an iterator gives the same result as using binary `operator+` and unary `operator*`
1296 using difference_type = typename TypeParam::iterator::difference_type;
1297
1298 TypeParam deque = TestFixture::full_test_deque();
1299
1300 for (difference_type diff{}; diff < static_cast<difference_type>(deque.size()); ++diff) {
1301 EXPECT_EQ(std::addressof(deque.begin()[diff]), std::addressof(*(deque.begin() + diff)));
1302 EXPECT_EQ(std::addressof(deque.cbegin()[diff]), std::addressof(*(deque.cbegin() + diff)));
1303
1304 EXPECT_EQ(std::addressof(deque.rbegin()[diff]), std::addressof(*(deque.rbegin() + diff)));
1305 EXPECT_EQ(std::addressof(deque.crbegin()[diff]), std::addressof(*(deque.crbegin() + diff)));
1306 }
1307}
1308
1309/// @test Using `operator[]` on the deque gives the same result as using `operator[]` on `begin()`
1311 using difference_type = typename TypeParam::iterator::difference_type;
1312
1313 TypeParam deque = TestFixture::full_test_deque();
1314 TypeParam const& const_deque = deque;
1315
1316 for (difference_type diff{}; diff < static_cast<difference_type>(deque.size()); ++diff) {
1317 EXPECT_EQ(std::addressof(deque[diff]), std::addressof(deque.begin()[diff]));
1318 EXPECT_EQ(std::addressof(const_deque[diff]), std::addressof(deque.cbegin()[diff]));
1319 }
1320}
1321
1322/// @test Binary `operator-` between any two iterators returns the distance between them
1324 using difference_type = typename TypeParam::iterator::difference_type;
1325
1326 // If it's possible to construct a deque that's neither full nor empty, test both the full one and the partially full
1327 // one; if not, then just test the full one.
1328 using deque_array = std::
1329 conditional_t<TypeParam::capacity() >= 2U, arene::base::array<TypeParam, 2U>, arene::base::array<TypeParam, 1U>>;
1330 deque_array deques;
1331 deques[0U] = TestFixture::full_test_deque();
1332 if (deques.size() >= 2U) {
1333 deques[1U] = TestFixture::half_test_deque();
1334 }
1335
1336 for (auto& deque : deques) {
1337 auto const signed_size = static_cast<difference_type>(deque.size());
1338
1339 auto current = deque.begin();
1340 auto const_current = deque.cbegin();
1341 for (difference_type current_pos{}; current_pos <= signed_size; ++current_pos) {
1342 // Check that every iterator from beginning to end has the expected difference from the current position
1343
1344 auto test_iter = deque.begin();
1345 auto const_test_iter = deque.cbegin();
1346 for (difference_type diff{-current_pos}; diff < (signed_size - current_pos); ++diff) {
1347 EXPECT_EQ(test_iter - current, diff);
1348 EXPECT_EQ(const_test_iter - const_current, diff);
1349
1350 ++test_iter;
1351 ++const_test_iter;
1352 }
1353
1354 ++current;
1355 ++const_current;
1356 }
1357 }
1358}
1359
1360/// @test Incrementing an iterator all at once is the same as repeatedly incrementing it one step
1362 using difference_type = typename TypeParam::iterator::difference_type;
1363
1364 TypeParam deque = TestFixture::full_test_deque();
1365 auto curr = deque.begin();
1366 auto const_curr = deque.cbegin();
1367 for (difference_type diff{}; diff <= static_cast<difference_type>(deque.size()); ++diff) {
1368 EXPECT_EQ(deque.begin() + diff, curr);
1369 ++curr;
1370
1371 EXPECT_EQ(deque.cbegin() + diff, const_curr);
1372 ++const_curr;
1373 }
1374}
1375
1376/// @test Decrementing an iterator all at once is the same as repeatedly decrementing it one step
1378 using difference_type = typename TypeParam::iterator::difference_type;
1379
1380 TypeParam deque = TestFixture::full_test_deque();
1381 auto curr = deque.end();
1382 auto const_curr = deque.cend();
1383 for (difference_type diff{}; diff <= static_cast<difference_type>(deque.size()); ++diff) {
1384 EXPECT_EQ(deque.end() - diff, curr);
1385 --curr;
1386
1387 EXPECT_EQ(deque.cend() - diff, const_curr);
1388 --const_curr;
1389 }
1390}
1391
1392/// @test Incrementing an iterator by exactly enough to go out of bounds causes it to become the end iterator
1394 using difference_type = typename TypeParam::iterator::difference_type;
1395
1396 TypeParam deque = TestFixture::full_test_deque();
1397 auto start = deque.begin();
1398 auto const_start = deque.cbegin();
1399 for (auto diff = static_cast<difference_type>(deque.size()); diff >= 0; --diff) {
1400 EXPECT_EQ(start + diff, deque.end());
1401 EXPECT_EQ(const_start + diff, deque.cend());
1402 ++start;
1403 ++const_start;
1404 }
1405}
1406
1407/// @test When created on an empty deque, the begin and end pair of each iterator type equal each other
1409 TypeParam deque = TestFixture::construct();
1410 EXPECT_EQ(deque.begin(), deque.end());
1411 EXPECT_EQ(deque.cbegin(), deque.cend());
1412 EXPECT_EQ(deque.rbegin(), deque.rend());
1413 EXPECT_EQ(deque.crbegin(), deque.crend());
1414}
1415
1416/// @brief Check that the first value is ordered strictly before the second
1417template <typename T>
1418auto check_ordering(T const& first, T const& second) noexcept -> void {
1419 EXPECT_TRUE(first < second);
1420 EXPECT_TRUE(first <= second);
1421 EXPECT_FALSE(first > second);
1422 EXPECT_FALSE(first >= second);
1423
1424 EXPECT_FALSE(second < first);
1425 EXPECT_FALSE(second <= first);
1426 EXPECT_TRUE(second > first);
1427 EXPECT_TRUE(second >= first);
1428}
1429
1430/// @test Iterators to the same deque are ordered with respect to each other in the way they're supposed to be
1432 TypeParam deque = TestFixture::full_test_deque();
1433
1434 auto curr = deque.begin();
1435 auto const_curr = deque.cbegin();
1436 for (std::size_t i{}; i + 1U < deque.size(); ++i) {
1437 ++curr;
1438 ++const_curr;
1439
1440 check_ordering(deque.begin(), curr);
1441 check_ordering(deque.cbegin(), const_curr);
1442 check_ordering(curr, deque.end());
1443 check_ordering(const_curr, deque.cend());
1444 }
1445}
1446
1447/// @test Dereferencing the end iterator of any iterator type causes a crash
1449 TypeParam deque = TestFixture::full_test_deque();
1450 ASSERT_DEATH(*deque.end(), "Precondition");
1451 ASSERT_DEATH(*deque.cend(), "Precondition");
1452 ASSERT_DEATH(static_cast<void>(*deque.rend()), "Precondition");
1453 ASSERT_DEATH(static_cast<void>(*deque.crend()), "Precondition");
1454}
1455
1456/// @test When created on an empty deque, dereferencing the begin iterator of any iterator type causes a crash
1458 TypeParam deque = TestFixture::construct();
1459 ASSERT_DEATH(*deque.begin(), "Precondition");
1460 ASSERT_DEATH(*deque.cbegin(), "Precondition");
1461 ASSERT_DEATH(static_cast<void>(*deque.rbegin()), "Precondition");
1462 ASSERT_DEATH(static_cast<void>(*deque.crbegin()), "Precondition");
1463}
1464
1465/// @test Default-constructed instances of any deque's iterators cause crashes when incremented or dereferenced
1467 TypeParam deque = TestFixture::full_test_deque();
1468
1469 typename TypeParam::iterator default_it;
1470 EXPECT_NE(default_it, deque.begin());
1471 EXPECT_NE(default_it, deque.end());
1472 ASSERT_DEATH(*default_it, "Precondition");
1473 ASSERT_DEATH(default_it += 0, "Precondition");
1474}
1475
1476/// @test Default-constructed instances of any deque's const iterators cause crashes when incremented or dereferenced
1478 TypeParam deque = TestFixture::full_test_deque();
1479
1480 typename TypeParam::const_iterator default_it;
1481 EXPECT_NE(default_it, deque.cbegin());
1482 EXPECT_NE(default_it, deque.cend());
1483 ASSERT_DEATH(*default_it, "Precondition");
1484 ASSERT_DEATH(default_it += 0, "Precondition");
1485}
1486
1487/// @test Trying to compare iterators for ordering when they come from two different deques causes a crash
1489 TypeParam deque1 = TestFixture::full_test_deque();
1490 TypeParam deque2 = TestFixture::full_test_deque();
1491
1492 ASSERT_DEATH(std::ignore = (deque1.begin() < deque2.begin()), "Precondition");
1493 ASSERT_DEATH(std::ignore = (deque1.begin() <= deque2.begin()), "Precondition");
1494 ASSERT_DEATH(std::ignore = (deque1.begin() > deque2.begin()), "Precondition");
1495 ASSERT_DEATH(std::ignore = (deque1.begin() >= deque2.begin()), "Precondition");
1496}
1497
1498/// @test Trying to subtract the most negative possible difference from an iterator causes a precondition violation
1500 TypeParam deque = TestFixture::full_test_deque();
1501
1502 // This value can not be negated, so trying to subtract by it causes a precondition violation.
1503 constexpr auto minimum_value = std::numeric_limits<typename TypeParam::iterator::difference_type>::lowest();
1504
1505 ASSERT_DEATH(std::ignore = (deque.begin() - minimum_value), "Precondition");
1506 ASSERT_DEATH(std::ignore = (deque.cbegin() - minimum_value), "Precondition");
1507}
1508
1510
1512 InlineDequeTest,
1588);
1589
1591 InlineDequeDeathTest,
1612);
1613
1614} // namespace testing
1615} // namespace base
1616} // namespace arene
1617
1618#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_INLINE_CONTAINER_TESTING_DEQUE_HPP_
The death tests use the same fixture as the non-death tests, but as a distinct type to improve log ou...
Definition deque.hpp:182
Test fixture for all type-parameterized inline_deque tests.
Definition deque.hpp:90
static constexpr auto construct() noexcept(noexcept(Deque())) -> Deque
Return an empty Deque, allowing to call as this->construct, which becomes useful with the ....
Definition deque.hpp:113
static constexpr auto test_deque(std::size_t size) noexcept(noexcept(test_deque(0, size))) -> Deque
Return a Deque containing the test values [0,size) of T.
Definition deque.hpp:128
static constexpr auto test_deque(std::size_t begin, std::size_t end) noexcept(noexcept(::arene::base::testing::test_deque< Deque >(begin, end))) -> Deque
Return a Deque containing the test values [begin,end) of T.
Definition deque.hpp:119
static constexpr auto wrapped_test_deque() noexcept(noexcept(test_deque(Deque::capacity))) -> Deque
Return a Deque containing the test values [capacity/2, 3*capacity/2) of T.
Definition deque.hpp:147
static constexpr auto test_initializer_list() noexcept -> std::initializer_list< T >
Return a std::initializer_list containing user-parameterized test_values.
Definition deque.hpp:168
static constexpr auto half_test_deque() noexcept(noexcept(test_deque(Deque::capacity))) -> Deque
Return a Deque containing the test values [0,capacity/2) of T.
Definition deque.hpp:134
static constexpr bool constexpr_compatible
Whether the type parameter is constexpr compatible for this test.
Definition deque.hpp:95
static constexpr auto full_test_initializer_list() noexcept -> std::initializer_list< T >
Return a std::initializer_list containing Deque::capacity user-parameterized test_values.
Definition deque.hpp:174
static constexpr auto full_test_deque() noexcept(noexcept(test_deque(Deque::capacity))) -> Deque
Return a Deque containing the test values [0,capacity) of T.
Definition deque.hpp:140
static constexpr auto test_value(std::size_t idx) noexcept(noexcept(::arene::base::testing::test_value< T >(idx))) ->
Return the idx 'th test value of the current T , parameterized by test suite users.
Definition deque.hpp:106
static constexpr auto test_initializer_list(std::index_sequence< Indices... >) noexcept -> std::initializer_list< T >
Return a std::initializer_list containing user-parameterized test_values.
Definition deque.hpp:160
Definition customization.hpp:36
constexpr auto test_deque(std::size_t begin, std::size_t end) noexcept(std::is_nothrow_copy_constructible< typename T::value_type >::value) -> T
Create a test deque containing a range of test values.
Definition deque.hpp:59
constexpr bool is_list_initializable_v
A type trait to check if a type is list-initializable using a brace-enclosed list of values with a gi...
Definition deque.hpp:74
ARENE_IGNORE_ALL("-Wfloat-equal", "These tests don't perform arithmetic, so equality is OK even for floating point")
Definition array_exceptions_disabled.cpp:11
CONDITIONAL_TYPED_TEST_P(InlineDequeTest, PushFrontOneElement, is_double_ended< TypeParam >)
Definition deque.hpp:218
REGISTER_TYPED_TEST_SUITE_P(InlineDequeDeathTest, PushFrontMoreThanCapacity, PushBackMoreThanCapacity, NonWrappingInsertOneWhenFull, BackWhenEmpty, ConstBackWhenEmpty, PopFrontWhenEmpty, PopBackWhenEmpty, FrontWhenEmpty, ConstFrontWhenEmpty, CopyConstructFromBackwardRange, CopyConstructFromOversizedRange, MoveConstructFromBackwardRange, MoveConstructFromOversizedRange, ConstructFromOversizedInitializerList, DereferencingEndIteratorIsPreconditionViolation, DereferencingBeginOfEmptyDequeIsPreconditionViolation, DefaultConstructedIteratorCantBeUsed, DefaultConstructedConstIteratorCantBeUsed, IteratorOrderingFromDifferentDequesIsPreconditionViolation, SubtractingIteratorByMinimumValueIsPreconditionViolation)
auto check_ordering(T const &first, T const &second) noexcept -> void
Check that the first value is ordered strictly before the second.
Definition deque.hpp:1418
constexpr bool is_double_ended
Type trait to see if a particular TypeParam is double-ended or not; used to exclude some tests.
Definition deque.hpp:189
TYPED_TEST_P(InlineDequeTest, CanConstruct)
Definition deque.hpp:196
CONDITIONAL_TYPED_TEST_P(InlineDequeTest, IteratorsNotInvalidatedByPopFront, TypeParam::capacity() >=2U)
Definition deque.hpp:1216
TYPED_TEST_SUITE_P(InlineDequeTest)
REGISTER_TYPED_TEST_SUITE_P(InlineDequeTest, CanConstruct, CapacityIsAsSpecified, CapacityIsNoexcept, SizeIsNoexcept, PushFrontOneElement, PushBackOneElement, EmplaceFrontReturnsReference, EmplaceBackReturnsReference, FrontPushedElementIsCorrect, BackPushedElementIsCorrect, PushFrontWithinCapacity, PushBackWithinCapacity, PushFrontDetailCoverage, InsertConstraints, CopyInsertOne, MoveInsertOne, CopyInsertOneAtEnd, MoveInsertOneAtEnd, GoCircularFromFront, GoCircularFromBack, BasicFunctionFromFront, BasicFunctionFromBack, CanObserveAndModifyFromFront, CanObserveAndModifyFromBack, PushFrontCopiesLvalues, PushBackCopiesLvalues, NotCopyConstructibleIfDataTypeNotCopyConstructible, NotMoveConstructibleIfDataTypeNotMoveConstructible, NotCopyAssignableIfDataTypeNotCopyConstructibleAndCopyAssignable, NotMoveAssignableIfDataTypeNotMoveConstructibleAndMoveAssignable, CanConstructAtCompileTime, RangeConstructionSfinae, RangeConstructionNoexcept, CopyConstructFromRange, MoveConstructFromRange, InitializerListConstructionSfinae, InitializerListConstructionNoexcept, ConstructFromInitializerList, ConstructFromEmptyList, TryCopyConstructFromBackwardRange, TryCopyConstructFromOversizedRange, TryMoveConstructFromBackwardRange, TryMoveConstructFromOversizedRange, TryConstructFromOversizedInitializerList, CanCopyConstruct, CanCopyTryConstruct, CanMoveConstruct, CanMoveTryConstruct, CanCopyAssign, SelfCopyAssign, CanMoveAssign, SelfMoveAssign, CopyAssignIntoPartiallyFull, CopyAssignFromPartiallyFull, MoveAssignIntoPartiallyFull, MoveAssignFromPartiallyFull, IteratorsAreRandomAccessAndNoexcept, NonConstIteratorsImplicitlyConvertibleToConst, InspectWithIterators, IteratorsWrapAround, MutableIteratorsWork, InspectWithReverseIterators, MutableReverseIteratorsWork, IteratorsNotInvalidatedByPopFront, IteratorsNotInvalidatedByPopBack, BinaryPlusEquivalentToPlusEquals, BinaryMinusEquivalentToMinusEquals, IteratorBracketOperatorEquivalentToBinaryPlus, ContainerBracketOperatorEquivalentToIteratorBracketOperator, AnyIteratorDifferenceReturnsDistance, IteratorForwardMovementIsTheSameAsRepeatedIncrementing, IteratorBackwardMovementIsTheSameAsRepeatedDecrementing, IteratorsIncrementedOutOfBoundsBecomeEnd, EmptyDequeBeginEqualsEnd, IteratorsAreOrdered)
TYPED_TEST_SUITE_P(InlineDequeDeathTest)
CONDITIONAL_TYPED_TEST_P(InlineDequeTest, BasicFunctionFromBack, TypeParam::capacity >=2)
Definition deque.hpp:546
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10