Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
vector.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_VECTOR_HPP_
6#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_INLINE_CONTAINER_TESTING_VECTOR_HPP_
7
8#include <gmock/gmock.h>
9
10#include "arene/base/algorithm/all_of.hpp"
11#include "arene/base/algorithm/equal.hpp"
12#include "arene/base/array/array.hpp"
13#include "arene/base/compiler_support/diagnostics.hpp"
14#include "arene/base/compiler_support/platform_queries.hpp"
15#include "arene/base/compiler_support/preprocessor.hpp"
16#include "arene/base/constraints/substitution_succeeds.hpp"
17#include "arene/base/inline_container/testing/customization.hpp"
18#include "arene/base/inline_container/testing/default_constructible_properties.hpp"
19#include "arene/base/inline_container/testing/unique_test_value.hpp"
20#include "arene/base/inline_container/vector.hpp"
21#include "arene/base/iterator/reverse_iterator.hpp"
22#include "arene/base/optional/optional_resetter.hpp"
23#include "arene/base/stdlib_choice/addressof.hpp"
24#include "arene/base/stdlib_choice/cstddef.hpp"
25#include "arene/base/stdlib_choice/declval.hpp"
26#include "arene/base/stdlib_choice/forward.hpp"
27#include "arene/base/stdlib_choice/initializer_list.hpp"
28#include "arene/base/stdlib_choice/integer_sequence.hpp"
29#include "arene/base/stdlib_choice/is_assignable.hpp"
30#include "arene/base/stdlib_choice/is_constructible.hpp"
31#include "arene/base/stdlib_choice/is_copy_assignable.hpp"
32#include "arene/base/stdlib_choice/is_copy_constructible.hpp"
33#include "arene/base/stdlib_choice/is_default_constructible.hpp"
34#include "arene/base/stdlib_choice/is_move_assignable.hpp"
35#include "arene/base/stdlib_choice/is_move_constructible.hpp"
36#include "arene/base/stdlib_choice/is_rvalue_reference.hpp"
37#include "arene/base/stdlib_choice/is_same.hpp"
38#include "arene/base/stdlib_choice/iterator_tags.hpp"
39#include "arene/base/stdlib_choice/iterator_traits.hpp"
40#include "arene/base/stdlib_choice/move.hpp"
41#include "arene/base/stdlib_choice/move_iterator.hpp"
42#include "arene/base/stdlib_choice/numeric_limits.hpp"
43#include "arene/base/stdlib_choice/pair.hpp"
44#include "arene/base/stdlib_choice/reference_wrapper.hpp"
45#include "arene/base/stdlib_choice/stdexcept.hpp"
46#include "arene/base/testing/gtest.hpp"
47#include "arene/base/type_manipulation/consume_values.hpp"
48#include "arene/base/type_traits/comparison_traits.hpp"
49#include "arene/base/type_traits/is_swappable.hpp"
50#include "arene/base/utility/swap.hpp"
51#include "testlibs/utilities/iterator_types.hpp"
52
53namespace arene {
54namespace base {
55namespace testing {
56
58ARENE_IGNORE_ALL("-Wfloat-equal", "These tests don't perform arithmetic, so equality is OK even for floating point");
59
60template <class T>
62 constexpr explicit equal_to_value(T const& input)
63 : value{input} {}
64 constexpr auto operator()(T const& arg) -> bool { return arg == value; }
65
66 T const& value;
67};
68
69/// @brief Check if all element of @c range are equal to @c value
70/// @tparam Range The type of the range to check
71/// @tparam T The type of the value to compare against
72/// @param range The range to check
73/// @param value The value to compare against
74///
75/// This helper is an alternative to GTest matchers @c Each(Eq(value)), which require the value to be copy
76/// constructible.
77template <class Range, class T>
78constexpr auto all_elements_are(Range const& range, T const& value) -> bool {
79 return arene::base::all_of(range.begin(), range.end(), equal_to_value<T>{value});
80}
81
82/// @brief Check if all element of @c range are equal to the elements in @c values
83/// @tparam Range1 The type of the range to check
84/// @tparam Range2 The type of the value to compare against
85/// @param range The range to check
86/// @param values The values to compare against
87///
88/// This helper is an alternative to GTest matcher @c ElementsAreArray, which require the values to be copy
89/// constructible.
90template <class Range1, class Range2>
91constexpr auto elements_are_array(Range1 const& range, Range2 const& values) -> bool {
92 return arene::base::equal(range.begin(), range.end(), values.begin());
93}
94
95/// @brief Create a test vector containing a range of test values
96/// @tparam T The type to contain in the test vector
97/// @tparam Capacity The capacity of inline_vector to populate (note: this is not the size / number of actual entries)
98/// @param begin The first index of test value to put in the vector
99/// @param end The after-end index of test value to put in the vector
100/// @return An inline_vector<T, Capacity> containing [test_value(begin), test_value(end))
101template <typename T, std::size_t Capacity>
102constexpr auto test_vector(std::size_t begin, std::size_t end) noexcept(std::is_nothrow_copy_constructible<T>::value)
104 ::arene::base::inline_vector<T, Capacity> vec;
105 for (std::size_t ii = begin; ii < end; ++ii) {
106 vec.push_back(test_value<T>(ii));
107 }
108 return vec;
109}
110
111/// @brief Push back multiple values into a vector
112/// @tparam Vector The type of the vector
113/// @tparam Values The type of the values
114/// @param vec The vector to push back into
115/// @param values the values to push back
116template <class Vector, class... Values>
117constexpr auto vector_push_back(Vector& vec, Values&&... values) -> void {
118 arene::base::consume_values({0, (vec.push_back(std::forward<Values>(values)), 0)...});
119}
120
121/// @brief sorts the container and then returns it
122/// @tparam Container The type of a container
123/// @param container A container to be sorted
124/// @return @c container with sorted elements
125///
126/// @note @c std::sort is not constexpr in C++14
127/// @note use of @c arene::base::sort introduces coverage misses
128///
129template <typename Container>
130constexpr auto sort_helper(Container container) noexcept -> Container {
131 // TODO
132 // The use of 'arene::base::sort' introduces coverage misses due to newly
133 // introduced instatiations that aren't fully exercised.
134 bool swapped{true};
135 while (swapped) {
136 swapped = false;
137 for (std::size_t ii = 0UL; ii + 1UL < container.size(); ++ii) {
138 if (container[ii + 1] < container[ii]) {
139 arene::base::swap(container[ii], container[ii + 1]);
140 swapped = true;
141 }
142 }
143 }
144 return container;
145}
146
147/// @brief True if a type is copy constructible and copy assignable, false otherwise
148/// @param T the type to check
149template <class T>
151
152/////////////////////////
153// Parameterized tests //
154/////////////////////////
155
156/// @brief Test fixture for all type-parameterized @c inline_vector tests
157/// @tparam T The type parameter currently being used for tests; filled in by Google Test as @c TypeParam
158template <typename Vector>
159class InlineVectorTest : public ::testing::Test {
160 public:
161 using T = typename Vector::value_type;
162
163 /// @brief Whether or not the current type parameter is constexpr compatible for this test
164 static constexpr bool constexpr_compatible =
166 static_assert(
168 "Constexpr-compatible types must have constexpr specializations of test_value_array or test_value"
169 );
170
171 /// @brief The base capacity to use for most @c inline_vector instantiations in the parameterized tests
172 static constexpr std::size_t capacity = Vector::capacity;
173 static_assert(capacity > 0UL, "Parameterized capacity can not be 0 (0-capacity vectors are always tested)");
174
175 protected:
176 static void SetUpTestSuite() { ::arene::base::testing::assert_default_constructible_properties<Vector>(); }
177
178 /// @brief An @c inline_vector with @c capacity using any given type; useful in tests making vectors of wrapper types
179 /// @tparam ValueType The element type of this particular vector
180 template <typename ValueType>
182 /// @brief An @c inline_vector with @c value_type=T using any given capacity; useful in tests doing assignment
183 /// @tparam OtherCapacity The capacity of this particular vector
184 template <std::size_t OtherCapacity>
186
187 /// @brief A helper template to get the type resulting from a @c try_construct call
188 /// @tparam Vec An @c inline_vector type which we will try to construct
189 /// @tparam Args The arguments with which we will try to construct @c Vec
190 template <typename Vec, typename... Args>
192
193 /// @brief A type with a @c noexcept(false) conversion operator to @c T (doesn't actually throw, just declares it)
195 /// @brief Implicit conversion operator to @c T which declares that it might throw, though it doesn't actually
196 /// @return The 0th test value of @c T
197 // NOLINTNEXTLINE(hicpp-explicit-conversions)
198 operator T() const noexcept(false) { return ::arene::base::testing::test_value<T>(0); }
199 };
200
201 /// @brief A bidirectional iterator of @c T which declares that it could throw, used in some @c noexcept tests
203 /// @brief The category of this iterator
205 /// @brief The type used for differences in this iterator
207 /// @brief The type returned by dereferencing this iterator
208 using reference = T&&;
209 /// @brief The value type pointed to by this iterator
210 using value_type = T;
211 /// @brief This iterator as a pointer (disabled)
212 using pointer = void;
213
214 /// @brief Dereference operator; never defined
215 auto operator*() const -> reference;
216
217 /// @brief Pre-increment operator; never defined
219 /// @brief Post-increment operator; never defined
221 /// @brief Pre-decrement operator; never defined
223 /// @brief Post-decrement operator; never defined
225 /// @brief Equality operator; never defined
227 /// @brief Inequality operator; never defined
229 };
230
231 /// @brief An input iterator pointing to any type whose operators have adjustable @c noexcept specifications
232 /// @tparam U The value type of the iterator
233 /// @tparam OperatorsNoexcept The @c noexcept specifications of all operators are equal to this
234 template <typename U, bool OperatorsNoexcept>
236 /// @brief The category of this iterator
238 /// @brief The type used for differences in this iterator
240 /// @brief The type returned by dereferencing this iterator
241 using reference = U&;
242 /// @brief The value type pointed to by this iterator
243 using value_type = U;
244 /// @brief This iterator as a pointer (disabled)
245 using pointer = void;
246
247 /// @brief Dereference operator; never defined
248 auto operator*() const noexcept(OperatorsNoexcept) -> reference;
249
250 /// @brief Pre-increment operator; never defined
252 /// @brief Post-increment operator; never defined
254 /// @brief Equality operator; never defined
256 /// @brief Inequality operator; never defined
258 };
259
260 /// @brief An input iterator pointing to any type which declares that it could throw, used in some @c noexcept tests
261 /// @tparam U The value type of the iterator
262 template <typename U>
263 using throwing_input_iterator = input_iterator_with_configurable_noexcept<U, false>;
264 /// @brief An input iterator pointing to any type which declares that it can not throw, used in some @c noexcept tests
265 /// @tparam U The value type of the iterator
266 template <typename U>
267 using non_throwing_input_iterator = input_iterator_with_configurable_noexcept<U, true>;
268
269 /// @brief Construct a @c Vector from the passed parameters; allows calling as this->construct, which can be shorter
270 /// @tparam U The types of the arguments to the constructor
271 /// @param params The parameters to the constructor
272 template <typename... U>
273 static constexpr auto construct(U&&... params) noexcept(noexcept(Vector(std::forward<U>(params)...))) -> Vector {
274 return Vector(std::forward<U>(params)...);
275 }
276
277 /// @brief Return the @c idx 'th test value of the current @c T , parameterized by test suite users
278 /// @param idx The index of the test value to get
279 /// @return The @c idx 'th test value of the current @c T
280 static constexpr auto test_value(std::size_t idx) noexcept(noexcept(::arene::base::testing::test_value<T>(idx)))
281 -> decltype(::arene::base::testing::test_value<T>(idx)) {
282 return ::arene::base::testing::test_value<T>(idx);
283 }
284
285 /// @brief Return the @c N 'th test value of the current @c T , parameterized by test suite users
286 /// @tparam N The index of the test value to get
287 /// @return The @c N 'th test value of the current @c T
288 /// @note This requires <tt> test_value(0), ..., test_value(N) </tt> are unique values
289 template <std::size_t N>
290 static constexpr auto unique_test_value() noexcept(noexcept(::arene::base::testing::unique_test_value<T, N>()))
291 -> decltype(::arene::base::testing::unique_test_value<T, N>()) {
292 return ::arene::base::testing::unique_test_value<T, N>();
293 }
294
295 /// @brief Return a @c Vector containing the test values @c [begin,end) of @c T , parameterized by test suite users
296 /// @param begin The index of the first test value to put into the test vector
297 /// @param end The index after that of the last test value to put into the test vector
298 /// @return A test Vector holding the test values determined by the indices
299 static constexpr auto test_vector(std::size_t begin, std::size_t end) noexcept(
300 noexcept(::arene::base::testing::test_vector<T, capacity>(begin, end))
301 ) -> Vector {
302 return ::arene::base::testing::test_vector<T, capacity>(begin, end);
303 }
304
305 /// @brief Return a @c Vector containing the test values @c [0,size) of @c T , parameterized by test suite users
306 /// @param size The number of test values to put into the test vector
307 /// @return A test vector holding the test values determined by the size
308 static constexpr auto test_vector(std::size_t size) noexcept(noexcept(test_vector(0, size))) -> Vector {
309 return test_vector(0, size);
310 }
311
312 /// @brief Return a @c Vector containing the test values @c [0,capacity) of @c T , parameterized by test suite users
313 /// @return A test vector holding the test values determined by the capacity
314 static constexpr auto full_test_vector() noexcept(noexcept(test_vector(capacity))) -> Vector {
315 return test_vector(capacity);
316 }
317
318 /// @brief Return a @c std::initializer_list containing user-parameterized @c test_value s
319 /// @tparam Indices A pack of indices, one for each test value in the initializer list
320 /// @return A copy of a statically-allocated @c std::initializer_list<T> containing one test value per index
321 template <std::size_t... Indices>
322 static constexpr auto test_initializer_list(std::index_sequence<Indices...>) noexcept -> std::initializer_list<T> {
323 return ::arene::base::testing::test_initializer_list<T, Indices...>();
324 }
325
326 /// @brief Return a @c std::initializer_list containing user-parameterized @c test_value s
327 /// @tparam Size The number of values in the @c std::initializer_list
328 /// @return A copy of a statically-allocated @c std::initializer_list<T> containing one test value per index
329 template <std::size_t Size>
330 static constexpr auto test_initializer_list() noexcept -> std::initializer_list<T> {
331 return test_initializer_list(std::make_index_sequence<Size>{});
332 }
333
334 /// @brief Return a @c std::initializer_list containing @c capacity user-parameterized @c test_value s
335 /// @return A copy of a statically-allocated @c std::initializer_list<T> containing @c capacity entries
336 static constexpr auto full_test_initializer_list() noexcept -> std::initializer_list<T> {
337 return test_initializer_list<capacity>();
338 }
339};
340
341/// @brief The Death Tests use the same fixture as the "normal" tests. Inherits so that it will be a distinct type.
342/// @tparam T The type parameter of a given test instantiation
343template <typename T>
345
346// Declare the three test suites for Google Test; test cases will all be added to one of these.
349
350/// @test A default-constructed `inline_vector` is empty
351TYPED_TEST_P(InlineVectorTest, CanConstructAnEmptyVector) { ASSERT_TRUE(TestFixture::construct().empty()); }
352
353/// @test The capacity of a default-constructed `inline_vector` is equal to the supplied template parameter
355 COND_STATIC_ASSERT_EQ(TestFixture::construct().capacity(), TypeParam::capacity);
356}
357
358/// @test The `capacity` member function of `inline_vector` is declared `noexcept`
360 STATIC_ASSERT_TRUE(noexcept(TestFixture::construct().capacity()));
361}
362
363/// @test The size of a default-constructed `inline_vector` is zero
364TYPED_TEST_P(InlineVectorTest, InitialSizeIsZero) { EXPECT_EQ(TestFixture::construct().size(), 0); }
365
366/// @test The size of an `inline_vector` initialized from a list of values is correct in a `constexpr` context
367TYPED_TEST_P(InlineVectorTest, SizeIsConstexpr) {
368 COND_STATIC_ASSERT_EQ(TestFixture::full_test_vector().size(), TypeParam::capacity);
369}
370
371/// @test The `size` member function of `inline_vector` is declared `noexcept`
372TYPED_TEST_P(InlineVectorTest, SizeIsNoexcept) { STATIC_ASSERT_TRUE(noexcept(TestFixture::construct().size())); }
373
374/// @test Using `push_back` to add an item to a default-constructed `inline_vector` increases the size
375TYPED_TEST_P(InlineVectorTest, CanPushBackAValue) {
376 TypeParam vec;
377 vec.push_back(TestFixture::test_value(0));
378 EXPECT_EQ(vec.size(), 1);
379}
380
381/// @test After using `push_back` to add an item to a default-constructed `inline_vector`, that item can be retrieved
382/// via the `back` member function
384 TypeParam vec;
385 vec.push_back(TestFixture::test_value(0));
386 EXPECT_EQ(vec.back(), TestFixture::test_value(0));
387}
388
389/// @test After using `push_back` to add an item to a default-constructed `inline_vector`, the vector is no longer empty
391 TypeParam vec;
392 vec.push_back(TestFixture::test_value(0));
393 ASSERT_FALSE(vec.empty());
394}
395
396/// @test After using `push_back` twice to add two items to a default-constructed `inline_vector`, the size is
397/// incremented to 2, and the second item can be retrieved via the `back` member function
399 TypeParam vec;
400 vec.push_back(TestFixture::test_value(0));
401 vec.push_back(TestFixture::test_value(1));
402 EXPECT_EQ(vec.size(), 2);
403 EXPECT_EQ(vec.back(), TestFixture::test_value(1));
404}
405
406/// @test `push_back` of an rvalue is `noexcept` if and only if the value type can be constructed without throwing from
407/// an rvalue
409 constexpr bool move_noexcept = std::is_nothrow_move_constructible<typename TypeParam::value_type>{};
410 STATIC_ASSERT_EQ(
411 noexcept(TestFixture::construct().push_back(std::declval<typename TypeParam::value_type&&>())),
412 move_noexcept
413 );
414}
415
416/// @test `push_back` of an lvalue is `noexcept` if and only if the value type can be constructed without throwing from
417/// an lvalue
419 InlineVectorTest,
421 std::is_copy_constructible<typename TypeParam::value_type>::value
422) {
423 constexpr bool copy_noexcept = std::is_nothrow_copy_constructible<typename TypeParam::value_type>{};
424 STATIC_ASSERT_EQ(
425 noexcept(TestFixture::construct().push_back(std::declval<typename TypeParam::value_type const&>())),
426 copy_noexcept
427 );
428}
429
430/// @test A default-constructed `inline_vector` is empty in a constexpr context
431TYPED_TEST_P(InlineVectorTest, EmptyIsConstexpr) { COND_STATIC_ASSERT_TRUE(TestFixture::construct().empty()); }
432
433/// @test The `empty` member function of `inline_vector` is `noexcept`
434TYPED_TEST_P(InlineVectorTest, EmptyIsNoexcept) { STATIC_ASSERT_TRUE(noexcept(TestFixture::construct().empty())); }
435
436/// @test The `at` member function throws a `std::out_of_range` exception when invoked with an index of 0 on
437/// a default-constructed `inline_vector`
439#if ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) // conditional removal of at() tests based on exception state.
440 ASSERT_THROW(TestFixture::construct().at(0), std::out_of_range);
441#else
442 GTEST_SKIP() << "`at` tests skipped because exceptions are disabled";
443#endif // ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) conditional removal
444}
445
446/// @test The `at` member function returns the value stored when invoked with an index of 0 on a
447/// `inline_vector` into which one element has been stored via `push_back`
449#if ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) // conditional removal of at() tests based on exception state.
450 auto vec = TestFixture::construct();
451 vec.push_back(TestFixture::test_value(0));
452 EXPECT_EQ(vec[0], TestFixture::test_value(0));
453#else
454 GTEST_SKIP() << "`at` tests skipped because exceptions are disabled";
455#endif // ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) conditional removal
456}
457
458/// @test The return type of the `at` member function on a non-`const` `inline_vector` is a non-`const` reference to
459/// `value_type`
461#if ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) // conditional removal of at() tests based on exception state.
462 ::testing::StaticAssertTypeEq<decltype(std::declval<TypeParam&>().at(0)), typename TypeParam::value_type&>();
463#else
464 GTEST_SKIP() << "`at` tests skipped because exceptions are disabled";
465#endif // ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) conditional removal
466}
467
468/// @test The return type of the `at` member function on a `const` `inline_vector` is a `const` reference to
469/// `value_type`
471#if ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) // conditional removal of at() tests based on exception state.
472 ::testing::
473 StaticAssertTypeEq<decltype(std::declval<TypeParam const&>().at(0)), typename TypeParam::value_type const&>();
474#else
475 GTEST_SKIP() << "`at` tests skipped because exceptions are disabled";
476#endif // ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) conditional removal
477}
478
479/// @test The `at` member function returns the corresponding value stored when invoked with an index of 0 or
480/// 1 on an `inline_vector` into which two elements have been stored via `push_back`
482#if ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) // conditional removal of at() tests based on exception state.
483 auto vec = TestFixture::construct();
484 vec.push_back(TestFixture::test_value(0));
485 vec.push_back(TestFixture::test_value(1));
486
487 EXPECT_EQ(vec.at(0), TestFixture::test_value(0));
488 EXPECT_EQ(vec.at(1), TestFixture::test_value(1));
489#else
490 GTEST_SKIP() << "`at` tests skipped because exceptions are disabled";
491#endif // ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) conditional removal
492}
493
494/// @test The `at` member function throws when invoked with an index that is equal to or larger than the size of the
495/// vector on an `inline_vector` into which two elements have been stored via `push_back`
497#if ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) // conditional removal of at() tests based on exception state.
498 auto vec = TestFixture::construct();
499 vec.push_back(TestFixture::test_value(0));
500
501 ASSERT_THROW(vec.at(vec.size()), std::out_of_range);
502 ASSERT_THROW(vec.at(vec.size() * 2), std::out_of_range);
503 ASSERT_THROW(vec.at(std::numeric_limits<std::size_t>::max()), std::out_of_range);
504#else
505 GTEST_SKIP() << "`at` tests skipped because exceptions are disabled";
506#endif // ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) conditional removal
507}
508
509/// @test The `at` member function returns the corresponding value stored when invoked via a `const` reference to a
510/// vector with an index of 0 or 1 on an `inline_vector` into which two elements have been stored via `push_back`.
512#if ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) // conditional removal of at() tests based on exception state.
513 auto vec = TestFixture::construct();
514 vec.push_back(TestFixture::test_value(0));
515 vec.push_back(TestFixture::test_value(1));
516
517 auto const& const_vec = vec;
518 EXPECT_EQ(const_vec.at(0), TestFixture::test_value(0));
519 EXPECT_EQ(const_vec.at(1), TestFixture::test_value(1));
520#else
521 GTEST_SKIP() << "`at` tests skipped because exceptions are disabled";
522#endif // ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) conditional removal
523}
524
525/// @test The `at` member function throws when invoked via a `const` reference to a vector with an index that is equal
526/// to or larger than the size of an `inline_vector` into which two elements have been stored via `push_back`
528#if ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) // conditional removal of at() tests based on exception state.
529 auto vec = TestFixture::construct();
530 vec.push_back(TestFixture::test_value(0));
531
532 auto const& const_vec = vec;
533
534 ASSERT_THROW(const_vec.at(vec.size()), std::out_of_range);
535 ASSERT_THROW(const_vec.at(vec.size() * 2), std::out_of_range);
536 ASSERT_THROW(const_vec.at(std::numeric_limits<std::size_t>::max()), std::out_of_range);
537#else
538 GTEST_SKIP() << "`at` tests skipped because exceptions are disabled";
539#endif // ARENE_IS_ON(ARENE_EXCEPTIONS_ENABLED) conditional removal of at() tests based on exception state.
540}
541
542/// @test The `max_size` member function of `inline_vector` returns the capacity specified as a template parameter.
544 COND_STATIC_ASSERT_EQ(TestFixture::construct().max_size(), TypeParam::capacity);
545 COND_STATIC_ASSERT_TRUE(noexcept(TestFixture::construct().max_size()));
546}
547
548/// @test Invoking `push_back` on a vector that is at capacity terminates the program with a precondition violation.
550 auto vec = TestFixture::construct();
551 for (std::size_t i = 0; i < vec.max_size(); ++i) {
552 vec.push_back(TestFixture::test_value(0));
553 }
554 ASSERT_DEATH(vec.push_back(TestFixture::test_value(0)), "Precondition violation");
555}
556
557/// @test The size of a default-constructed vector with a capacity of zero is zero, when obtained via the
558/// `size` member function, and via comparing the iterators returned from `begin` and `end`
560 inline_vector<typename TypeParam::value_type, 0> const zvec;
561 inline_vector<typename TypeParam::value_type const, 0> const czvec;
562 ASSERT_EQ(zvec.begin(), zvec.end());
563 ASSERT_EQ(czvec.begin(), czvec.end());
564 ASSERT_EQ(zvec.size(), 0);
565 ASSERT_EQ(czvec.size(), 0);
566}
567
568/// @test Invoking `push_back` on a zero-capacity vector terminates the program with a precondition violation
570 inline_vector<typename TypeParam::value_type, 0> vec{};
571 ASSERT_DEATH(vec.push_back(TestFixture::test_value(0)), "Precondition violation");
572}
573
574/// @test Given a default-constructed `inline_vector`, after one element has been added via `push_back`, `back` returns
575/// a reference to that element. After a second element has been added via `push_back`, `back` now returns a reference
576/// to the second element.
578 auto vec = TestFixture::construct();
579
580 vec.push_back(TestFixture::test_value(0));
581 typename TypeParam::value_type& val1 = vec.back();
582 EXPECT_EQ(std::addressof(val1), std::addressof(vec[0]));
583
584 if (TypeParam::capacity >= 2UL) {
585 vec.push_back(TestFixture::test_value(1));
586 typename TypeParam::value_type& val2 = vec.back();
587 EXPECT_EQ(std::addressof(val2), std::addressof(vec[1]));
588 }
589}
590
591/// @test Given a default-constructed `inline_vector`, after one element has been added via `push_back`, `back` called
592/// via a `const` reference to the vector returns a `const` reference to that element. After a second element has been
593/// added via `push_back`, `back` called via a `const` reference to the vector now returns a `const` reference to the
594/// second element.
596 auto vec = TestFixture::construct();
597 auto const& const_vec = vec;
598
599 vec.push_back(TestFixture::test_value(0));
600 auto& val1 = const_vec.back();
601 ::testing::StaticAssertTypeEq<decltype(val1), typename TypeParam::value_type const&>();
602 EXPECT_EQ(std::addressof(val1), &const_vec[0]);
603
604 if (TypeParam::capacity >= 2UL) {
605 vec.push_back(TestFixture::test_value(1));
606 auto& val2 = const_vec.back();
607 ::testing::StaticAssertTypeEq<decltype(val2), typename TypeParam::value_type const&>();
608 EXPECT_EQ(std::addressof(val2), &const_vec[1]);
609 }
610}
611
612/// @test Invoking `back` cannot throw
613TYPED_TEST_P(InlineVectorTest, BackIsNoexcept) {
614 STATIC_ASSERT_TRUE(noexcept(std::declval<TypeParam&>().back()));
615 STATIC_ASSERT_TRUE(noexcept(std::declval<TypeParam const&>().back()));
616}
617
618/// @test In a `constexpr` context, an `inline_vector` can be default-constructed, and a new value inserted via
619/// `push_back`, such that the `size` of the container is now 1, and the value can be retrieved via `at(0)`
621 constexpr auto vec = TestFixture::test_vector(1);
622 STATIC_ASSERT_EQ(vec.size(), 1);
623 STATIC_ASSERT_EQ(vec[0], TestFixture::test_value(0));
624}
625
626/// @test An `inline_vector` can be constructed from a `std::initializer_list` without throwing exceptions, and the size
627/// and values stored in the vector are the same as the size and values of the initializer list.
629 InlineVectorTest,
631 std::is_copy_constructible<typename TypeParam::value_type>::value
632) {
633 auto const values = TestFixture::full_test_initializer_list();
634
635 TypeParam const vec{values};
636 STATIC_ASSERT_EQ(noexcept(TypeParam{values}), std::is_nothrow_copy_constructible<typename TypeParam::value_type>{});
637
638 EXPECT_THAT(vec, ::testing::ElementsAreArray(values));
639}
640
641/// @test An `inline_vector` can be constructed from a `std::initializer_list` in a `constexpr` context, and the
642/// elements are those from the initializer list
644 InlineVectorTest,
646 InlineVectorTest<TypeParam>::constexpr_compatible&&
648) {
649 constexpr auto values = TestFixture::full_test_initializer_list();
650
651 constexpr TypeParam vec{values};
652
653 EXPECT_THAT(vec, ::testing::ElementsAreArray(values));
654}
655
656template <typename Vec>
657constexpr auto constexpr_non_const_back(Vec&& vec) -> typename Vec::value_type {
658 static_assert(std::is_rvalue_reference<Vec&&>::value, "Only expected to be called with an r-value reference.");
659 return std::forward<Vec>(vec).back();
660}
661
662/// @test Given a `constexpr` `inline_vector` constructed by pushing back values, `back` can be used in a `constexpr`
663/// context to retrieve the last value in the vector, which must therefore equal the last value pushed back
665 constexpr auto vec = TestFixture::full_test_vector();
666 STATIC_ASSERT_EQ(vec.back(), TestFixture::test_value(TypeParam::capacity - 1UL));
667 STATIC_ASSERT_EQ(
668 constexpr_non_const_back(TestFixture::full_test_vector()),
669 TestFixture::test_value(TypeParam::capacity - 1UL)
670 );
671}
672
673/// @test Given an `inline_vector` initialized by pushing back values, the `front` member function can be used to
674/// retrieve the first value, which must be equal to the first value of the vector as retrieved via `at(0)`
675TYPED_TEST_P(InlineVectorTest, CanGetFront) {
676 auto vec = TestFixture::full_test_vector();
677 EXPECT_EQ(std::addressof(vec.front()), std::addressof(vec[0]));
678 ::testing::StaticAssertTypeEq<decltype(vec.front()), typename TypeParam::value_type&>();
679 STATIC_ASSERT_TRUE(noexcept(vec.front()));
680 auto const& const_vec = vec;
681 EXPECT_EQ(&const_vec.front(), &const_vec[0]);
682 ::testing::StaticAssertTypeEq<decltype(const_vec.front()), typename TypeParam::value_type const&>();
683 STATIC_ASSERT_TRUE(noexcept(const_vec.front()));
684}
685
686template <typename Vec>
687constexpr auto constexpr_non_const_front(Vec&& vec) -> typename Vec::value_type {
688 static_assert(std::is_rvalue_reference<Vec&&>::value, "Only expected to be called with an r-value reference.");
689 return std::forward<Vec>(vec).front();
690}
691
692/// @test Given an instance of `inline_vector` by pushing back values in a `constexpr` context, the
693/// `front` member function can be used in a `constexpr` context to retrieve the first value, which must be equal to the
694/// first value of the pushed back
696 constexpr auto vec = TestFixture::full_test_vector();
697 STATIC_ASSERT_EQ(vec.front(), TestFixture::test_value(0));
698 STATIC_ASSERT_EQ(constexpr_non_const_front(TestFixture::full_test_vector()), TestFixture::test_value(0));
699}
700
701/// @test The `begin` and `end` member functions of an `inline_vector` must return an `iterator`, and they must be equal
702/// for a default-constructed vector
703TYPED_TEST_P(InlineVectorTest, CanGetIterator) {
704 auto vec = TestFixture::construct();
705 ::testing::StaticAssertTypeEq<decltype(vec.begin()), typename TypeParam::iterator>();
706 ::testing::StaticAssertTypeEq<decltype(vec.end()), typename TypeParam::iterator>();
707 STATIC_ASSERT_TRUE(noexcept(vec.begin()));
708 STATIC_ASSERT_TRUE(noexcept(vec.end()));
709 EXPECT_EQ(vec.begin(), vec.end());
710}
711
712/// @test Given an `inline_vector` constructed by pushing back values, the iterators returned from `begin` and `end`
713/// can be passed as an iterator pair to `arene::base::equal` to compare the values in the vector to those in the
714/// initializer list, which must return @c true, to indicate that the values are the same.
716 auto const values = TestFixture::full_test_initializer_list();
717 auto const vec = TestFixture::full_test_vector();
718 ASSERT_TRUE(arene::base::equal(values.begin(), values.end(), vec.begin(), vec.end()));
719}
720
721/// @test Given a `const` `inline_vector` constructed by pushing back values, the iterators returned from `begin` and
722/// `end` can be passed as an iterator pair to `arene::base::equal` to compare the values in the vector to those in the
723/// initializer list, which must return @c true, to indicate that the values are the same.
725 auto const values = TestFixture::full_test_initializer_list();
726 auto const vec = TestFixture::full_test_vector();
727 ASSERT_TRUE(arene::base::equal(values.begin(), values.end(), vec.begin(), vec.end()));
728}
729
730/// @test The `iterator` type of an `inline_vector` must have the required type aliases for a random-access iterator.
731TYPED_TEST_P(InlineVectorTest, IteratorTypedefs) {
732 using value_type = typename TypeParam::value_type;
733 ::testing::StaticAssertTypeEq<typename TypeParam::iterator::value_type, value_type>();
734 ::testing::StaticAssertTypeEq<typename TypeParam::iterator::reference, value_type&>();
735 ::testing::StaticAssertTypeEq<typename TypeParam::iterator::pointer, value_type*>();
736 ::testing::StaticAssertTypeEq<typename TypeParam::iterator::difference_type, std::ptrdiff_t>();
737 ::testing::StaticAssertTypeEq<typename TypeParam::iterator::iterator_category, std::random_access_iterator_tag>();
738
739 ::testing::StaticAssertTypeEq<typename TypeParam::const_iterator::value_type, value_type>();
740 ::testing::StaticAssertTypeEq<typename TypeParam::const_iterator::reference, value_type const&>();
741 ::testing::StaticAssertTypeEq<typename TypeParam::const_iterator::pointer, value_type const*>();
742 ::testing::StaticAssertTypeEq<typename TypeParam::const_iterator::difference_type, std::ptrdiff_t>();
743 ::testing::StaticAssertTypeEq<typename TypeParam::const_iterator::iterator_category, std::random_access_iterator_tag>(
744 );
745}
746
747/// @test `inline_vector` must have the required type aliases for a sequence container
748TYPED_TEST_P(InlineVectorTest, Typedefs) {
749 using value_type = typename TypeParam::value_type;
750 ::testing::StaticAssertTypeEq<typename TypeParam::value_type, value_type>();
751 ::testing::StaticAssertTypeEq<typename TypeParam::pointer, value_type*>();
752 ::testing::StaticAssertTypeEq<typename TypeParam::const_pointer, value_type const*>();
753 ::testing::StaticAssertTypeEq<typename TypeParam::reference, value_type&>();
754 ::testing::StaticAssertTypeEq<typename TypeParam::const_reference, value_type const&>();
755 ::testing::StaticAssertTypeEq<typename TypeParam::size_type, std::size_t>();
756 ::testing::StaticAssertTypeEq<typename TypeParam::difference_type, std::ptrdiff_t>();
757 ::testing::StaticAssertTypeEq<
758 typename TypeParam::reverse_iterator,
759 ::arene::base::reverse_iterator<typename TypeParam::iterator>>();
760 ::testing::StaticAssertTypeEq<
761 typename TypeParam::const_reverse_iterator,
762 ::arene::base::reverse_iterator<typename TypeParam::const_iterator>>();
763}
764
765/// @brief Check that iteration works when taking a vector with the given type
766/// @tparam Vec The type to take the vector as; intended to be a value type either with const or without
767/// @param values The values expected to be included in the vector
768/// @param vec The vector to check
769/// @return @c true if @c values and @c vec have the same contents, @c false if not
770template <typename Vec>
771constexpr auto constexpr_iterate(std::initializer_list<typename Vec::value_type> const values, Vec vec) -> bool {
772 // This test is specifically testing a range-based for loop, so we do that even though the iteration gets weird
773 auto val_it = values.begin();
774 for (auto const& vec_val : vec) {
775 if (val_it == values.end()) {
776 return false; // The ranges are unequal if this happens while there are still values in `vec`
777 }
778 if (vec_val != *val_it) {
779 return false;
780 }
781 ++val_it;
782 }
783
784 return val_it == values.end(); // If this reached the end and all elements were equal, the ranges are equal
785}
786
787/// @test It is possible to iterate over the values in a mutable `inline_vector` using a ranged-`for` loop in a
788/// `constexpr` context.
790 STATIC_ASSERT_TRUE(
791 constexpr_iterate<TypeParam>(TestFixture::full_test_initializer_list(), TestFixture::full_test_vector())
792 );
793}
794
795/// @test It is possible to iterate over the values in a const `inline_vector` using a ranged-`for` loop in a
796/// `constexpr` context.
798 STATIC_ASSERT_TRUE(
799 constexpr_iterate<TypeParam const>(TestFixture::full_test_initializer_list(), TestFixture::full_test_vector())
800 );
801}
802
803/// @test Given a non-empty `inline_vector`, invoking `erase` with the iterator returned from `begin` removes the first
804/// element, moving the remaining elements to one lower index and decreasing the size by one, and returns an iterator to
805/// the new first element.
807 auto vec = TestFixture::full_test_vector();
808
809 STATIC_ASSERT_TRUE(std::is_same<
810 decltype(vec.erase(std::declval<typename TypeParam::const_iterator>())),
811 typename TypeParam::iterator>::value);
812 auto const pos = vec.erase(vec.begin());
813 EXPECT_EQ(pos, vec.begin());
814 EXPECT_EQ(vec.size(), TypeParam::capacity - 1UL);
815 if (TypeParam::capacity >= 2) {
816 EXPECT_EQ(vec[0], TestFixture::test_value(1));
817 }
818 if (TypeParam::capacity >= 3) {
819 EXPECT_EQ(vec[1], TestFixture::test_value(2));
820 }
821 if (TypeParam::capacity >= 4) {
822 EXPECT_EQ(vec[2], TestFixture::test_value(3));
823 }
824}
825
826/// @test Given a non-empty `inline_vector`, invoking `erase` with an iterator referring to an element that is neither
827/// the first or last element removes that element, moves the following elements to one lower index, reduces the size by
828/// one, and returns an iterator to the element that replaced the erased element.
830 auto vec = TestFixture::full_test_vector();
831
832 STATIC_ASSERT_TRUE(std::is_same<
833 decltype(vec.erase(std::declval<typename TypeParam::const_iterator>())),
834 typename TypeParam::iterator>::value);
835 auto pos = vec.erase(vec.begin() + 1);
836 EXPECT_EQ(pos, vec.begin() + 1);
837 EXPECT_EQ(vec.size(), TypeParam::capacity - 1UL);
838 EXPECT_EQ(vec[0], TestFixture::test_value(0));
839 if (TypeParam::capacity >= 3) {
840 EXPECT_EQ(vec[1], TestFixture::test_value(2));
841 }
842 if (TypeParam::capacity >= 4) {
843 EXPECT_EQ(vec[2], TestFixture::test_value(3));
844 }
845}
846
847template <typename Vec, typename... Args>
848constexpr auto constexpr_erase(std::size_t index, Args&&... args) -> Vec {
849 Vec vec{};
850 vector_push_back(vec, std::forward<Args>(args)...);
851 vec.erase(vec.begin() + static_cast<std::ptrdiff_t>(index));
852 return vec;
853}
854
855/// @test In a `constexpr` context, given a non-empty `inline_vector`, invoking `erase` with an iterator referring to an
856/// element that is neither the first or last element removes that element, moves the following elements to one lower
857/// index, reduces the size by one.
859 InlineVectorTest,
860 CanErase,
861 InlineVectorTest<TypeParam>::constexpr_compatible&& TypeParam::capacity >= 4
862) {
863 constexpr auto vec = constexpr_erase<TypeParam>(
864 2,
865 TestFixture::test_value(0),
866 TestFixture::test_value(1),
867 TestFixture::test_value(2),
868 TestFixture::test_value(3)
869 );
870 STATIC_ASSERT_EQ(vec.size(), 3);
871 STATIC_ASSERT_EQ(vec[0], TestFixture::test_value(0));
872 STATIC_ASSERT_EQ(vec[1], TestFixture::test_value(1));
873 STATIC_ASSERT_EQ(vec[2], TestFixture::test_value(3));
874}
875
876/// @test Invoking `erase` with an iterator range referring to elements in the same `inline_vector`, removes those
877/// elements, moves the following elements to take their place, and returns an iterator with the same offset from the
878/// beginning of the vector as the first erased element
880 auto vec = TestFixture::construct();
881 constexpr std::size_t erase_start = 2;
882 constexpr std::size_t erase_end = 5;
883 arene::base::array<arene::base::optional<typename TypeParam::value_type>, TypeParam::capacity> expected;
884 std::size_t expected_pos{0};
885 for (std::size_t idx = 0; idx < TypeParam::capacity; ++idx) {
886 vec.push_back(TestFixture::test_value(idx));
887 if (idx < erase_start || idx >= erase_end) {
888 expected[expected_pos].emplace(TestFixture::test_value(idx));
889 ++expected_pos;
890 }
891 }
892
893 ::testing::StaticAssertTypeEq<
894 decltype(vec.erase(
895 std::declval<typename TypeParam::const_iterator>(),
896 std::declval<typename TypeParam::const_iterator>()
897 )),
898 typename TypeParam::iterator>();
899 auto const pos = vec.erase(vec.begin() + erase_start, vec.begin() + erase_end);
900 EXPECT_EQ(pos, vec.begin() + erase_start);
901 ASSERT_EQ(vec.size(), expected_pos);
902 EXPECT_TRUE(elements_are_array(vec, expected));
903}
904
905/// @test Constructing with just a size creates a vector with that many default-constructed elements
907 InlineVectorTest,
910) {
911 auto value_vec = TestFixture::construct(TypeParam::capacity);
912
913 STATIC_ASSERT_EQ(noexcept(TypeParam(0)), std::is_nothrow_default_constructible<typename TypeParam::value_type>{});
914 EXPECT_EQ(value_vec.size(), TypeParam::capacity);
915 EXPECT_TRUE(all_elements_are(value_vec, typename TypeParam::value_type{}));
916}
917
918/// @test Constructing an `inline_vector` with a count and a value creates the specified number of elements
919/// copy-constructed from the supplied value, and sets the `size` of the vector to that count.
921 InlineVectorTest,
923 std::is_copy_constructible<typename TypeParam::value_type>::value
924) {
925 auto const value = TestFixture::test_value(0);
926 auto const value_vec = TestFixture::construct(TypeParam::capacity, value);
927
928 STATIC_ASSERT_EQ(
929 noexcept(TypeParam(TypeParam::capacity, value)),
930 std::is_nothrow_copy_constructible<typename TypeParam::value_type>{}
931 );
932 EXPECT_EQ(value_vec.size(), TypeParam::capacity);
933 EXPECT_THAT(value_vec, ::testing::Each(::testing::Eq(value)));
934}
935
936/// @test The `inline_vector` copy constructor copies the stored elements and size from the original vector.
938 InlineVectorTest,
940 std::is_copy_constructible<typename TypeParam::value_type>::value
941) {
942 auto const vec = TestFixture::full_test_vector();
943 // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
944 auto const copy(vec);
945
946 EXPECT_THAT(copy, ::testing::ElementsAreArray(vec));
947}
948
949/// @test The `inline_vector` move constructor moves the stored elements from the original vector
951 auto const values = TestFixture::full_test_initializer_list();
952 auto vec = TestFixture::full_test_vector();
953
954 // NOLINTNEXTLINE(hicpp-move-const-arg)
955 TypeParam const moved(std::move(vec));
956 EXPECT_TRUE(elements_are_array(moved, values));
957}
958
959/// @test The `inline_vector` copy-assignment operator uses copy assignment for elements from the source where there is
960/// already a corresponding element in the destination, and copy construction for elements that do not have a
961/// corresponding element in the destination
963 constexpr std::size_t count = TypeParam::capacity;
964 constexpr std::size_t smaller_count = TypeParam::capacity - 1UL;
965
966 auto vec = TestFixture::test_vector(count);
967 auto copy = TestFixture::test_vector(smaller_count);
968 copy = vec;
969
970 ASSERT_EQ(vec.size(), count);
971 ASSERT_EQ(copy.size(), count);
972 for (std::size_t i = 0; i < count; ++i) {
973 EXPECT_EQ(vec[i], copy[i]);
974 EXPECT_EQ(TestFixture::test_value(i), copy[i]);
975 }
976}
977
978/// @test The `inline_vector` copy-assignment operator destroys the excess elements in the destination when the source
979/// vector has fewer elements than the destination vector
981 constexpr std::size_t count = TypeParam::capacity - 1UL;
982 constexpr std::size_t larger_count = TypeParam::capacity;
983
984 auto vec = TestFixture::test_vector(count);
985 auto copy = TestFixture::test_vector(larger_count);
986 copy = vec;
987
988 ASSERT_EQ(vec.size(), count);
989 ASSERT_EQ(copy.size(), count);
990 for (std::size_t i = 0; i < count; ++i) {
991 EXPECT_EQ(vec[i], copy[i]);
992 EXPECT_EQ(TestFixture::test_value(i), copy[i]);
993 }
994}
995
996/// @test Copy-assignment for `inline_vector` is `noexcept` if and only if the stored element type is both
997/// nothrow-copy-constructible and nothrow-copy-assignable
999 using short_vec = typename TestFixture::template vector_with_capacity<TypeParam::capacity>;
1000 using vec = typename TestFixture::template vector_with_capacity<TypeParam::capacity + 1UL>;
1001
1002 constexpr bool should_be_copyable = std::is_copy_constructible<typename TypeParam::value_type>{} &&
1003 std::is_copy_assignable<typename TypeParam::value_type>{};
1004 STATIC_ASSERT_EQ(
1005 std::is_copy_constructible<vec>::value,
1006 std::is_copy_constructible<typename TypeParam::value_type>::value
1007 );
1008 STATIC_ASSERT_EQ(std::is_copy_assignable<vec>{}, should_be_copyable);
1009 STATIC_ASSERT_EQ((std::is_assignable<short_vec&, vec const&>{}), should_be_copyable);
1010 STATIC_ASSERT_EQ((std::is_assignable<vec&, short_vec const&>{}), should_be_copyable);
1011
1012 constexpr bool assign_noexcept = std::is_nothrow_copy_constructible<typename TypeParam::value_type>{} &&
1013 std::is_nothrow_copy_assignable<typename TypeParam::value_type>{};
1014 STATIC_ASSERT_EQ(
1015 std::is_nothrow_copy_constructible<vec>::value,
1016 std::is_nothrow_copy_constructible<typename TypeParam::value_type>::value
1017 );
1018 STATIC_ASSERT_EQ(std::is_nothrow_copy_assignable<vec>{}, assign_noexcept);
1019 STATIC_ASSERT_EQ((std::is_nothrow_assignable<short_vec&, vec const&>{}), assign_noexcept);
1020 STATIC_ASSERT_EQ((std::is_nothrow_assignable<vec&, short_vec const&>{}), assign_noexcept);
1021}
1022
1023/// @test The `inline_vector` move-assignment operator uses move assignment for elements from the source where there is
1024/// already a corresponding element in the destination, and move construction for elements that do not have a
1025/// corresponding element in the destination
1027 constexpr std::size_t count = TypeParam::capacity;
1028 constexpr std::size_t smaller_count = TypeParam::capacity - 1UL;
1029
1030 auto first = TestFixture::construct();
1031 arene::base::array<arene::base::optional<typename TypeParam::value_type>, TypeParam::capacity> expected;
1032 std::size_t expected_pos{0};
1033 for (std::size_t idx = 0; idx < count; ++idx) {
1034 first.push_back(TestFixture::test_value(idx));
1035 expected[expected_pos].emplace(TestFixture::test_value(idx));
1036 ++expected_pos;
1037 }
1038
1039 auto second = TestFixture::test_vector(smaller_count);
1040 // NOLINTNEXTLINE(hicpp-move-const-arg)
1041 second = std::move(first);
1042
1043 EXPECT_EQ(second.size(), count);
1044 EXPECT_TRUE(elements_are_array(second, expected));
1045}
1046
1047/// @test The `inline_vector` move-assignment operator destroys the excess elements in the destination when the source
1048/// vector has fewer elements than the destination vector
1050 constexpr std::size_t count = TypeParam::capacity - 1UL;
1051 constexpr std::size_t larger_count = TypeParam::capacity;
1052
1053 auto first = TestFixture::test_vector(count);
1054 auto second = TestFixture::test_vector(larger_count);
1055 second = std::move(first);
1056
1057 ASSERT_EQ(second.size(), count);
1058 for (std::size_t i = 0; i < count; ++i) {
1059 EXPECT_EQ(TestFixture::test_value(i), second[i]);
1060 }
1061}
1062
1063/// @test Move-assignment for `inline_vector` is `noexcept` if and only if the value type is nothrow-move-constructible
1064/// and nothrow-move-assignable
1066 using short_vec = typename TestFixture::template vector_with_capacity<TypeParam::capacity>;
1067 using vec = typename TestFixture::template vector_with_capacity<TypeParam::capacity + 1UL>;
1068
1069 constexpr bool should_be_movable = std::is_move_assignable<typename TypeParam::value_type>{} &&
1070 std::is_move_constructible<typename TypeParam::value_type>{};
1071 STATIC_ASSERT_EQ(std::is_move_constructible<vec>{}, should_be_movable);
1072 STATIC_ASSERT_EQ(std::is_move_assignable<vec>{}, should_be_movable);
1073 STATIC_ASSERT_EQ((std::is_assignable<short_vec&, vec>{}), should_be_movable);
1074 STATIC_ASSERT_EQ((std::is_assignable<vec&, short_vec>{}), should_be_movable);
1075
1076 constexpr bool assign_should_be_noexcept = std::is_nothrow_move_assignable<typename TypeParam::value_type>{} &&
1077 std::is_nothrow_move_constructible<typename TypeParam::value_type>{};
1078 STATIC_ASSERT_EQ(
1079 std::is_nothrow_move_constructible<vec>::value,
1080 std::is_nothrow_move_constructible<typename TypeParam::value_type>::value
1081 );
1082 STATIC_ASSERT_EQ(std::is_nothrow_move_assignable<vec>{}, assign_should_be_noexcept);
1083 STATIC_ASSERT_EQ((std::is_nothrow_assignable<short_vec&, vec>{}), assign_should_be_noexcept);
1084 STATIC_ASSERT_EQ((std::is_nothrow_assignable<vec&, short_vec>{}), assign_should_be_noexcept);
1085}
1086
1087// A Matcher that checks if the elements in an argument (by index) match the result of calling a function with the index
1088// NOLINTNEXTLINE(modernize-use-trailing-return-type) The declaration happens in a macro and we can't control it
1090 for (std::size_t ii = 0; ii < arg.size(); ++ii) {
1091 if (arg[ii] != function(ii)) {
1092 return false;
1093 }
1094 }
1095
1096 return true;
1097}
1098
1099/// @test Invoking `pop_back` on a non-empty `inline_vector` destroys the last element and reduces the size by one.
1100TYPED_TEST_P(InlineVectorTest, CanPopBack) {
1101 auto vec = TestFixture::test_vector(TypeParam::capacity - 1UL);
1102
1103 vec.push_back(TestFixture::test_value(TypeParam::capacity - 1UL));
1104 vec.pop_back();
1105
1106 EXPECT_EQ(vec.size(), TypeParam::capacity - 1UL);
1107 EXPECT_THAT(vec, elements_match_function(TestFixture::test_value));
1108}
1109
1110/// @test `pop_back` is declared `noexcept`
1112 STATIC_ASSERT_TRUE(noexcept(std::declval<TypeParam>().pop_back()));
1113}
1114
1115template <typename Vec>
1116constexpr auto constexpr_pop_back(Vec&& vec) -> Vec {
1117 static_assert(std::is_rvalue_reference<Vec&&>::value, "Only expected to be called with an r-value reference.");
1118 std::forward<Vec>(vec).pop_back();
1119 return std::forward<Vec>(vec);
1120}
1121
1122/// @test In a `constexpr` context, `pop_back` removes the last element of a non-empty vector
1124 constexpr auto vec = constexpr_pop_back<TypeParam>(TestFixture::full_test_vector());
1125 STATIC_ASSERT_EQ(vec.size(), TypeParam::capacity - 1UL);
1126
1127 if (TypeParam::capacity >= 2) {
1128 EXPECT_EQ(vec[0], TestFixture::test_value(0));
1129 }
1130 if (TypeParam::capacity >= 3) {
1131 EXPECT_EQ(vec[1], TestFixture::test_value(1));
1132 }
1133 if (TypeParam::capacity >= 4) {
1134 EXPECT_EQ(vec[2], TestFixture::test_value(2));
1135 }
1136}
1137
1138/// @test `erase` is `noexcept` if and only if the element type has `noexcept` move assignment
1140 auto vec = TestFixture::construct();
1141
1142 STATIC_ASSERT_EQ(
1143 noexcept(vec.erase(vec.begin(), vec.end())),
1144 std::is_nothrow_move_assignable<typename TypeParam::value_type>{}
1145 );
1146 STATIC_ASSERT_EQ(noexcept(vec.erase(vec.begin())), std::is_nothrow_move_assignable<typename TypeParam::value_type>{});
1147}
1148
1149/// @test Given an empty `inline_vector`, and the iterator returned from `begin`, `insert` can add an element to the
1150/// vector, setting the size to one.
1152 auto vec1 = TestFixture::construct();
1153 auto const& const_vec1 = vec1;
1154 auto const itr = vec1.insert(const_vec1.begin(), TestFixture::test_value(0));
1155 EXPECT_EQ(itr, vec1.begin());
1156 EXPECT_EQ(vec1.size(), 1);
1157 EXPECT_EQ(vec1[0], TestFixture::test_value(0));
1158}
1159
1160/// @test Given an `inline_vector` with existing elements, and the iterator returned from `end`, `insert` can add an
1161/// element to the end of the vector, increasing the size by one
1163 auto vec1 = TestFixture::test_vector(1);
1164 auto const& const_vec1 = vec1;
1165 auto const pos = vec1.insert(const_vec1.end(), TestFixture::test_value(1));
1166 EXPECT_EQ(pos, vec1.begin() + 1);
1167 EXPECT_EQ(vec1.size(), 2);
1168 EXPECT_EQ(vec1[0], TestFixture::test_value(0));
1169 EXPECT_EQ(vec1[1], TestFixture::test_value(1));
1170}
1171
1172/// @test Given an `inline_vector` with existing elements, and an iterator to an existing element in the vector,
1173/// `insert` can add an element at the iterator position, increasing the vector size by one. The existing element at the
1174/// location referenced by the iterator, and the subsequent elements, are moved to make room for the new element.
1176 auto vec1 = TestFixture::test_vector(2);
1177 auto const& const_vec1 = vec1;
1178 auto const pos = vec1.insert(const_vec1.begin() + 1, TestFixture::test_value(2));
1179 EXPECT_EQ(pos, vec1.begin() + 1);
1180 EXPECT_EQ(vec1.size(), 3);
1181 EXPECT_EQ(vec1[0], TestFixture::test_value(0));
1182 EXPECT_EQ(vec1[1], TestFixture::test_value(2));
1183 EXPECT_EQ(vec1[2], TestFixture::test_value(1));
1184}
1185
1186/// @test Invoking `insert` on an `inline_vector` with `size` equal to the capacity terminates the program with a
1187/// precondition violation
1189 InlineVectorDeathTest,
1191 std::is_default_constructible<typename TypeParam::value_type>::value
1192) {
1193 auto vec1 = TestFixture::construct(TypeParam::capacity);
1194 EXPECT_EQ(vec1.size(), TypeParam::capacity);
1195 ASSERT_DEATH(vec1.insert(vec1.end(), TestFixture::test_value(0)), "Precondition violation");
1196 ASSERT_DEATH(vec1.insert(vec1.begin(), TestFixture::test_value(0)), "Precondition violation");
1197 EXPECT_EQ(vec1.size(), TypeParam::capacity);
1198 EXPECT_TRUE(all_elements_are(vec1, typename TypeParam::value_type{}));
1199}
1200
1201/// @test Invoking the `inline_vector` constructor with a count larger than the capacity terminates the program with a
1202/// precondition violation
1204 InlineVectorDeathTest,
1207) {
1208 ASSERT_DEATH(TestFixture::construct(TypeParam::capacity + 1), "Precondition violation");
1209}
1210
1211/// @test Invoking the `inline_vector` constructor with a count and value where the count is larger than the capacity
1212/// terminates the program with a precondition violation
1214 InlineVectorDeathTest,
1216 std::is_copy_constructible<typename TypeParam::value_type>::value
1217) {
1218 auto const source = TestFixture::test_value(0);
1219 ASSERT_DEATH(TestFixture::construct(TypeParam::capacity + 1, source), "Precondition violation");
1220}
1221
1222/// @test Invoking the `inline_vector` constructor with an initializer list with more elements than the capacity
1223/// terminates the program with a precondition violation
1225 InlineVectorDeathTest,
1227 std::is_copy_constructible<typename TypeParam::value_type>::value
1228) {
1229 ASSERT_DEATH(
1230 TestFixture::construct(TestFixture::template test_initializer_list<TypeParam::capacity + 1UL>()),
1231 "Precondition violation"
1232 );
1233}
1234
1235template <typename Vec>
1236constexpr auto constexpr_resize(Vec vec, std::size_t size) -> Vec {
1237 vec.resize(size);
1238 return vec;
1239}
1240
1241/// @test In a constexpr context, invoking `resize` with a count of zero on an `inline_vector` with a capacity of zero
1242/// does nothing
1244 InlineVectorTest,
1247) {
1248 constexpr typename TestFixture::template vector_with_capacity<0> vec{};
1249 constexpr typename TestFixture::template vector_with_capacity<0> vec2 = constexpr_resize(vec, 0);
1250 // NOLINTNEXTLINE(readability-container-size-empty)
1251 STATIC_ASSERT_EQ(vec2.size(), 0);
1252}
1253
1254/// @test In a `constexpr` context, invoking `resize` with a count of zero on an `inline_vector` with a non-zero
1255/// capacity and size sets the size to zero
1257 InlineVectorTest,
1259 InlineVectorTest<TypeParam>::constexpr_compatible&& std::is_default_constructible<typename TypeParam::value_type>{}
1260) {
1261 constexpr auto vec = TestFixture::construct(TypeParam::capacity);
1262 constexpr auto vec2 = constexpr_resize(vec, 0);
1263 // NOLINTNEXTLINE(readability-container-size-empty)
1264 STATIC_ASSERT_EQ(vec2.size(), 0);
1265}
1266
1267/// @test In a `constexpr` context, invoking `resize` with a non-zero count on an `inline_vector` with a non-zero
1268/// capacity and different size sets the size to the specified size
1270 InlineVectorTest,
1272 InlineVectorTest<TypeParam>::constexpr_compatible&& std::is_default_constructible<typename TypeParam::value_type>{}
1273) {
1274 constexpr std::size_t count1 = TypeParam::capacity - 1UL;
1275 constexpr std::size_t count2 = TypeParam::capacity;
1276 constexpr auto vec = TestFixture::construct(count1);
1277 STATIC_ASSERT_EQ(vec.size(), count1);
1278 constexpr auto vec2 = constexpr_resize(vec, count2);
1279 STATIC_ASSERT_EQ(vec2.size(), count2);
1280}
1281
1282/// @test `resize` is `noexcept` if and only if the default constructor of the element type is `noexcept`
1284 InlineVectorTest,
1287) {
1288 STATIC_ASSERT_EQ(
1289 noexcept(TestFixture::construct().resize(0)),
1290 std::is_nothrow_default_constructible<typename TypeParam::value_type>{}
1291 );
1292}
1293
1294/// @test `resize` with a value to copy is `noexcept` if and only if the copy constructor of the element type is
1295/// `noexcept`
1297 InlineVectorTest,
1299 std::is_copy_constructible<typename TypeParam::value_type>::value
1300) {
1301 STATIC_ASSERT_EQ(
1302 noexcept(std::declval<TypeParam&>().resize(0, std::declval<typename TypeParam::value_type>())),
1303 std::is_nothrow_copy_constructible<typename TypeParam::value_type>{}
1304 );
1305}
1306
1307/// @test Invoking the `resize` member function with a size and a value on a vector with more elements than the
1308/// specified size sets the size of the vector to the specified count and does not construct new elements
1310 InlineVectorTest,
1312 std::is_copy_constructible<typename TypeParam::value_type>::value
1313) {
1314 constexpr std::size_t initial_count = TypeParam::capacity;
1315 auto const initial_value = TestFixture::test_value(0);
1316 TypeParam vec(initial_count, initial_value);
1317 constexpr std::size_t count = TypeParam::capacity - 1UL;
1318 auto const value = TestFixture::test_value(1);
1319 vec.resize(count, value);
1320 ASSERT_EQ(vec.size(), count);
1321
1322 for (std::size_t idx = 0; idx < count; ++idx) {
1323 EXPECT_EQ(vec[idx], initial_value);
1324 }
1325}
1326
1327/// @test Invoking the `resize` member function with a size and a value on a vector with fewer elements than the
1328/// specified size sets the size of the vector to the specified count, and constructs a number of new elements
1329/// equal to the difference between the specified size and the previous size by copy-construction from the specified
1330/// value
1332 InlineVectorTest,
1334 std::is_copy_constructible<typename TypeParam::value_type>::value
1335) {
1336 constexpr std::size_t initial_count = TypeParam::capacity - 1UL;
1337 auto const initial_value = TestFixture::test_value(0);
1338 TypeParam vec(initial_count, initial_value);
1339 constexpr std::size_t count = TypeParam::capacity;
1340 auto const value = TestFixture::test_value(1);
1341 vec.resize(count, value);
1342 ASSERT_EQ(vec.size(), count);
1343
1344 for (std::size_t idx = 0; idx < initial_count; ++idx) {
1345 EXPECT_EQ(vec[idx], initial_value);
1346 }
1347 for (std::size_t idx = initial_count; idx < count; ++idx) {
1348 EXPECT_EQ(vec[idx], value);
1349 }
1350}
1351
1352/// @test In a `constexpr` context, invoking the `inline_vector` constructor with a count and a value constructs a
1353/// vector holding the specified number of elements copied from the source value
1355 InlineVectorTest,
1357 InlineVectorTest<TypeParam>::constexpr_compatible&&
1359) {
1360 constexpr auto source = TestFixture::test_value(0);
1361 constexpr auto vec = TestFixture::construct(TypeParam::capacity, source);
1362
1363 STATIC_ASSERT_EQ(vec.size(), TypeParam::capacity);
1364 STATIC_ASSERT_TRUE(all_elements_are(vec, source));
1365}
1366
1367template <typename Vec, typename T>
1368constexpr auto constexpr_insert(Vec&& vec, std::ptrdiff_t offset, T&& value) -> Vec {
1369 static_assert(std::is_rvalue_reference<Vec&&>::value, "Only expected to be called with an r-value reference.");
1370 std::forward<Vec>(vec).insert(std::forward<Vec>(vec).begin() + offset, std::forward<T>(value));
1371 return std::forward<Vec>(vec);
1372}
1373
1374/// @test In a `constexpr` context, invoking `insert` with an iterator referring to an existing element, moves the
1375/// referred to element and subsequent elements to make room for the new element, inserts the new element, and increases
1376/// the size by one.
1378 InlineVectorTest,
1379 CanInsert,
1380 InlineVectorTest<TypeParam>::constexpr_compatible&& TypeParam::capacity >= 3
1381) {
1382 constexpr auto vec = constexpr_insert<TypeParam>(TestFixture::test_vector(2), 1, TestFixture::test_value(2));
1383
1384 STATIC_ASSERT_EQ(vec.size(), 3);
1385 STATIC_ASSERT_EQ(vec[0], TestFixture::test_value(0));
1386 STATIC_ASSERT_EQ(vec[1], TestFixture::test_value(2));
1387 STATIC_ASSERT_EQ(vec[2], TestFixture::test_value(1));
1388}
1389
1390/// @test An `inline_vector` can be constructed from an iterator range, creating a vector by moving the elements
1391/// from the source range, with a size equal to the number of elements in the source range
1393 auto const expected = TestFixture::full_test_vector();
1394 auto source = TestFixture::full_test_vector();
1395
1396 TypeParam vec(std::make_move_iterator(source.begin()), std::make_move_iterator(source.end()));
1397
1398 EXPECT_EQ(vec.size(), expected.size());
1399 EXPECT_TRUE(elements_are_array(vec, expected));
1400}
1401
1402/// @test Construction of an `inline_vector` from an iterator range is `noexcept` if operations on the iterator are
1403/// `noexcept` and the element type of the vector is nothrow-constructible from the reference type of the iterator
1405 using source_it =
1406 std::move_iterator<typename arene::base::array<typename TypeParam::value_type, TypeParam::capacity>::iterator>;
1407 using source_val = typename source_it::reference;
1408
1409 constexpr bool it_operations_noexcept = noexcept(++std::declval<source_it>())&& noexcept(*std::declval<source_it>());
1410 constexpr bool element_construction_noexcept =
1411 std::is_nothrow_constructible<typename TypeParam::value_type, source_val>{};
1412
1413 STATIC_ASSERT_TRUE((std::is_constructible<TypeParam, source_it, source_it>{}));
1414 STATIC_ASSERT_EQ(
1415 (std::is_nothrow_constructible<TypeParam, source_it, source_it>{}),
1416 it_operations_noexcept && element_construction_noexcept
1417 );
1418
1419 using throws_when_converted = typename TestFixture::throws_when_converted_to_t;
1420 using convertible_array = ::arene::base::array<throws_when_converted, TypeParam::capacity>;
1421 using throwing_bidirectional_iterator = typename TestFixture::throwing_bidirectional_move_iterator_of_t;
1422
1423 STATIC_ASSERT_TRUE(std::is_constructible<
1424 TypeParam,
1425 typename convertible_array::const_iterator,
1426 typename convertible_array::const_iterator>::value);
1427 STATIC_ASSERT_FALSE(std::is_nothrow_constructible<
1428 TypeParam,
1429 typename convertible_array::const_iterator,
1430 typename convertible_array::const_iterator>::value);
1431 STATIC_ASSERT_TRUE(
1432 std::is_constructible<TypeParam, throwing_bidirectional_iterator, throwing_bidirectional_iterator>::value
1433 );
1434 STATIC_ASSERT_FALSE(
1435 std::is_nothrow_constructible<TypeParam, throwing_bidirectional_iterator, throwing_bidirectional_iterator>::value
1436 );
1437}
1438
1439/// @test Construction of an `inline_vector` from an input iterator range is `noexcept` if operations on the iterator
1440/// are `noexcept` and the element type of the vector is nothrow-constructible from the reference type of the iterator
1442 using input_it = ::testing::demoted_iterator<typename TypeParam::value_type*, std::input_iterator_tag>;
1443 using throws_when_converted = typename TestFixture::throws_when_converted_to_t;
1444 using throwing_it_throwing_type = typename TestFixture::template throwing_input_iterator<throws_when_converted>;
1445 using throwing_it_raw_type = typename TestFixture::template throwing_input_iterator<typename TypeParam::value_type>;
1446 using nothrow_it_throwing_type = typename TestFixture::template non_throwing_input_iterator<throws_when_converted>;
1447 using nothrow_it_raw_type =
1448 typename TestFixture::template non_throwing_input_iterator<typename TypeParam::value_type>;
1449
1450 constexpr bool it_operations_noexcept = noexcept(++std::declval<input_it>())&& noexcept(*std::declval<input_it>());
1451 constexpr bool element_construction_noexcept =
1452 std::is_nothrow_constructible<typename TypeParam::value_type, typename input_it::reference>{};
1453
1454 STATIC_ASSERT_TRUE((std::is_constructible<TypeParam, input_it, input_it>{}));
1455 STATIC_ASSERT_EQ(
1456 (std::is_nothrow_constructible<TypeParam, input_it, input_it>{}),
1457 it_operations_noexcept && element_construction_noexcept
1458 );
1459
1460 STATIC_ASSERT_TRUE(std::is_constructible<TypeParam, throwing_it_throwing_type, throwing_it_throwing_type>::value);
1461 STATIC_ASSERT_FALSE(
1462 std::is_nothrow_constructible<TypeParam, throwing_it_throwing_type, throwing_it_throwing_type>::value
1463 );
1464 STATIC_ASSERT_TRUE(std::is_constructible<TypeParam, throwing_it_raw_type, throwing_it_raw_type>::value);
1465 STATIC_ASSERT_FALSE(std::is_nothrow_constructible<TypeParam, throwing_it_raw_type, throwing_it_raw_type>::value);
1466 STATIC_ASSERT_TRUE(std::is_constructible<TypeParam, nothrow_it_raw_type, nothrow_it_raw_type>::value);
1467 STATIC_ASSERT_EQ(
1468 (std::is_nothrow_constructible<TypeParam, nothrow_it_raw_type, nothrow_it_raw_type>::value),
1469 std::is_nothrow_copy_constructible<typename TypeParam::value_type>::value
1470 );
1471 STATIC_ASSERT_TRUE(std::is_constructible<TypeParam, nothrow_it_throwing_type, nothrow_it_throwing_type>::value);
1472 STATIC_ASSERT_FALSE(
1473 std::is_nothrow_constructible<TypeParam, nothrow_it_throwing_type, nothrow_it_throwing_type>::value
1474 );
1475}
1476
1477/// @test In a `constexpr` context, an `inline_vector` can be constructed from an iterator range, creating a vector
1478/// holding copies of the elements from the source range, with a size equal to the number of elements in the source
1479/// range
1480// Note: std::move_iterator is not constexpr in C++14, so this is limited to copy constructible types.
1482 InlineVectorTest,
1484 InlineVectorTest<TypeParam>::constexpr_compatible&&
1486) {
1487 constexpr auto source = TestFixture::full_test_initializer_list();
1488 constexpr TypeParam vec(source.begin(), source.end());
1489
1490 STATIC_ASSERT_EQ(vec.size(), source.size());
1491 STATIC_ASSERT_TRUE(equal(vec.begin(), vec.end(), source.begin(), source.end()));
1492}
1493
1494/// @test Given an `inline_vector` holding existing elements, assigning to that vector with an initializer list holding
1495/// more elements copy assigns over the existing elements, and then copy-constructs new elements to increase the size of
1496/// the vector to that of the initializer list
1498 constexpr std::size_t smaller_count = TypeParam::capacity - 1UL;
1499
1500 auto const value = TestFixture::full_test_initializer_list();
1501
1502 auto copy = TestFixture::test_vector(smaller_count);
1503 copy = value;
1504
1505 EXPECT_THAT(copy, ::testing::ElementsAreArray(value));
1506}
1507
1508/// @test Given an `inline_vector` holding existing elements, assigning to that vector with an initializer list holding
1509/// fewer elements copy assigns over the existing elements up to the size of the initializer list, and then destroys a
1510/// number of elements equal to the difference between the old size of the vector and the size of the initializer list
1512 constexpr std::size_t larger_count = TypeParam::capacity;
1513
1514 auto const value = TestFixture::template test_initializer_list<TypeParam::capacity - 1UL>();
1515
1516 auto copy = TestFixture::test_vector(larger_count);
1517 copy = value;
1518
1519 EXPECT_THAT(copy, ::testing::ElementsAreArray(value));
1520}
1521
1522/// @test Invoking the `assign` member function with an iterator range sets the vector to have a size equal to the
1523/// number of elements in the range, and each element to be a copy of the corresponding element in the range
1525 auto source = TestFixture::full_test_vector();
1526
1527 auto vec = TestFixture::test_vector(0);
1528 vec.assign(std::make_move_iterator(source.begin()), std::make_move_iterator(source.end()));
1529
1530 EXPECT_TRUE(elements_are_array(vec, TestFixture::full_test_initializer_list()));
1531}
1532
1533/// @test Assignment of an `inline_vector` from an iterator range is `noexcept` if operations on the iterator are
1534/// `noexcept` and the element type of the vector is nothrow-constructible and nothrow-assignable from the reference
1535/// type of the iterator
1537 using array_it = std::move_iterator<typename array<typename TypeParam::value_type, TypeParam::capacity>::iterator>;
1538 using throws_when_converted = typename TestFixture::throws_when_converted_to_t;
1539 using convertible_array_it = std::move_iterator<typename array<throws_when_converted, TypeParam::capacity>::iterator>;
1540 using throwing_bidirectional_iterator = typename TestFixture::throwing_bidirectional_move_iterator_of_t;
1541
1542 constexpr bool it_operations_noexcept = noexcept(++std::declval<array_it>())&& noexcept(*std::declval<array_it>());
1543 constexpr bool element_construction_noexcept =
1544 std::is_nothrow_constructible<typename TypeParam::value_type, typename array_it::reference>{} &&
1545 std::is_nothrow_assignable<typename TypeParam::value_type&, typename array_it::reference>{};
1546
1547 STATIC_ASSERT_EQ(
1548 noexcept(TypeParam{}.assign(std::declval<array_it>(), std::declval<array_it>())),
1549 it_operations_noexcept && element_construction_noexcept
1550 );
1551 STATIC_ASSERT_FALSE(
1552 noexcept(TypeParam{}.assign(std::declval<convertible_array_it>(), std::declval<convertible_array_it>()))
1553 );
1554 STATIC_ASSERT_FALSE(noexcept(TypeParam{}.assign(
1555 std::declval<throwing_bidirectional_iterator>(),
1556 std::declval<throwing_bidirectional_iterator>()
1557 )));
1558}
1559
1560/// @test Invoking the `assign` member function with an initializer list sets the vector to have a size equal to the
1561/// number of elements in the initializer list, and each element to be a copy of the corresponding element in the
1562/// initializer list
1564 constexpr std::size_t smaller_count = TypeParam::capacity - 1UL;
1565
1566 auto const value = TestFixture::full_test_initializer_list();
1567
1568 auto copy = TestFixture::test_vector(smaller_count);
1569 copy.assign(value);
1570
1571 EXPECT_THAT(copy, ::testing::ElementsAreArray(value));
1572}
1573
1574/// @test Assignment of an `inline_vector` from an initializer list is `noexcept` if the element type of the vector is
1575/// nothrow-copy-constructible
1577 constexpr bool is_nothrow_copyable = std::is_nothrow_copy_constructible<typename TypeParam::value_type>{} &&
1578 std::is_nothrow_copy_assignable<typename TypeParam::value_type>{};
1579
1580 STATIC_ASSERT_TRUE(std::is_assignable<TypeParam, std::initializer_list<typename TypeParam::value_type>>::value);
1581 STATIC_ASSERT_EQ(
1582 (std::is_nothrow_assignable<TypeParam, std::initializer_list<typename TypeParam::value_type>>::value),
1583 is_nothrow_copyable
1584 );
1585
1586 auto const values = TestFixture::full_test_initializer_list();
1587 STATIC_ASSERT_EQ(noexcept(TypeParam{}.assign(values)), is_nothrow_copyable);
1588}
1589
1590/// @test Invoking the `assign` member function with an iterator range specified using input iterators sets the vector
1591/// to have a size equal to the number of elements in the range, and each element to be a copy of the corresponding
1592/// element in the range
1594 auto source = TestFixture::full_test_vector();
1595
1596 auto vec = TestFixture::test_vector(0);
1597 using move_it = std::move_iterator<typename decltype(source)::iterator>;
1598 using input_it = ::testing::demoted_iterator<move_it, std::input_iterator_tag>;
1599
1600 auto begin = input_it{std::make_move_iterator(source.begin())};
1601 auto end = input_it{std::make_move_iterator(source.end())};
1602 vec.assign(begin, end);
1603
1604 EXPECT_TRUE(elements_are_array(vec, TestFixture::full_test_initializer_list()));
1605}
1606
1607/// @test Assignment of an `inline_vector` from an input iterator range is `noexcept` if operations on the iterator are
1608/// `noexcept` and the element type of the vector is nothrow-constructible from the value type of the iterator
1610 using throws_when_converted = typename TestFixture::throws_when_converted_to_t;
1611 using throwing_it_throwing_type = typename TestFixture::template throwing_input_iterator<throws_when_converted>;
1612 using throwing_it_raw_type = typename TestFixture::template throwing_input_iterator<typename TypeParam::value_type>;
1613 using nothrow_it_throwing_type = typename TestFixture::template non_throwing_input_iterator<throws_when_converted>;
1614 using nothrow_it_raw_type =
1615 typename TestFixture::template non_throwing_input_iterator<typename TypeParam::value_type>;
1616
1617 STATIC_ASSERT_FALSE(noexcept(TypeParam{}.assign(
1618 std::declval<::testing::demoted_iterator<throwing_it_throwing_type, std::input_iterator_tag>>(),
1619 std::declval<::testing::demoted_iterator<throwing_it_throwing_type, std::input_iterator_tag>>()
1620 )));
1621 STATIC_ASSERT_FALSE(
1622 noexcept(TypeParam{}.assign(std::declval<throwing_it_throwing_type>(), std::declval<throwing_it_throwing_type>()))
1623 );
1624 STATIC_ASSERT_FALSE(
1625 noexcept(TypeParam{}.assign(std::declval<throwing_it_raw_type>(), std::declval<throwing_it_raw_type>()))
1626 );
1627 STATIC_ASSERT_EQ(
1628 noexcept(TypeParam{}.assign(std::declval<nothrow_it_raw_type>(), std::declval<nothrow_it_raw_type>())),
1629 std::is_nothrow_copy_assignable<typename TypeParam::value_type>::value &&
1630 std::is_nothrow_copy_constructible<typename TypeParam::value_type>::value
1631 );
1632 STATIC_ASSERT_FALSE(
1633 noexcept(TypeParam{}.assign(std::declval<nothrow_it_throwing_type>(), std::declval<nothrow_it_throwing_type>()))
1634 );
1635}
1636
1637/// @test Invoking the `assign` member function with a count and a value sets the size of the vector to the specified
1638/// count, where each element is a copy of the supplied value
1640 constexpr std::size_t count = TypeParam::capacity;
1641 constexpr std::size_t smaller_count = TypeParam::capacity - 1UL;
1642
1643 auto copy = TestFixture::test_vector(smaller_count);
1644 auto const value = TestFixture::test_value(0);
1645 copy.assign(count, value);
1646
1647 EXPECT_EQ(copy.size(), count);
1648 for (std::size_t i = 0; i < count; ++i) {
1649 EXPECT_EQ(copy[i], value);
1650 }
1651}
1652
1653/// @test The `assign` member function taking a size and a value is not `noexcept` if the value type is
1654/// not nothrow-copy-constructible
1656 constexpr bool is_nothrow_copyable = std::is_nothrow_copy_constructible<typename TypeParam::value_type>{} &&
1657 std::is_nothrow_copy_assignable<typename TypeParam::value_type>{};
1658 STATIC_ASSERT_EQ(noexcept(TypeParam{}.assign(0, TestFixture::test_value(0))), is_nothrow_copyable);
1659}
1660
1661/// @test Invoking the `assign` member function with a count and a value where the count is larger than the capacity of
1662/// the vector terminates the program with a precondition violation
1664 constexpr std::size_t smaller_count = TypeParam::capacity - 1UL;
1665
1666 auto const initial_value = TestFixture::test_value(0);
1667 TypeParam copy(smaller_count, initial_value);
1668 auto const value = TestFixture::test_value(1);
1669 ASSERT_DEATH(copy.assign(TypeParam::capacity + 1, value), "Precondition violation");
1670
1671 EXPECT_EQ(copy.size(), smaller_count);
1672 for (std::size_t i = 0; i < smaller_count; ++i) {
1673 EXPECT_EQ(copy[i], initial_value);
1674 }
1675}
1676
1677/// @test The index operator returns a reference to the element type of the vector
1679 ::testing::StaticAssertTypeEq<decltype(std::declval<TypeParam&>()[0]), typename TypeParam::value_type&>();
1680}
1681
1682/// @test The index operator for a `const` vector returns a `const` reference to the element type of the vector
1684 ::testing::StaticAssertTypeEq<decltype(std::declval<TypeParam const&>()[0]), typename TypeParam::value_type const&>();
1685}
1686
1687/// @test Given an `inline_vector` with multiple elements, the index operator can be used with appropriate index values
1688/// to access each element, returning a reference to the element at that index
1690 auto vec = TestFixture::test_vector(2);
1691 auto const& const_vec = vec;
1692
1693 EXPECT_EQ(vec[0], TestFixture::test_value(0));
1694 EXPECT_EQ(vec[1], TestFixture::test_value(1));
1695 // NOLINTNEXTLINE(readability-container-data-pointer)
1696 EXPECT_EQ(&const_vec[0], std::addressof(vec[0]));
1697 EXPECT_EQ(&const_vec[1], std::addressof(vec[1]));
1698}
1699
1700/// @test The index operator is `noexcept`
1701TYPED_TEST_P(InlineVectorTest, IndexOperatorIsNoexcept) { STATIC_ASSERT_TRUE(noexcept(std::declval<TypeParam&>()[0])); }
1702
1703/// @test Passing an index that is equal to or larger than the size of the vector terminates the program with a
1704/// precondition violation
1705TYPED_TEST_P(InlineVectorDeathTest, IndexOperatorOutOfRange) {
1706 ASSERT_DEATH(TestFixture::construct()[0], "index < this->size()");
1707}
1708
1709/// @test The index operator is `noexcept` for a `const` vector
1711 STATIC_ASSERT_TRUE(noexcept(std::declval<TypeParam const&>()[0]));
1712}
1713
1714/// @test The index operator can be used to access the elements of an `inline_vector` in a `constexpr` context.
1716 InlineVectorTest,
1718 InlineVectorTest<TypeParam>::constexpr_compatible&& TypeParam::capacity >= 2
1719) {
1720 constexpr auto vec = TestFixture::test_vector(2);
1721 STATIC_ASSERT_EQ(vec[0], TestFixture::test_value(0));
1722 STATIC_ASSERT_EQ(vec[1], TestFixture::test_value(1));
1723}
1724
1725/// @test The `data` member function is noexcept and returns a pointer to the first element of a non-empty vector
1726TYPED_TEST_P(InlineVectorTest, Data) {
1727 auto vec = TestFixture::full_test_vector();
1728 auto const& const_vec = vec;
1729
1730 // NOLINTNEXTLINE(readability-container-data-pointer)
1731 EXPECT_EQ(vec.data(), std::addressof(vec[0]));
1732 // NOLINTNEXTLINE(readability-container-data-pointer)
1733 EXPECT_EQ(const_vec.data(), std::addressof(vec[0]));
1734
1735 STATIC_ASSERT_TRUE(noexcept(vec.data()));
1736 STATIC_ASSERT_TRUE(noexcept(const_vec.data()));
1737
1738 // This is just to check that data() works in constexpr.
1739 COND_STATIC_ASSERT_NE(TestFixture::full_test_vector().data(), nullptr);
1740}
1741
1742/// @test Given an `inline_vector` which is not empty, invoking the `clear` method makes the vector empty
1744 auto vec = TestFixture::full_test_vector();
1745
1746 EXPECT_EQ(vec.size(), TypeParam::capacity);
1747 EXPECT_FALSE(vec.empty());
1748 vec.clear();
1749 EXPECT_EQ(vec.size(), 0);
1750 EXPECT_TRUE(vec.empty());
1751
1752 STATIC_ASSERT_TRUE(noexcept(vec.clear()));
1753}
1754
1755template <typename Vec>
1756constexpr auto constexpr_clear(Vec vec) -> Vec {
1757 vec.clear();
1758 return vec;
1759}
1760
1761/// @test In a `constexpr` context, given an `inline_vector` which is not empty, invoking the `clear` method makes the
1762/// vector empty
1764 constexpr auto vec = TestFixture::full_test_vector();
1765
1766 constexpr auto value2 = constexpr_clear(vec);
1767 STATIC_ASSERT_TRUE(value2.empty());
1768}
1769
1770/// @test Two instances of `inline_vector` can be compared for equality using `operator==` and `operator!=`. Two vectors
1771/// are the same if and only if they have the same size, and each element from one vector compares equal to the element
1772/// with the same index in the other vector.
1774 InlineVectorTest,
1776 InlineVectorTest<TypeParam>::constexpr_compatible&& TypeParam::capacity >= 4
1777) {
1778 constexpr TypeParam vec{
1779 TestFixture::template unique_test_value<0>(),
1780 TestFixture::template unique_test_value<1>(),
1781 TestFixture::template unique_test_value<2>()
1782 };
1783 constexpr TypeParam different_contents{
1784 TestFixture::template unique_test_value<3>(),
1785 TestFixture::template unique_test_value<4>(),
1786 TestFixture::template unique_test_value<5>()
1787 };
1788 constexpr auto longer = TestFixture::test_vector(4);
1789 constexpr TypeParam copy{vec};
1790
1791 STATIC_ASSERT_TRUE(vec != different_contents);
1792 STATIC_ASSERT_TRUE(vec != longer);
1793 STATIC_ASSERT_FALSE(vec != copy);
1794 STATIC_ASSERT_FALSE(vec == different_contents);
1795 STATIC_ASSERT_FALSE(vec == longer);
1796 STATIC_ASSERT_TRUE(vec == copy);
1797}
1798
1799template <class Vec>
1800constexpr auto erase_front(Vec&& vec, std::size_t count) {
1801 static_assert(std::is_rvalue_reference<Vec&&>::value, "Only expected to be called with an r-value reference.");
1802 using difference_type = typename std::iterator_traits<typename Vec::iterator>::difference_type;
1803 std::forward<Vec>(vec).erase(
1804 std::forward<Vec>(vec).begin(),
1805 std::forward<Vec>(vec).begin() + static_cast<difference_type>(count)
1806 );
1807 return std::forward<Vec>(vec);
1808}
1809
1810/// A type trait to tell if the given type parameter is fully comparable or not for the purposes of these tests
1811/// @tparam T The type to check
1812template <typename T>
1815
1816/// @test Two instances of `inline_vector` can be compared for ordering using `operator<` and `operator>`. One vector
1817/// compares less than another if the first has a smaller size than the second, and all elements are equal to the
1818/// corresponding element in the second vector with the same index or they have the same size, and there is an element
1819/// such that all elements with a lower index compare equal to the corresponding element in the second vector, and that
1820/// element compares less than the corresponding element of the second vector.
1822 InlineVectorTest,
1824 InlineVectorTest<TypeParam>::constexpr_compatible&& is_fully_comparable_v<typename TypeParam::value_type>&&
1825 TypeParam::capacity >= 4
1826) {
1827 constexpr auto sorted_test_values = sort_helper(TypeParam{
1828 TestFixture::template unique_test_value<0>(),
1829 TestFixture::template unique_test_value<1>(),
1830 TestFixture::template unique_test_value<2>(),
1831 TestFixture::template unique_test_value<3>()
1832 });
1833
1834 constexpr auto low_value = TypeParam(sorted_test_values.begin(), sorted_test_values.begin() + 2UL);
1835 constexpr auto high_value = TypeParam(sorted_test_values.begin() + 2UL, sorted_test_values.begin() + 4UL);
1836 constexpr auto long_value = TypeParam(sorted_test_values.begin(), sorted_test_values.begin() + 3UL);
1837 constexpr auto low_value_copy = low_value;
1838
1839 STATIC_ASSERT_TRUE(low_value < high_value);
1840 STATIC_ASSERT_TRUE(low_value < long_value);
1841 STATIC_ASSERT_FALSE(low_value < low_value_copy);
1842 STATIC_ASSERT_FALSE(high_value < low_value);
1843 STATIC_ASSERT_TRUE(high_value > low_value);
1844 STATIC_ASSERT_TRUE(long_value > low_value);
1845 STATIC_ASSERT_FALSE(low_value_copy > low_value);
1846 STATIC_ASSERT_FALSE(low_value > high_value);
1847
1848 STATIC_ASSERT_TRUE(low_value <= high_value);
1849 STATIC_ASSERT_TRUE(low_value <= long_value);
1850 STATIC_ASSERT_TRUE(low_value <= low_value_copy);
1851 STATIC_ASSERT_FALSE(high_value <= low_value);
1852 STATIC_ASSERT_TRUE(high_value >= low_value);
1853 STATIC_ASSERT_TRUE(long_value >= low_value);
1854 STATIC_ASSERT_TRUE(low_value_copy >= low_value);
1855 STATIC_ASSERT_FALSE(low_value >= high_value);
1856}
1857
1858template <typename ValueType>
1860 using value_type = ValueType;
1861 value_type value_;
1862
1863 public:
1864 explicit move_only_wrapper(value_type value)
1865 : value_(std::move(value)) {}
1870 ~move_only_wrapper() = default;
1871
1872 auto get() -> value_type& { return value_; }
1873};
1874
1875/// @test The `emplace_back` member function can be used to add an element to an `inline_vector`. The new element is
1876/// constructed with the arguments supplied to `emplace_back`
1877TYPED_TEST_P(InlineVectorTest, CanEmplaceBack) {
1878 using value_type = typename TypeParam::value_type;
1879
1880 struct with_constructor_args {
1881 std::reference_wrapper<value_type const> value;
1882 // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
1883 value_type& reference;
1884 move_only_wrapper<value_type> wrapper;
1885
1886 with_constructor_args(value_type const& val, value_type& ref, move_only_wrapper<value_type> wrap_arg)
1887 : value(val),
1888 reference(ref),
1889 wrapper(std::move(wrap_arg)) {}
1890 };
1891
1892 typename TestFixture::template standard_capacity_vector<with_constructor_args> vec;
1893
1894 value_type const value1 = TestFixture::test_value(0);
1895 value_type value2 = TestFixture::test_value(1);
1896 auto& result = vec.emplace_back(value1, value2, move_only_wrapper<value_type>(TestFixture::test_value(2)));
1897
1898 ::testing::StaticAssertTypeEq<decltype(result), with_constructor_args&>();
1899 EXPECT_EQ(vec.size(), 1);
1900 ASSERT_FALSE(vec.empty());
1901 EXPECT_EQ(std::addressof(result), std::addressof(vec[0]));
1902
1903 EXPECT_EQ(result.value.get(), value1);
1904 EXPECT_EQ(std::addressof(result.reference), std::addressof(value2));
1905 EXPECT_EQ(result.wrapper.get(), TestFixture::test_value(2));
1906}
1907
1908template <typename Container, typename... Args>
1909constexpr auto constexpr_emplace_back(Args&&... args) -> Container {
1910 Container res;
1911 res.emplace_back(std::forward<Args>(args)...);
1912 return res;
1913}
1914
1915/// @test In a `constexpr` context, the `emplace_back` member function can be used to add an element to an
1916/// `inline_vector`. The new element is constructed with the arguments supplied to `emplace_back`
1918 using value_type = typename TypeParam::value_type;
1919 struct with_constructor_args {
1920 value_type first;
1921 value_type second;
1922 value_type third;
1923
1924 with_constructor_args() = default;
1925
1926 // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
1927 constexpr with_constructor_args(value_type&& fst, value_type&& snd, value_type&& trd)
1928 : first(std::move(fst)),
1929 second(std::move(snd)),
1930 third(std::move(trd)) {}
1931 };
1932
1933 constexpr auto vec =
1934 constexpr_emplace_back<typename TestFixture::template standard_capacity_vector<with_constructor_args>>(
1935 TestFixture::test_value(0),
1936 TestFixture::test_value(1),
1937 TestFixture::test_value(2)
1938 );
1939
1940 STATIC_ASSERT_EQ(vec.size(), 1);
1941 STATIC_ASSERT_EQ(vec[0].first, TestFixture::test_value(0));
1942 STATIC_ASSERT_EQ(vec[0].second, TestFixture::test_value(1));
1943 STATIC_ASSERT_EQ(vec[0].third, TestFixture::test_value(2));
1944}
1945
1946template <typename T>
1948 explicit throws_without_nullptr(T const&) {}
1949 throws_without_nullptr(T const&, std::nullptr_t) noexcept {}
1950};
1951
1952/// @test `emplace_back` is `noexcept` if and only if the element type of the vector is nothrow-constructible from the
1953/// supplied arguments
1955 STATIC_ASSERT_EQ(
1956 noexcept(TestFixture::construct().emplace_back(std::declval<typename TypeParam::value_type&&>())),
1957 std::is_nothrow_move_constructible<typename TypeParam::value_type>{}
1958 );
1959}
1960
1961/// @test `emplace_back` is `noexcept` if and only if the element type of the vector is nothrow-constructible from the
1962/// supplied arguments
1964 InlineVectorTest,
1966 std::is_copy_constructible<typename TypeParam::value_type>::value
1967) {
1968 using value_type = typename TypeParam::value_type;
1969 STATIC_ASSERT_EQ(
1970 noexcept(TestFixture::construct().emplace_back(std::declval<value_type const&>())),
1971 std::is_nothrow_copy_constructible<value_type>{}
1972 );
1973
1974 STATIC_ASSERT_FALSE(
1975 noexcept(typename TestFixture::template standard_capacity_vector<throws_without_nullptr<value_type>>{}
1976 .emplace_back(std::declval<value_type const&>()))
1977 );
1978 STATIC_ASSERT_TRUE(
1979 noexcept(typename TestFixture::template standard_capacity_vector<throws_without_nullptr<value_type>>{}
1980 .emplace_back(std::declval<value_type const&>(), nullptr))
1981 );
1982}
1983
1984/// @test `emplace` with a position is `noexcept` if and only if the element type of the vector is
1985/// nothrow-move-constructible, nothrow-move-assignable, and nothrow-constructible from the supplied arguments
1987 using value_type = typename TypeParam::value_type;
1988 using const_it = typename TypeParam::const_iterator;
1989
1990 constexpr bool is_nothrow_movable =
1991 std::is_nothrow_move_constructible<value_type>{} && std::is_nothrow_move_assignable<value_type>{};
1992
1993 STATIC_ASSERT_EQ(
1994 noexcept(TestFixture::construct().emplace(std::declval<const_it>(), std::declval<value_type&&>())),
1995 is_nothrow_movable
1996 );
1997
1998 using overload_test_vector =
1999 typename TestFixture::template standard_capacity_vector<throws_without_nullptr<value_type>>;
2000 using overload_it = typename overload_test_vector::const_iterator;
2001 STATIC_ASSERT_FALSE(noexcept(overload_test_vector{}.emplace(std::declval<overload_it>(), std::declval<value_type>()))
2002 );
2003 STATIC_ASSERT_TRUE(
2004 noexcept(overload_test_vector{}.emplace(std::declval<overload_it>(), std::declval<value_type>(), nullptr))
2005 );
2006}
2007
2008/// @test Invoking `emplace` inserts a new value at the position indicated, constructing the new value with the supplied
2009/// arguments, and returning an iterator referencing the new value
2010TYPED_TEST_P(InlineVectorTest, EmplaceInsert) {
2011 using value_type = typename TypeParam::value_type;
2012 struct with_constructor_args {
2013 std::reference_wrapper<value_type const> value;
2014 value_type* raw_pointer;
2015 move_only_wrapper<value_type> wrapper;
2016
2017 with_constructor_args(value_type const& val, value_type* rptr, move_only_wrapper<value_type> wrap_arg)
2018 : value(val),
2019 raw_pointer(rptr),
2020 wrapper(std::move(wrap_arg)) {}
2021 };
2022
2023 typename TestFixture::template standard_capacity_vector<with_constructor_args> vec;
2024 auto const& const_vec1 = vec;
2025 value_type const value1 = TestFixture::test_value(0);
2026 value_type value2 = TestFixture::test_value(1);
2027 auto pos = vec.emplace(
2028 const_vec1.begin(),
2029 value1,
2030 std::addressof(value2),
2031 move_only_wrapper<value_type>(TestFixture::test_value(2))
2032 );
2033 EXPECT_EQ(pos, vec.begin());
2034 EXPECT_EQ(vec.size(), 1);
2035 EXPECT_EQ(&*pos, std::addressof(vec[0]));
2036
2037 EXPECT_EQ(pos->value.get(), value1);
2038 ASSERT_NE(pos->raw_pointer, nullptr);
2039 EXPECT_EQ(pos->raw_pointer, std::addressof(value2));
2040 EXPECT_EQ(pos->wrapper.get(), TestFixture::test_value(2));
2041}
2042
2043template <typename Vec, typename Arg>
2044constexpr auto constexpr_emplace(Vec&& vec, std::ptrdiff_t pos, Arg&& arg) -> Vec {
2045 static_assert(std::is_rvalue_reference<Vec&&>::value, "Only expected to be called with an r-value reference.");
2046 std::forward<Vec>(vec).emplace(std::forward<Vec>(vec).begin() + pos, std::forward<Arg>(arg));
2047 return std::forward<Vec>(vec);
2048}
2049
2050/// @test `emplace` can be invoked in a `constexpr` context to construct an element at a specified index.
2052 InlineVectorTest,
2053 CanEmplace,
2054 InlineVectorTest<TypeParam>::constexpr_compatible&& TypeParam::capacity >= 3
2055) {
2056 constexpr auto vec1 = TestFixture::test_vector(2);
2057
2058 struct convertible_to_typeparam {
2059 // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
2060 constexpr operator typename TypeParam::value_type() noexcept { return TestFixture::test_value(2); }
2061 };
2062
2063 constexpr TypeParam vec2 = constexpr_emplace(TestFixture::test_vector(2), 1, convertible_to_typeparam{});
2064
2065 STATIC_ASSERT_EQ(vec2.size(), vec1.size() + 1);
2066 STATIC_ASSERT_EQ(vec2[0], vec1[0]);
2067 STATIC_ASSERT_EQ(vec2[1], static_cast<typename TypeParam::value_type>(convertible_to_typeparam{}));
2068 STATIC_ASSERT_EQ(vec2[2], vec1[1]);
2069}
2070
2071/// @test `emplace` with a position is `noexcept` if and only if the element type of the vector is
2072/// nothrow-move-constructible, nothrow-move-assignable, and nothrow-constructible from an lvalue argument
2074 InlineVectorTest,
2076 std::is_copy_constructible<typename TypeParam::value_type>::value
2077) {
2078 using value_type = typename TypeParam::value_type;
2079 using const_it = typename TypeParam::const_iterator;
2080
2081 constexpr bool is_nothrow_movable =
2082 std::is_nothrow_move_constructible<value_type>{} && std::is_nothrow_move_assignable<value_type>{};
2083
2084 STATIC_ASSERT_EQ(
2085 noexcept(TestFixture::construct().emplace(std::declval<const_it>(), std::declval<value_type const&>())),
2086 is_nothrow_movable && std::is_nothrow_copy_constructible<value_type>{}
2087 );
2088}
2089
2090/// @test Emplacing using the default constructor has the right exception specification. This test is separate from the
2091/// ones above due to a bug in GCC8 which tries to instantiate the `emplace_back` and `emplace` functions before
2092/// checking their exception specifications, which fails for types that are not default-constructible.
2094 InlineVectorTest,
2097) {
2098 using value_type = typename TypeParam::value_type;
2099 using const_it = typename TypeParam::const_iterator;
2100
2101 constexpr bool is_nothrow_movable =
2102 std::is_nothrow_move_constructible<value_type>{} && std::is_nothrow_move_assignable<value_type>{};
2103
2104 STATIC_ASSERT_EQ(
2105 noexcept(TestFixture::construct().emplace_back()),
2106 std::is_nothrow_default_constructible<value_type>{}
2107 );
2108 STATIC_ASSERT_EQ(
2109 noexcept(TestFixture::construct().emplace(std::declval<const_it>())),
2110 is_nothrow_movable && std::is_nothrow_default_constructible<value_type>{}
2111 );
2112}
2113
2114/// @test Invoking `emplace_back` on an `inline_vector<T>` which has a size equal to its capacity terminates the program
2115/// with a precondition violation
2117 auto vec = TestFixture::test_vector(TypeParam::capacity);
2118
2119 ASSERT_DEATH(vec.emplace_back(TestFixture::test_value(0)), "Precondition violation");
2120}
2121
2122/// @test Invoking `swap` without a namespace qualification on two `inline_vector` instances exchanges the contents, so
2123/// the elements from one have been moved to the other, and vice-versa.
2125 auto value1 = TestFixture::full_test_vector();
2126 auto value2 = TestFixture::test_vector(TypeParam::capacity, TypeParam::capacity + TypeParam::capacity / 2UL);
2127
2128 swap(value1, value2);
2129
2130 EXPECT_EQ(value1, TestFixture::test_vector(TypeParam::capacity, TypeParam::capacity + TypeParam::capacity / 2UL));
2131 EXPECT_EQ(value2, TestFixture::full_test_vector());
2132}
2133
2134template <typename Vec>
2135constexpr auto constexpr_swap(Vec lhs, Vec rhs) -> std::pair<Vec, Vec> {
2136 swap(lhs, rhs);
2137 return {lhs, rhs};
2138}
2139
2140/// @test In a `constexpr` context, two `inline_vector` instances can be swapped with an unqualified call to `swap`.
2142 constexpr auto value1 = TestFixture::full_test_vector();
2143 constexpr auto value2 =
2144 TestFixture::test_vector(TypeParam::capacity, TypeParam::capacity + TypeParam::capacity / 2UL);
2145
2146 constexpr auto vec_swapped = constexpr_swap(value1, value2);
2147 STATIC_ASSERT_EQ(vec_swapped.first, value2);
2148 STATIC_ASSERT_EQ(vec_swapped.second, value1);
2149}
2150
2151/// @test Swapping two `inline_vector`s is `noexcept` if and only if the element
2152/// type is nothrow swappable AND the element type is nothrow move constructible
2154 constexpr bool element_nothrow = ::arene::base::is_nothrow_swappable_v<typename TypeParam::value_type> &&
2155 std::is_nothrow_move_constructible<typename TypeParam::value_type>::value;
2156
2157 STATIC_ASSERT_EQ(::arene::base::is_nothrow_swappable_v<TypeParam>, element_nothrow);
2158 STATIC_ASSERT_EQ(noexcept(std::declval<TypeParam>().swap(std::declval<TypeParam&>())), element_nothrow);
2159}
2160
2161/// @test `insert` of an rvalue is `noexcept` if the element type of the vector is nothrow-constructible from the
2162/// supplied value, and is nothrow-move-constructible and nothrow-move-assignable
2164 using value_type = typename TypeParam::value_type;
2165 using iterator = typename TypeParam::const_iterator;
2166
2167 constexpr bool is_nothrow_movable =
2168 std::is_nothrow_move_constructible<value_type>{} && std::is_nothrow_move_assignable<value_type>{};
2169
2170 STATIC_ASSERT_EQ(
2171 noexcept(TypeParam{}.insert(std::declval<iterator>(), std::declval<value_type&&>())),
2172 is_nothrow_movable
2173 );
2174}
2175
2176/// @test `insert` of an lvalue is `noexcept` if the element type of the vector is nothrow-constructible from the
2177/// supplied value, and is nothrow-move-constructible and nothrow-move-assignable
2179 using value_type = typename TypeParam::value_type;
2180 using iterator = typename TypeParam::const_iterator;
2181
2182 constexpr bool is_nothrow_movable =
2183 std::is_nothrow_move_constructible<value_type>{} && std::is_nothrow_move_assignable<value_type>{};
2184
2185 STATIC_ASSERT_EQ(
2186 noexcept(TypeParam{}.insert(std::declval<iterator>(), std::declval<value_type const&>())),
2187 is_nothrow_movable && std::is_nothrow_copy_constructible<value_type>::value
2188 );
2189}
2190
2191/// @test `insert` is `noexcept` if the element type of the vector is nothrow-copy-constructible, and is
2192/// nothrow-move-constructible and nothrow-move-assignable
2194 using value_type = typename TypeParam::value_type;
2195 using iterator = typename TypeParam::const_iterator;
2196
2197 constexpr bool is_nothrow_movable =
2198 std::is_nothrow_move_constructible<value_type>{} && std::is_nothrow_move_assignable<value_type>{};
2199
2200 STATIC_ASSERT_EQ(
2201 noexcept(TypeParam{}.insert(std::declval<iterator>(), 0U, std::declval<value_type&&>())),
2202 is_nothrow_movable && std::is_nothrow_copy_constructible<value_type>{}
2203 );
2204 STATIC_ASSERT_EQ(
2205 noexcept(TypeParam{}.insert(std::declval<iterator>(), 0U, std::declval<value_type const&>())),
2206 is_nothrow_movable && std::is_nothrow_copy_constructible<value_type>{}
2207 );
2208}
2209
2210/// @test Invoking `insert` with a count and a value to insert more elements than there are remaining spaces in the
2211/// vector before it exceeds capacity terminates the program with a precondition violation.
2213 auto value = TestFixture::test_vector(TypeParam::capacity - 1UL);
2214 ASSERT_DEATH(value.insert(value.begin(), 2UL, TestFixture::test_value(5)), "Precondition violation");
2215}
2216
2217/// @test Invoking `insert` with the end iterator of the `inline_vector` and a count and value appends the specified
2218/// number of copies of the supplied value to the end of the vector.
2220 InlineVectorTest,
2223) {
2224 auto const value1 = TestFixture::test_value(0);
2225 auto const value2 = TestFixture::test_value(1);
2226 auto const value3 = TestFixture::test_value(2);
2227 TypeParam vec{value1, value2};
2228 constexpr std::size_t insert_count = 5;
2229
2230 vec.insert(vec.end(), insert_count, value3);
2231 EXPECT_EQ(vec.size(), insert_count + 2);
2232 EXPECT_EQ(vec[0], value1);
2233 EXPECT_EQ(vec[1], value2);
2234 for (std::size_t i = 0; i < insert_count; ++i) {
2235 EXPECT_EQ(vec[i + 2], value3);
2236 }
2237}
2238
2239/// @test Invoking `insert` with an iterator referring to an existing element of an `inline_vector` and a count and
2240/// value moves the referred to element and subsequent elements to make room, and inserts the specified number of copies
2241/// of the supplied value prior to the existing element.
2243 InlineVectorTest,
2246) {
2247 auto const value1 = TestFixture::test_value(0);
2248 auto const value2 = TestFixture::test_value(1);
2249 auto const value3 = TestFixture::test_value(2);
2250 auto const value4 = TestFixture::test_value(3);
2251 auto const value_inserted = TestFixture::test_value(4);
2252 TypeParam vec{value1, value2, value3, value4};
2253 constexpr std::size_t insert_count = 3;
2254
2255 vec.insert(vec.begin() + 1, insert_count, value_inserted);
2256 EXPECT_EQ(vec.size(), insert_count + 4);
2257 EXPECT_EQ(vec[0], value1);
2258 for (std::size_t i = 0; i < insert_count; ++i) {
2259 EXPECT_EQ(vec[i + 1], value_inserted);
2260 }
2261 EXPECT_EQ(vec[insert_count + 1], value2);
2262 EXPECT_EQ(vec[insert_count + 2], value3);
2263 EXPECT_EQ(vec[insert_count + 3], value4);
2264}
2265
2266/// @test Invoking `insert` with an iterator referring to an existing element of an `inline_vector` and a source
2267/// iterator range denoted by a pair of iterators moves the referred to element and subsequent elements to make room,
2268/// and inserts the elements from the source iterator range prior to the existing element.
2270 auto vec1 = TestFixture::test_vector(4);
2271 auto vec2 = TestFixture::test_vector(4, 11);
2272 auto const vec2_expected = TestFixture::test_vector(4, 11);
2273
2274 vec1.insert(vec1.begin() + 1, std::make_move_iterator(vec2.begin()), std::make_move_iterator(vec2.end()));
2275 EXPECT_EQ(vec1.size(), vec2.size() + 4);
2276 EXPECT_EQ(vec1[0], TestFixture::test_value(0));
2277 for (std::size_t idx = 0; idx < vec2.size(); ++idx) {
2278 EXPECT_EQ(vec1[idx + 1], vec2_expected[idx]);
2279 }
2280 EXPECT_EQ(vec1[vec2_expected.size() + 1], TestFixture::test_value(1));
2281 EXPECT_EQ(vec1[vec2_expected.size() + 2], TestFixture::test_value(2));
2282 EXPECT_EQ(vec1[vec2_expected.size() + 3], TestFixture::test_value(3));
2283}
2284
2285/// @test `insert` is `noexcept` if the element type of the vector is nothrow-constructible from the supplied iterator's
2286/// reference type, and is nothrow-move-constructible and nothrow-move-assignable
2288 using value_type = typename TypeParam::value_type;
2289 using ivec_iter = typename TypeParam::const_iterator;
2290 using source_array = ::arene::base::array<value_type, TypeParam::capacity>;
2291 using throws_when_converted = typename TestFixture::throws_when_converted_to_t;
2292 using throw_conv_array = ::arene::base::array<throws_when_converted, TypeParam::capacity>;
2293 using throwing_it_throwing_type = typename TestFixture::template throwing_input_iterator<throws_when_converted>;
2294 using throwing_it_raw_type = typename TestFixture::template throwing_input_iterator<value_type>;
2295 using nothrow_it_throwing_type = typename TestFixture::template non_throwing_input_iterator<throws_when_converted>;
2296 using nothrow_it_raw_type = typename TestFixture::template non_throwing_input_iterator<value_type>;
2297
2298 constexpr bool is_nothrow_movable =
2299 std::is_nothrow_move_constructible<value_type>{} && std::is_nothrow_move_assignable<value_type>{};
2300
2301 STATIC_ASSERT_EQ(
2302 noexcept(this->construct().insert(
2303 std::declval<ivec_iter>(),
2304 std::declval<typename source_array::const_iterator>(),
2305 std::declval<typename source_array::const_iterator>()
2306 )),
2307 is_nothrow_movable && std::is_nothrow_copy_constructible<value_type>{}
2308 );
2309
2310 STATIC_ASSERT_FALSE(noexcept(this->construct().insert(
2311 std::declval<ivec_iter>(),
2312 std::declval<typename throw_conv_array::const_iterator>(),
2313 std::declval<typename throw_conv_array::const_iterator>()
2314 )));
2315
2316 STATIC_ASSERT_EQ(
2317 noexcept(this->construct().insert(
2318 std::declval<ivec_iter>(),
2319 std::declval<nothrow_it_raw_type>(),
2320 std::declval<nothrow_it_raw_type>()
2321 )),
2322 is_nothrow_movable && std::is_nothrow_copy_constructible<value_type>{}
2323 );
2324 STATIC_ASSERT_FALSE(noexcept(this->construct().insert(
2325 std::declval<ivec_iter>(),
2326 std::declval<::testing::demoted_iterator<throwing_it_throwing_type, std::input_iterator_tag>>(),
2327 std::declval<::testing::demoted_iterator<throwing_it_throwing_type, std::input_iterator_tag>>()
2328 )));
2329 STATIC_ASSERT_FALSE(noexcept(this->construct().insert(
2330 std::declval<ivec_iter>(),
2331 std::declval<throwing_it_throwing_type>(),
2332 std::declval<throwing_it_throwing_type>()
2333 )));
2334 STATIC_ASSERT_FALSE(noexcept(this->construct().insert(
2335 std::declval<ivec_iter>(),
2336 std::declval<throwing_it_raw_type>(),
2337 std::declval<throwing_it_raw_type>()
2338 )));
2339 STATIC_ASSERT_FALSE(noexcept(this->construct().insert(
2340 std::declval<ivec_iter>(),
2341 std::declval<nothrow_it_throwing_type>(),
2342 std::declval<nothrow_it_throwing_type>()
2343 )));
2344}
2345
2346/// @test `cbegin` and `cend` return `const_iterator`s to the corresponding locations of the `inline_vector`.
2348 auto const value1 = TestFixture::full_test_vector();
2349
2350 ASSERT_EQ(value1.cbegin(), value1.begin());
2351 ASSERT_EQ(value1.cend(), value1.end());
2352
2353 ::testing::StaticAssertTypeEq<decltype(value1.cbegin()), typename TypeParam::const_iterator>();
2354 STATIC_ASSERT_TRUE(noexcept(value1.cbegin()));
2355 STATIC_ASSERT_TRUE(noexcept(value1.cend()));
2356
2357 auto value2 = TestFixture::full_test_vector();
2358 ::testing::StaticAssertTypeEq<decltype(value2.cbegin()), typename TypeParam::const_iterator>();
2359 ::testing::StaticAssertTypeEq<decltype(value2.cend()), typename TypeParam::const_iterator>();
2360
2361 EXPECT_EQ(value2.begin(), value2.cbegin());
2362 EXPECT_EQ(value2.end(), value2.cend());
2363}
2364
2365/// @test `rbegin`, `rend`, `crbegin` and `crend` return reverse iterators to the appropriate locations in the
2366/// `inline_vector`, such that iteration _forwards_ from `rbegin` or `crbegin` iterates through the elements of the
2367/// `inline_vector` in reverse order.
2368TYPED_TEST_P(InlineVectorTest, ReverseIteration) {
2369 auto const value1 = TestFixture::full_test_vector();
2370
2371 auto itr = value1.rbegin();
2372 auto citr = value1.crbegin();
2373 for (std::size_t steps = 0UL; steps < value1.size(); ++steps) {
2374 ASSERT_NE(itr, value1.rend());
2375 ASSERT_NE(citr, value1.crend());
2376
2377 EXPECT_EQ(*itr, value1[value1.size() - steps - 1UL]);
2378 EXPECT_EQ(*citr, value1[value1.size() - steps - 1UL]);
2379
2380 ++itr;
2381 ++citr;
2382 }
2383 EXPECT_EQ(itr, value1.rend());
2384 EXPECT_EQ(citr, value1.crend());
2385}
2386
2387/// @test An `inline_vector` can be constructed from an `inline_vector` with a larger capacity, provided the number of
2388/// elements in the source vector is less than the capacity of the target vector
2390 InlineVectorTest,
2392 InlineVectorTest<TypeParam>::constexpr_compatible&&
2394) {
2395 constexpr std::size_t larger_capacity = TypeParam::capacity + 2UL;
2396 constexpr typename TestFixture::template vector_with_capacity<larger_capacity> large_vector{
2397 TestFixture::template test_initializer_list<TypeParam::capacity - 1UL>()
2398 };
2399
2400 constexpr TypeParam small_vector(large_vector);
2401
2402 STATIC_ASSERT_EQ(small_vector.size(), large_vector.size());
2403 STATIC_ASSERT_TRUE(equal(small_vector.begin(), small_vector.end(), large_vector.begin(), large_vector.end()));
2404}
2405
2406/// @test An `inline_vector` can be assigned from an `inline_vector` with a larger capacity, provided the number of
2407/// elements in the source vector is less than the capacity of the target vector
2409 constexpr std::size_t larger_capacity = TypeParam::capacity + 2UL;
2410 typename TestFixture::template vector_with_capacity<larger_capacity> const large_vector{
2411 TestFixture::template test_initializer_list<TypeParam::capacity - 1UL>()
2412 };
2413
2414 TypeParam small_vector;
2415 small_vector = large_vector;
2416
2417 EXPECT_EQ(small_vector.size(), large_vector.size());
2418 for (std::size_t i = 0; i < small_vector.size(); ++i) {
2419 EXPECT_EQ(small_vector[i], large_vector[i]);
2420 }
2421}
2422
2423/// @test `try_construct` can be used to construct an empty `inline_vector`.
2425 STATIC_ASSERT_TRUE(std::is_same<decltype(TypeParam::try_construct()), ::arene::base::optional<TypeParam>>::value);
2426 STATIC_ASSERT_TRUE(noexcept(TypeParam::try_construct()));
2427
2428 COND_STATIC_ASSERT_TRUE(TypeParam::try_construct().has_value());
2429 COND_STATIC_ASSERT_TRUE(TypeParam::try_construct()->empty());
2430}
2431
2432/// @test `try_construct` can be used to construct an `inline_vector` with a specified number of elements
2434 InlineVectorTest,
2437) {
2438 STATIC_ASSERT_TRUE(std::is_same<decltype(TypeParam::try_construct(0)), ::arene::base::optional<TypeParam>>::value);
2439 STATIC_ASSERT_EQ(
2440 noexcept(TypeParam::try_construct(0)),
2441 std::is_nothrow_default_constructible<typename TypeParam::value_type>::value
2442 );
2443
2444 COND_STATIC_ASSERT_TRUE(TypeParam::try_construct(TypeParam::capacity).has_value());
2445 COND_STATIC_ASSERT_FALSE(TypeParam::try_construct(TypeParam::capacity)->empty());
2446 COND_STATIC_ASSERT_EQ(TypeParam::try_construct(TypeParam::capacity)->size(), TypeParam::capacity);
2447}
2448
2449/// @test `try_construct` can be used to attempt to construct an `inline_vector` with a specified number of elements
2450/// that exceeds the capacity of the vector, in which case the result is an empty `optional`.
2452 InlineVectorTest,
2455) {
2456 constexpr std::size_t size1 = TypeParam::capacity + 1UL;
2457 STATIC_ASSERT_TRUE(std::is_same<decltype(TypeParam::try_construct(size1)), ::arene::base::optional<TypeParam>>::value
2458 );
2459 STATIC_ASSERT_EQ(
2460 noexcept(TypeParam::try_construct(size1)),
2461 std::is_nothrow_default_constructible<typename TypeParam::value_type>::value
2462 );
2463
2464 COND_STATIC_ASSERT_FALSE(TypeParam::try_construct(size1).has_value());
2465}
2466
2467/// @test `try_construct` with a number of elements is not considered for overload resolution if the element type of the
2468/// `inline_vector<T>` is not default-constructible.
2470 constexpr bool can_construct_with_size_only =
2471 ::arene::base::substitution_succeeds<TestFixture::template try_construct_result, TypeParam, std::size_t>;
2472 STATIC_ASSERT_EQ(can_construct_with_size_only, std::is_default_constructible<typename TypeParam::value_type>{});
2473}
2474
2475/// @test The `inline_vector` constructor with a number of elements is not considered for overload resolution if the
2476/// element type of the `inline_vector<T>` is not default-constructible.
2478 STATIC_ASSERT_EQ(
2479 (std::is_constructible<TypeParam, std::size_t>::value),
2480 std::is_default_constructible<typename TypeParam::value_type>{}
2481 );
2482}
2483
2484/// @test The default constructor and corresponding `try_construct` function of `inline_vector<T>` is always `noexcept`,
2485/// even if the stored element type's default constructor can throw
2487 STATIC_ASSERT_TRUE(noexcept(TypeParam::try_construct()));
2488 STATIC_ASSERT_TRUE(noexcept(TypeParam{}));
2489
2490 COND_STATIC_ASSERT_TRUE(TypeParam::try_construct().has_value());
2491 COND_STATIC_ASSERT_TRUE(TypeParam::try_construct()->empty());
2492 COND_STATIC_ASSERT_TRUE(TypeParam().empty());
2493}
2494
2495/// @test The `try_construct` function of `inline_vector` that takes a number of elements is not `noexcept` if the
2496/// default constructor of the stored element type is not `noexcept`
2498 InlineVectorTest,
2501) {
2502 STATIC_ASSERT_TRUE(std::is_same<decltype(TypeParam::try_construct(0)), ::arene::base::optional<TypeParam>>::value);
2503 STATIC_ASSERT_EQ(
2504 noexcept(TypeParam::try_construct(0)),
2505 std::is_nothrow_default_constructible<typename TypeParam::value_type>{}
2506 );
2507}
2508
2509/// @test The constructor of `inline_vector` that takes a number of elements is not `noexcept` if the default
2510/// constructor of the stored element type is not `noexcept`
2512 InlineVectorTest,
2515) {
2516 STATIC_ASSERT_EQ(noexcept(TypeParam(0)), std::is_nothrow_default_constructible<typename TypeParam::value_type>{});
2517}
2518
2519/// @test Specifying a number of elements larger than the capacity of an `inline_vector` when invoking the
2520/// constructor terminates the program with a precondition violation
2522 InlineVectorDeathTest,
2525) {
2526 constexpr std::size_t size1 = TypeParam::capacity + 1UL;
2527 ASSERT_DEATH(this->construct(size1), "Precondition violation"); // dies regardless of exception behavior
2528}
2529
2530/// @test The overload of `try_construct` that takes a size and source value is not considered for overload resolution
2531/// if the element type of the `inline_vector<T>` is not copy-constructible.
2533 using value_type = typename TypeParam::value_type;
2534 constexpr bool copy_ok = std::is_copy_constructible<value_type>::value;
2535 STATIC_ASSERT_EQ((std::is_constructible<TypeParam, std::size_t, value_type>::value), copy_ok);
2536 STATIC_ASSERT_EQ(
2537 (::arene::base::
2538 substitution_succeeds<TestFixture::template try_construct_result, TypeParam, std::size_t, value_type>),
2539 copy_ok
2540 );
2541}
2542
2543/// @test The overload of `try_construct` that takes an initializer list is not considered for overload resolution if
2544/// the element type of the `inline_vector` is not copy-constructible.
2546 STATIC_ASSERT_EQ(
2547 (std::is_constructible<TypeParam, std::initializer_list<typename TypeParam::value_type>>::value),
2548 std::is_copy_constructible<typename TypeParam::value_type>::value
2549 );
2550 STATIC_ASSERT_EQ(
2551 (arene::base::substitution_succeeds<
2552 TestFixture::template try_construct_result,
2553 TypeParam,
2554 std::initializer_list<typename TypeParam::value_type>>),
2555 std::is_copy_constructible<typename TypeParam::value_type>::value
2556 );
2557}
2558
2559/// @test Invoking `try_construct` with an initializer list constructs an `inline_vector` holding copies of the elements
2560/// from the initializer list
2562 InlineVectorTest,
2564 std::is_copy_constructible<typename TypeParam::value_type>::value
2565) {
2566 auto const values = TestFixture::full_test_initializer_list();
2567
2568 STATIC_ASSERT_EQ(
2569 noexcept(TypeParam::try_construct(values)),
2570 std::is_nothrow_copy_constructible<typename TypeParam::value_type>{}
2571 );
2572 ASSERT_TRUE(TypeParam::try_construct(values).has_value());
2573 ASSERT_EQ(TypeParam::try_construct(values)->size(), values.size());
2574
2575 auto res = TypeParam::try_construct(values);
2576 EXPECT_THAT(*res, ::testing::ElementsAreArray(values));
2577}
2578
2579/// @test Invoking `try_construct` with an initializer list holding more elements than the capacity of the
2580/// `inline_vector` returns an empty `optional`
2582 InlineVectorTest,
2584 std::is_copy_constructible<typename TypeParam::value_type>::value
2585) {
2586 auto const values = TestFixture::template test_initializer_list<TypeParam::capacity + 1UL>();
2587
2588 ASSERT_FALSE(TypeParam::try_construct(values).has_value());
2589}
2590
2591/// @test Invoking `try_construct` with an existing `inline_vector` returns a copy of that source vector
2593 InlineVectorTest,
2595 std::is_copy_constructible<typename TypeParam::value_type>::value
2596) {
2597 using value_type = typename TypeParam::value_type;
2598 auto const values = TestFixture::full_test_vector();
2599
2600 STATIC_ASSERT_TRUE(::arene::base::substitution_succeeds<
2601 TestFixture::template try_construct_result,
2602 TypeParam,
2603 TypeParam const&>);
2604 STATIC_ASSERT_EQ(noexcept(TypeParam::try_construct(values)), std::is_nothrow_copy_constructible<value_type>::value);
2605 auto res = TypeParam::try_construct(values);
2606 ASSERT_TRUE(res.has_value());
2607 EXPECT_THAT(*res, ::testing::ElementsAreArray(values));
2608}
2609
2610/// @test Constructing an `inline_vector` with an existing `inline_vector` copies the elements from the source vector
2612 InlineVectorTest,
2614 std::is_copy_constructible<typename TypeParam::value_type>::value
2615) {
2616 auto const values = TestFixture::full_test_vector();
2617
2618 STATIC_ASSERT_EQ(noexcept(TypeParam(values)), std::is_nothrow_copy_constructible<typename TypeParam::value_type>{});
2619 auto res = this->construct(values);
2620 EXPECT_THAT(res, ::testing::ElementsAreArray(values));
2621}
2622
2623/// @test Invoking `try_construct` with an existing `inline_vector` with a smaller capacity returns an `inline_vector`
2624/// with the same elements as the source vector
2626 InlineVectorTest,
2628 std::is_copy_constructible<typename TypeParam::value_type>::value
2629) {
2630 // typename TestFixture::template vector_with_capacity<TypeParam::capacity - 1> const values{
2631 // TestFixture::test_vector(TypeParam::capacity - 1)
2632 // };
2633
2634 auto const values = ::arene::base::testing::test_vector<typename TypeParam::value_type, TypeParam::capacity - 1>(
2635 0,
2636 TypeParam::capacity - 1
2637 );
2638
2639 STATIC_ASSERT_TRUE(::arene::base::substitution_succeeds<
2640 TestFixture::template try_construct_result,
2641 TypeParam,
2642 TypeParam const&>);
2643 STATIC_ASSERT_EQ(
2644 noexcept(TypeParam::try_construct(values)),
2645 std::is_nothrow_copy_constructible<typename TypeParam::value_type>::value
2646 );
2648 ARENE_IGNORE_GCC(
2649 "-Wmaybe-uninitialized",
2650 "GCC issues false positive here when compiling with -fno-exceptions and using GCC's stdlib"
2651 );
2652 auto res = TypeParam::try_construct(values);
2653 ARENE_IGNORE_END();
2654 ASSERT_TRUE(res.has_value());
2655 EXPECT_THAT(*res, ::testing::ElementsAreArray(values));
2656}
2657
2658/// @test Constructing an `inline_vector` from an existing `inline_vector` with a smaller capacity returns an
2659/// `inline_vector` with the same elements as the source vector
2661 InlineVectorTest,
2663 std::is_copy_constructible<typename TypeParam::value_type>::value
2664) {
2665 static typename TestFixture::template vector_with_capacity<TypeParam::capacity - 1> const values{
2666 TestFixture::test_vector(TypeParam::capacity - 1)
2667 };
2668
2669 STATIC_ASSERT_EQ(noexcept(TypeParam(values)), std::is_nothrow_copy_constructible<typename TypeParam::value_type>{});
2670 auto res = this->construct(values);
2671 EXPECT_THAT(res, ::testing::ElementsAreArray(values));
2672}
2673
2674/// @test Invoking `try_construct` with an existing `inline_vector` with a larger capacity but a size that is less than
2675/// or equal to the capacity of the destination type returns an `inline_vector` with the same elements as the source
2676/// vector
2678 InlineVectorTest,
2680 std::is_copy_constructible<typename TypeParam::value_type>::value
2681) {
2682 auto const values = ::arene::base::testing::test_vector<typename TypeParam::value_type, TypeParam::capacity + 1>(
2683 0,
2684 TypeParam::capacity
2685 );
2686
2687 STATIC_ASSERT_TRUE(::arene::base::substitution_succeeds<
2688 TestFixture::template try_construct_result,
2689 TypeParam,
2690 TypeParam const&>);
2691 STATIC_ASSERT_EQ(
2692 noexcept(TypeParam::try_construct(values)),
2693 std::is_nothrow_copy_constructible<typename TypeParam::value_type>::value
2694 );
2695 auto res = TypeParam::try_construct(values);
2696 ASSERT_TRUE(res.has_value());
2697 EXPECT_THAT(*res, ::testing::ElementsAreArray(values));
2698}
2699
2700/// @test Invoking `try_construct` with an existing `inline_vector` with a larger capacity and a size that is larger
2701/// than the capacity of the destination type returns an empty `optional`
2703 InlineVectorTest,
2705 std::is_copy_constructible<typename TypeParam::value_type>::value
2706) {
2707 auto const values = ::arene::base::testing::test_vector<typename TypeParam::value_type, TypeParam::capacity + 1>(
2708 0,
2709 TypeParam::capacity + 1
2710 );
2711
2712 ASSERT_GT(values.size(), TypeParam::capacity);
2713 ASSERT_FALSE(TypeParam::try_construct(values).has_value());
2714}
2715
2716/// @test Constructing an `inline_vector` from an existing `inline_vector` with a larger capacity but a size that is
2717/// less than or equal to the capacity of the destination type copies elements from the source vector
2719 InlineVectorTest,
2721 std::is_copy_constructible<typename TypeParam::value_type>::value
2722) {
2723 auto const values = ::arene::base::testing::test_vector<typename TypeParam::value_type, TypeParam::capacity + 1>(
2724 0,
2725 TypeParam::capacity
2726 );
2727 constexpr bool copy_is_noexcept = std::is_nothrow_copy_constructible<typename TypeParam::value_type>::value;
2728
2729 STATIC_ASSERT_EQ(noexcept(TypeParam(values)), copy_is_noexcept);
2730 auto res = this->construct(values);
2731 EXPECT_THAT(res, ::testing::ElementsAreArray(values));
2732}
2733
2734/// @test `inline_vector` is not copy-constructible if the data type is not copy-constructible
2736 using smaller_vec = typename TestFixture::template vector_with_capacity<TypeParam::capacity - 1>;
2737 using larger_vec = typename TestFixture::template vector_with_capacity<TypeParam::capacity + 1>;
2738 constexpr bool copy_ok = std::is_copy_constructible<typename TypeParam::value_type>::value;
2739
2740 STATIC_ASSERT_EQ((std::is_constructible<TypeParam, TypeParam const&>::value), copy_ok);
2741 STATIC_ASSERT_EQ(
2742 (::arene::base::substitution_succeeds<TestFixture::template try_construct_result, TypeParam, TypeParam const&>),
2743 copy_ok
2744 );
2745 STATIC_ASSERT_EQ((std::is_constructible<TypeParam, smaller_vec const&>::value), copy_ok);
2746 STATIC_ASSERT_EQ(
2747 (::arene::base::substitution_succeeds<TestFixture::template try_construct_result, TypeParam, smaller_vec const&>),
2748 copy_ok
2749 );
2750 STATIC_ASSERT_EQ((std::is_constructible<TypeParam, larger_vec const&>::value), copy_ok);
2751 STATIC_ASSERT_EQ(
2752 (::arene::base::substitution_succeeds<TestFixture::template try_construct_result, TypeParam, larger_vec const&>),
2753 copy_ok
2754 );
2755}
2756
2757/// @test Invoking `try_construct` with an rvalue `inline_vector` constructs a new `inline_vector`, and move-constructs
2758/// the elements from the source to the new vector.
2760 auto const values = TestFixture::full_test_vector();
2761 auto values_copy = TestFixture::full_test_vector();
2762
2763 STATIC_ASSERT_TRUE(::arene::base::
2764 substitution_succeeds<TestFixture::template try_construct_result, TypeParam, TypeParam&&>);
2765 STATIC_ASSERT_EQ(
2766 noexcept(TypeParam::try_construct(std::move(values_copy))),
2767 std::is_nothrow_move_constructible<typename TypeParam::value_type>::value
2768 );
2769 auto res = TypeParam::try_construct(std::move(values_copy));
2770 ASSERT_TRUE(res.has_value());
2771 EXPECT_TRUE(elements_are_array(*res, values));
2772}
2773
2774/// @test Constructing an `inline_vector` from an rvalue `inline_vector` move-constructs the elements from the source to
2775/// the new vector.
2777 auto const values = TestFixture::full_test_vector();
2778 auto source = TestFixture::full_test_vector();
2779
2780 // NOLINTNEXTLINE(hicpp-move-const-arg)
2781 STATIC_ASSERT_EQ(
2782 noexcept(TypeParam(std::move(source))),
2783 std::is_nothrow_move_constructible<typename TypeParam::value_type>::value
2784 );
2785 // NOLINTNEXTLINE(hicpp-move-const-arg)
2786 auto res = this->construct(std::move(source));
2787 EXPECT_TRUE(elements_are_array(res, values));
2788}
2789
2790/// @test Invoking `try_construct` with an rvalue `inline_vector` with a larger capacity and a size that is larger
2791/// than the capacity of the destination type returns an empty `optional`
2793 auto values = ::arene::base::testing::test_vector<typename TypeParam::value_type, TypeParam::capacity + 1>(
2794 0,
2795 TypeParam::capacity + 1
2796 );
2797
2798 ASSERT_GT(values.size(), TypeParam::capacity);
2799
2800 ASSERT_FALSE(TypeParam::try_construct(std::move(values)).has_value());
2801}
2802
2803/// @test `inline_vector` is not move constructible if the element type is not move constructible
2805 using ivec = typename TestFixture::template vector_with_capacity<TypeParam::capacity>;
2806 using smaller_vec = typename TestFixture::template vector_with_capacity<TypeParam::capacity - 1>;
2807 using larger_vec = typename TestFixture::template vector_with_capacity<TypeParam::capacity + 1>;
2808 constexpr bool move_ok = std::is_move_constructible<typename TypeParam::value_type>::value;
2809
2810 STATIC_ASSERT_EQ((std::is_constructible<ivec, ivec&&>::value), move_ok);
2811 STATIC_ASSERT_EQ(
2812 (::arene::base::substitution_succeeds<TestFixture::template try_construct_result, ivec, ivec&&>),
2813 move_ok
2814 );
2815 STATIC_ASSERT_EQ((std::is_constructible<ivec, smaller_vec&&>::value), move_ok);
2816 STATIC_ASSERT_EQ(
2817 (::arene::base::substitution_succeeds<TestFixture::template try_construct_result, ivec, smaller_vec&&>),
2818 move_ok
2819 );
2820 STATIC_ASSERT_EQ((std::is_constructible<ivec, larger_vec&&>::value), move_ok);
2821 STATIC_ASSERT_EQ(
2822 (::arene::base::substitution_succeeds<TestFixture::template try_construct_result, ivec, larger_vec&&>),
2823 move_ok
2824 );
2825}
2826
2827/// @test Invoking `try_construct` with an iterator range returns an `inline_vector` with the same elements as the
2828/// source range
2830 auto const expected = TestFixture::full_test_vector();
2831 auto source = TestFixture::full_test_vector();
2832
2833 auto maybe_vec =
2834 TypeParam::try_construct(std::make_move_iterator(source.begin()), std::make_move_iterator(source.end()));
2835 ASSERT_TRUE(maybe_vec.has_value());
2836
2837 ASSERT_EQ(maybe_vec->size(), source.size());
2838 ASSERT_TRUE(elements_are_array(*maybe_vec, expected));
2839}
2840
2841/// @test `try_construct` from an iterator range is `noexcept` if the element type of the vector is
2842/// nothrow-constructible from the iterator's reference type
2843// Note: std::move_iterator is not marked noexcept, so this test requires the type to be copy constructible.
2845 InlineVectorTest,
2847 std::is_copy_constructible<typename TypeParam::value_type>::value
2848) {
2849 using array = ::arene::base::array<typename TypeParam::value_type, TypeParam::capacity>;
2850 using throws_when_converted = typename TestFixture::throws_when_converted_to_t;
2851 using convertible_array = ::arene::base::array<throws_when_converted, TypeParam::capacity>;
2852 using throwing_bidirectional_iterator = typename TestFixture::throwing_bidirectional_move_iterator_of_t;
2853
2854 STATIC_ASSERT_EQ(
2855 noexcept(TypeParam::try_construct(
2856 std::declval<typename array::const_iterator>(),
2857 std::declval<typename array::const_iterator>()
2858 )),
2859 std::is_nothrow_copy_constructible<typename TypeParam::value_type>::value
2860 );
2861 STATIC_ASSERT_FALSE(noexcept(TypeParam::try_construct(
2862 std::declval<typename convertible_array::const_iterator>(),
2863 std::declval<typename convertible_array::const_iterator>()
2864 )));
2865 STATIC_ASSERT_FALSE(noexcept(TypeParam::try_construct(
2866 std::declval<throwing_bidirectional_iterator>(),
2867 std::declval<throwing_bidirectional_iterator>()
2868 )));
2869}
2870
2871/// @test `try_construct` from an input iterator range is `noexcept` if the element type of the vector is
2872/// nothrow-constructible from the iterator's reference type
2874 InlineVectorTest,
2876 std::is_copy_constructible<typename TypeParam::value_type>::value
2877) {
2878 using value_type = typename TypeParam::value_type;
2879 using throws_when_converted = typename TestFixture::throws_when_converted_to_t;
2880 using throwing_it_throwing_type = typename TestFixture::template throwing_input_iterator<throws_when_converted>;
2881 using throwing_it_raw_type = typename TestFixture::template throwing_input_iterator<value_type>;
2882 using nothrow_it_throwing_type = typename TestFixture::template non_throwing_input_iterator<throws_when_converted>;
2883 using nothrow_it_raw_type = typename TestFixture::template non_throwing_input_iterator<value_type>;
2884
2885 STATIC_ASSERT_EQ(
2886 noexcept(TypeParam::try_construct(
2887 std::declval<::testing::demoted_iterator<value_type*, std::input_iterator_tag>>(),
2888 std::declval<::testing::demoted_iterator<value_type*, std::input_iterator_tag>>()
2889 )),
2890 std::is_nothrow_copy_constructible<value_type>::value
2891 );
2892 STATIC_ASSERT_FALSE(noexcept(
2893 TypeParam::try_construct(std::declval<throwing_it_throwing_type>(), std::declval<throwing_it_throwing_type>())
2894 ));
2895 STATIC_ASSERT_FALSE(
2896 noexcept(TypeParam::try_construct(std::declval<throwing_it_raw_type>(), std::declval<throwing_it_raw_type>()))
2897 );
2898 STATIC_ASSERT_EQ(
2899 noexcept(TypeParam::try_construct(std::declval<nothrow_it_raw_type>(), std::declval<nothrow_it_raw_type>())),
2900 std::is_nothrow_copy_constructible<value_type>::value
2901 );
2902 STATIC_ASSERT_FALSE(noexcept(
2903 TypeParam::try_construct(std::declval<nothrow_it_throwing_type>(), std::declval<nothrow_it_throwing_type>())
2904 ));
2905}
2906
2907/// @test Dereferencing a default-constructed `inline_vector` iterator terminates the program with a precondition
2908/// violation
2910 ASSERT_DEATH(*typename TypeParam::iterator{}, "Precondition violation");
2911 ASSERT_DEATH(*typename TypeParam::const_iterator{}, "Precondition violation");
2912}
2913
2914/// @test Iterator arithmetic on a default-constructed `inline_vector` iterator terminates the program with a
2915/// precondition violation
2917 ASSERT_DEATH(typename TypeParam::iterator{} + 1, "Precondition violation");
2918 ASSERT_DEATH(typename TypeParam::const_iterator{} + 1, "Precondition violation");
2919}
2920
2922
2924 InlineVectorTest,
2955 CanUseBack,
2957 Front,
2962 Typedefs,
2963 Iteration,
2967 CanErase,
2979 CanPopBack,
2994 CanInsert,
3015 Data,
3017 ClearWorks,
3025 CanEmplace,
3030 CanSwap,
3070);
3071
3073 InlineVectorDeathTest,
3087);
3088
3089} // namespace testing
3090} // namespace base
3091} // namespace arene
3092
3093#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_INLINE_CONTAINER_TESTING_VECTOR_HPP_
The Death Tests use the same fixture as the "normal" tests. Inherits so that it will be a distinct ty...
Definition vector.hpp:344
Test fixture for all type-parameterized inline_vector tests.
Definition vector.hpp:159
static constexpr auto test_vector(std::size_t begin, std::size_t end) noexcept(noexcept(::arene::base::testing::test_vector< T, capacity >(begin, end))) -> Vector
Return a Vector containing the test values [begin,end) of T , parameterized by test suite users.
Definition vector.hpp:299
static constexpr bool constexpr_compatible
Whether or not the current type parameter is constexpr compatible for this test.
Definition vector.hpp:164
static constexpr std::size_t capacity
The base capacity to use for most inline_vector instantiations in the parameterized tests.
Definition vector.hpp:172
static constexpr auto full_test_initializer_list() noexcept -> std::initializer_list< T >
Return a std::initializer_list containing capacity user-parameterized test_value s.
Definition vector.hpp:336
static void SetUpTestSuite()
Definition vector.hpp:176
static constexpr auto test_initializer_list(std::index_sequence< Indices... >) noexcept -> std::initializer_list< T >
Return a std::initializer_list containing user-parameterized test_value s.
Definition vector.hpp:322
static constexpr auto unique_test_value() noexcept(noexcept(::arene::base::testing::unique_test_value< T, N >())) -> N >())
Return the N 'th test value of the current T , parameterized by test suite users.
Definition vector.hpp:290
static constexpr auto full_test_vector() noexcept(noexcept(test_vector(capacity))) -> Vector
Return a Vector containing the test values [0,capacity) of T , parameterized by test suite users.
Definition vector.hpp:314
static constexpr auto test_initializer_list() noexcept -> std::initializer_list< T >
Return a std::initializer_list containing user-parameterized test_value s.
Definition vector.hpp:330
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 vector.hpp:280
static constexpr auto test_vector(std::size_t size) noexcept(noexcept(test_vector(0, size))) -> Vector
Return a Vector containing the test values [0,size) of T , parameterized by test suite users.
Definition vector.hpp:308
static constexpr auto construct(U &&... params) noexcept(noexcept(Vector(std::forward< U >(params)...))) -> Vector
Construct a Vector from the passed parameters; allows calling as this->construct, which can be shorte...
Definition vector.hpp:273
Definition vector.hpp:1859
auto operator=(move_only_wrapper &&) -> move_only_wrapper &=default
move_only_wrapper(value_type value)
Definition vector.hpp:1864
move_only_wrapper(move_only_wrapper &&)=default
auto get() -> value_type &
Definition vector.hpp:1872
move_only_wrapper(move_only_wrapper const &)=delete
auto operator=(move_only_wrapper const &) -> move_only_wrapper &=delete
Definition customization.hpp:36
constexpr auto sort_helper(Container container) noexcept -> Container
sorts the container and then returns it
Definition vector.hpp:130
constexpr auto constexpr_resize(Vec vec, std::size_t size) -> Vec
Definition external_vector.hpp:1068
constexpr auto constexpr_emplace_back(Args &&... args) -> Container
Definition vector.hpp:1909
constexpr auto vector_push_back(Vector &vec, Values &&... values) -> void
Push back multiple values into a vector.
Definition vector.hpp:117
constexpr auto elements_are_array(Range1 const &range, Range2 const &values) -> bool
Check if all element of range are equal to the elements in values.
Definition vector.hpp:91
constexpr auto all_elements_are(Range const &range, T const &value) -> bool
Check if all element of range are equal to value.
Definition vector.hpp:78
constexpr auto constexpr_non_const_front(Vec &&vec) -> typename Vec::value_type
Definition vector.hpp:687
TYPED_TEST_SUITE_P(InlineVectorDeathTest)
constexpr auto constexpr_pop_back(Vec &&vec) -> Vec
Definition vector.hpp:1116
REGISTER_TYPED_TEST_SUITE_P(InlineVectorTest, CanConstructAnEmptyVector, CapacityIsAsSpecified, CapacityIsNoexcept, InitialSizeIsZero, SizeIsConstexpr, SizeIsNoexcept, CanPushBackAValue, AfterPushBackCanGetLastElement, AfterPushBackVectorIsNotEmpty, SecondPushBackChangesLastValue, PushBackIsConditionallyNoexceptRvalue, PushBackIsConditionallyNoexceptLvalue, EmptyIsConstexpr, EmptyIsNoexcept, RetrievingAValueWithAtThrowsOnEmpty, RetrievingAValueWithAtReturnsValueAfterPushBack, AtReturnsReference, AtOnConstVectorReturnsConstReference, CanAccessMultipleValuesWithAt, AtIndexSizeOrLargerThrows, CanAccessMultipleValuesWithAtWithConstVec, AtIndexSizeOrLargerThrowsWithConstVec, MaxSizeEqualsCapacity, ZeroSizeVectorIsEmpty, BackReturnsReference, ConstBackReturnsConstReference, BackIsNoexcept, CanPushBack, CanConstructFromInitializerList, CanConstructFromInitializerListConstexpr, CanUseBack, CanGetFront, Front, CanGetIterator, CanIterateOverValues, CanIterateOverConstValues, IteratorTypedefs, Typedefs, Iteration, ConstIteration, CanEraseAtBeginning, CanEraseInMiddle, CanErase, CanEraseRange, CanConstructWithSize, CanConstructWithSizeAndValue, CopyingVectorCopiesElements, MovingVectorMovesElements, CopyAssignOverSmallerVectorCopiesElements, CopyAssignOverLargerVectorDestroysExcess, CopyingIsConditionallyDefined, MoveAssignOverSmallerVectorMovesElements, MoveAssignOverLargerVectorDestroysExcess, MovingIsConditionallyDefined, CanPopBack, PopBackIsNoexcept, PopBackIsUsable, EraseIsNoexceptIfTypeHasNoexceptMove, CanInsertInEmptyVector, CanInsertAtEndOfExistingVector, CanInsertInMiddleOfExistingVector, ResizeZeroCapacityVecToZeroIsOk, ResizeNonZeroCapacityVecToZeroIsOk, ResizeNonZeroCapacityVecToOtherIsOk, ResizeIsConditionallyNoexcept, ResizeWithValueIsConditionallyNoexcept, ResizingFromLargeToSmallLeavesElements, ResizingFromSmallToLargeConstructsElementsAsCopiesOfSpecified, CanInitializeWithSizeAndValue, CanInsert, CanConstructFromIteratorRange, IteratorRangeConstructionIsConditionallyNoexcept, InputIteratorRangeConstructionIsConditionallyNoexcept, CanConstructFromIteratorRangeConstexpr, CopyAssignOverSmallerVectorFromInitListCopiesElements, CopyAssignOverLargerVectorFromInitListDestroysExcess, CanAssignFromIteratorRange, IteratorRangeAssignmentIsConditionallyNoexcept, CanAssignFromInputIteratorRange, InputIteratorRangeAssignmentIsConditionallyNoexcept, CanAssignFromInitListUsingAssignFunction, AssignFromInitListUsingAssignFunctionIsConditionallyNoexcept, CanAssignFromSizeAndValue, AssignFromSizeAndValueIsConditionallyNoexcept, IndexOperatorReturnsReference, IndexOperatorOnConstVectorReturnsConstReference, CanAccessMultipleValuesWithIndexOperator, IndexOperatorIsNoexcept, IndexOperatorOnConstVectorIsNoexcept, IndexOperator, Data, AfterClearVectorIsEmpty, ClearWorks, CanCompareForEquality, CanCompareForOrdering, CanEmplaceBack, CanEmplaceBackConstexpr, EmplaceBackIsConditionallyNoexceptRvalue, EmplaceBackIsConditionallyNoexceptLvalue, EmplaceInsert, CanEmplace, EmplaceAtPositionIsConditionallyNoexceptRvalue, EmplaceAtPositionIsConditionallyNoexceptLvalue, DefaultEmplaceIsConditionallyNoexcept, ADLSwapSwapsContentsForBasicTypes, CanSwap, SwapNoexceptMatchesElementType, InsertRvalueIsConditionallyNoexcept, InsertLvalueIsConditionallyNoexcept, InsertWithCountIsConditionallyNoexcept, InsertNAtEndInsertsElements, InsertNInMiddleInsertsElements, InsertFromIteratorRangeInMiddle, InsertFromIteratorRangeIsConditionallyNoexcept, CanGetCBeginAndEnd, ReverseIteration, CanConstructFromBiggerCapacityVector, CanAssignFromBiggerCapacityVector, CanDefaultConstructViaTryConstruct, CanConstructWithSizeViaTryConstruct, ConstructWithExcessiveSizeViaTryConstructFails, CannotTryConstructWithSizeForANonDefaultConstructibleType, CannotConstructWithSizeForANonDefaultConstructibleType, DefaultTryConstructNoexceptEvenIfDefaultConstructorNotNoexcept, ConstructWithSizeViaTryConstructNotNoexceptIfDefaultConstructorNotNoexcept, ConstructWithSizeViaNormalConstructWithDefaultConstructorNotNoexceptIsNotNoexcept, NotConstructibleWithSizeAndSourceIfDataNotCopyable, NotConstructibleFromInitializerListIfDataTypeNotCopyConstructible, CanTryConstructFromInitializerList, TryConstructFromTooLargeInitializerListReturnsEmpty, CanCopyViaTryConstruct, CanCopyViaConstruct, CanCopyViaTryConstructFromSmaller, CanCopyViaConstructFromSmaller, CanCopyViaTryConstructFromLargerWithFewerElements, FailToCopyViaTryConstructFromLargerWithMoreElements, CanCopyViaConstructFromLargerWithFewerElements, NotCopyConstructibleIfDataTypeNotCopyConstructible, CanMoveViaTryConstruct, CanMoveViaConstruct, FailToMoveViaTryConstructFromLargerWithMoreElements, NotMoveConstructibleIfDataTypeNotMoveConstructible, CanTryConstructFromIteratorRange, IteratorRangeTryConstructionIsConditionallyNoexcept, InputIteratorRangeTryConstructionIsConditionallyNoexcept)
constexpr auto constexpr_insert(Vec &&vec, std::ptrdiff_t offset, T &&value) -> Vec
Definition vector.hpp:1368
constexpr auto constexpr_non_const_back(Vec &&vec) -> typename Vec::value_type
Definition vector.hpp:657
constexpr auto constexpr_erase(std::size_t index, Args &&... args) -> Vec
Definition vector.hpp:848
constexpr auto test_vector(std::size_t begin, std::size_t end) noexcept(std::is_nothrow_copy_constructible< T >::value) -> ::arene::base::inline_vector< T, Capacity >
Create a test vector containing a range of test values.
Definition vector.hpp:102
constexpr auto constexpr_emplace(Vec &&vec, std::ptrdiff_t pos, Arg &&arg) -> Vec
Definition vector.hpp:2044
constexpr auto erase_front(Vec &&vec, std::size_t count)
Definition vector.hpp:1800
ARENE_IGNORE_ALL("-Wfloat-equal", "These tests don't perform arithmetic, so equality is OK even for floating point")
MATCHER_P(elements_match_function, function, "")
Definition external_vector.hpp:936
constexpr auto is_copyable_v
True if a type is copy constructible and copy assignable, false otherwise.
Definition vector.hpp:150
constexpr auto constexpr_clear(Vec vec) -> Vec
Definition vector.hpp:1756
CONDITIONAL_TYPED_TEST_P(InlineVectorTest, CanConstructFromInitializerListConstexpr, InlineVectorTest< TypeParam >::constexpr_compatible &&std::is_copy_constructible< typename TypeParam::value_type >::value)
Definition vector.hpp:643
TYPED_TEST_SUITE_P(InlineVectorTest)
constexpr auto constexpr_iterate(std::initializer_list< typename Vec::value_type > const values, Vec vec) -> bool
Check that iteration works when taking a vector with the given type.
Definition vector.hpp:771
constexpr bool is_fully_comparable_v
Definition external_vector.hpp:1634
REGISTER_TYPED_TEST_SUITE_P(ExternalVectorDeathTest, AddingToInvalidIteratorIsPreconditionViolation, AssignIsPreconditionViolationIfSizeOverCapacity, ConstructWithExcessiveSizeViaNormalConstructIsAlwaysPreconditionViolation, ConstructingWithOutOfRangeSizeAndSourceIsPreconditionViolation, ConstructingWithOutOfRangeSizeIsPreconditionViolation, ConstructingWithTooManyInitializersIsPreconditionViolation, DereferencingInvalidIteratorIsPreconditionViolation, EmplaceBackIsPreconditionViolationIfFull, IndexOperatorOutOfRange, InsertNIsPreconditionViolationIfTooManyItems, InsertWhenAtCapacityIsPreconditionViolation, PushBackBeyondMaxSizeIsPreconditionViolation, PushBackOnZeroSizeVectorIsPreconditionViolation)
constexpr auto constexpr_swap(Vec lhs, Vec rhs) -> std::pair< Vec, Vec >
Definition vector.hpp:2135
Definition array_exceptions_disabled.cpp:11
CONDITIONAL_TYPED_TEST_P(InlineDequeTest, PushFrontOneElement, is_double_ended< TypeParam >)
Definition deque.hpp:218
TYPED_TEST_P(InlineDequeTest, CanConstruct)
Definition deque.hpp:196
CONDITIONAL_TYPED_TEST_P(InlineDequeTest, BasicFunctionFromBack, TypeParam::capacity >=2)
Definition deque.hpp:546
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10
An input iterator pointing to any type whose operators have adjustable noexcept specifications.
Definition vector.hpp:235
auto operator++() noexcept(OperatorsNoexcept) -> input_iterator_with_configurable_noexcept &
Pre-increment operator; never defined.
auto operator*() const noexcept(OperatorsNoexcept) -> reference
Dereference operator; never defined.
auto operator!=(input_iterator_with_configurable_noexcept const &) noexcept(OperatorsNoexcept) -> bool
Inequality operator; never defined.
auto operator++(int) noexcept(OperatorsNoexcept) -> input_iterator_with_configurable_noexcept
Post-increment operator; never defined.
auto operator==(input_iterator_with_configurable_noexcept const &) noexcept(OperatorsNoexcept) -> bool
Equality operator; never defined.
A bidirectional iterator of T which declares that it could throw, used in some noexcept tests.
Definition vector.hpp:202
auto operator*() const -> reference
Dereference operator; never defined.
auto operator==(throwing_bidirectional_move_iterator_of_t const &) -> bool
Equality operator; never defined.
auto operator++() -> throwing_bidirectional_move_iterator_of_t &
Pre-increment operator; never defined.
auto operator!=(throwing_bidirectional_move_iterator_of_t const &) -> bool
Inequality operator; never defined.
auto operator++(int) -> throwing_bidirectional_move_iterator_of_t
Post-increment operator; never defined.
auto operator--(int) -> throwing_bidirectional_move_iterator_of_t
Post-decrement operator; never defined.
auto operator--() -> throwing_bidirectional_move_iterator_of_t &
Pre-decrement operator; never defined.
A type with a noexcept(false) conversion operator to T (doesn't actually throw, just declares it)
Definition vector.hpp:194
operator T() const noexcept(false)
Implicit conversion operator to T which declares that it might throw, though it doesn't actually.
Definition vector.hpp:198
Definition vector.hpp:61
constexpr auto operator()(T const &arg) -> bool
Definition vector.hpp:64
T const & value
Definition vector.hpp:66
constexpr equal_to_value(T const &input)
Definition vector.hpp:62
Definition external_vector.hpp:1707
throws_without_nullptr(T const &)
Definition vector.hpp:1948
throws_without_nullptr(T const &, std::nullptr_t) noexcept
Definition vector.hpp:1949