| // Copyright 2025 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <lib/stdcompat/inplace_vector.h> |
| |
| #include <algorithm> |
| #include <list> |
| #include <memory> |
| |
| #include "gtest.h" |
| |
| namespace { |
| struct Counter { |
| inline static int move_count = 0; |
| inline static int destruct_count = 0; |
| Counter() = default; |
| Counter(const Counter&) = default; |
| Counter(Counter&&) { ++move_count; } |
| ~Counter() { ++destruct_count; } |
| Counter& operator=(Counter&&) { |
| ++move_count; |
| return *this; |
| } |
| Counter& operator=(const Counter&) = default; |
| }; |
| |
| struct S { |
| int x; |
| S(int v) : x(v) {} |
| }; |
| |
| struct Tracker { |
| inline static int count = 0; |
| Tracker() { ++count; } |
| Tracker(const Tracker&) { ++count; } |
| ~Tracker() { --count; } |
| }; |
| |
| // Test safety violations: capacity overflow, out-of-range access, and death test scenarios. |
| TEST(InplaceVectorTest, SafetyViolationDeathTests) { |
| EXPECT_DEATH((cpp26::inplace_vector<int, 2>{1, 2, 3}), ""); |
| EXPECT_DEATH((cpp26::inplace_vector<int, 3>{1, 2, 3, 4, 5}), ""); |
| |
| cpp26::inplace_vector<int, 1> v; |
| v.push_back(1); |
| EXPECT_DEATH(v.push_back(2), ""); |
| |
| cpp26::inplace_vector<int, 1> v2; |
| v2.emplace_back(1); |
| EXPECT_DEATH(v2.emplace_back(2), ""); |
| |
| EXPECT_DEATH((cpp26::inplace_vector<int, 2>(5)), ""); |
| EXPECT_DEATH((cpp26::inplace_vector<int, 2>(3, 42)), ""); |
| |
| std::vector<int> source{1, 2, 3, 4, 5}; |
| EXPECT_DEATH((cpp26::inplace_vector<int, 3>(source.begin(), source.end())), ""); |
| EXPECT_DEATH((cpp26::inplace_vector<int, 3>(cpp23::from_range, source)), ""); |
| |
| cpp26::inplace_vector<int, 2> v3; |
| std::vector<int> source2{1, 2, 3, 4}; |
| EXPECT_DEATH(v3.assign(source2.begin(), source2.end()), ""); |
| EXPECT_DEATH(v3.assign(5, 42), ""); |
| EXPECT_DEATH(v3.assign({1, 2, 3, 4}), ""); |
| EXPECT_DEATH(v3.assign_range(source2), ""); |
| |
| cpp26::inplace_vector<int, 3> v4{1, 2}; |
| EXPECT_DEATH(v4.resize(5), ""); |
| EXPECT_DEATH(v4.resize(5, 42), ""); |
| |
| cpp26::inplace_vector<int, 3> v5{1, 2, 3}; |
| EXPECT_DEATH(v5.insert(v5.begin(), 42), ""); |
| EXPECT_DEATH(v5.insert(v5.begin(), 2, 42), ""); |
| std::vector<int> source3{4, 5}; |
| EXPECT_DEATH(v5.insert(v5.begin(), source3.begin(), source3.end()), ""); |
| EXPECT_DEATH(v5.insert(v5.begin(), {4, 5}), ""); |
| EXPECT_DEATH(v5.insert_range(v5.begin(), source3), ""); |
| EXPECT_DEATH(v5.emplace(v5.begin(), 42), ""); |
| |
| cpp26::inplace_vector<int, 3> v6{1, 2}; |
| std::vector<int> source4{3, 4, 5}; |
| EXPECT_DEATH(v6.append_range(source4), ""); |
| |
| auto test_assignment_overflow = []() { |
| [[maybe_unused]] cpp26::inplace_vector<int, 3> v_small; |
| cpp26::inplace_vector<int, 3> v_large{1, 2, 3, 4, 5}; |
| }; |
| EXPECT_DEATH(test_assignment_overflow(), ""); |
| |
| cpp26::inplace_vector<int, 2> v7{1}; |
| EXPECT_DEATH(v7.at(1), ""); |
| const auto& cv7 = v7; |
| EXPECT_DEATH(cv7.at(2), ""); |
| } |
| |
| // Test object lifecycle management: move operations, destruction counting, and complex types. |
| TEST(InplaceVectorTest, ObjectLifecycleManagement) { |
| Counter::move_count = 0; |
| Counter::destruct_count = 0; |
| |
| { |
| cpp26::inplace_vector<Counter, 3> v1; |
| v1.emplace_back(); |
| v1.emplace_back(); |
| v1.emplace_back(); |
| |
| cpp26::inplace_vector<Counter, 3> v2; |
| v2.emplace_back(); |
| v2.emplace_back(); |
| v2.emplace_back(); |
| |
| EXPECT_EQ(Counter::destruct_count, 0); |
| |
| int move_count_before = Counter::move_count; |
| int destruct_count_before = Counter::destruct_count; |
| |
| v2 = std::move(v1); |
| |
| EXPECT_EQ(Counter::move_count, move_count_before + 3); |
| EXPECT_GE(Counter::destruct_count, destruct_count_before + 3); |
| |
| EXPECT_TRUE(v1.empty()); |
| EXPECT_EQ(v2.size(), 3u); |
| } |
| |
| EXPECT_GT(Counter::destruct_count, 0); |
| |
| Tracker::count = 0; |
| |
| cpp26::inplace_vector<Tracker, 3> v3; |
| v3.emplace_back(); |
| v3.emplace_back(); |
| EXPECT_EQ(Tracker::count, 2); |
| v3.clear(); |
| EXPECT_EQ(Tracker::count, 0); |
| |
| { |
| cpp26::inplace_vector<Tracker, 3> v4; |
| v4.emplace_back(); |
| v4.emplace_back(); |
| v4.emplace_back(); |
| EXPECT_EQ(Tracker::count, 3); |
| } |
| |
| EXPECT_EQ(Tracker::count, 0); |
| } |
| |
| // Test basic vector operations and various constructor forms. |
| TEST(InplaceVectorTest, BasicOperationsAndConstruction) { |
| cpp26::inplace_vector<int, 4> v; |
| EXPECT_TRUE(v.empty()); |
| EXPECT_EQ(v.size(), 0u); |
| EXPECT_EQ(v.capacity(), 4u); |
| EXPECT_EQ(v.max_size(), 4u); |
| |
| v.push_back(1); |
| v.push_back(2); |
| v.push_back(3); |
| EXPECT_EQ(v.size(), 3u); |
| EXPECT_FALSE(v.empty()); |
| EXPECT_EQ(v[0], 1); |
| EXPECT_EQ(v[1], 2); |
| EXPECT_EQ(v[2], 3); |
| EXPECT_EQ(v.front(), 1); |
| EXPECT_EQ(v.back(), 3); |
| |
| v.pop_back(); |
| EXPECT_EQ(v.size(), 2u); |
| EXPECT_EQ(v.back(), 2); |
| |
| v.clear(); |
| EXPECT_TRUE(v.empty()); |
| v.push_back(5); |
| EXPECT_EQ(v.size(), 1u); |
| EXPECT_EQ(v[0], 5); |
| v.clear(); |
| |
| cpp26::inplace_vector<int, 4> v_init{4, 5, 6}; |
| EXPECT_EQ(v_init.size(), 3u); |
| EXPECT_EQ(v_init[0], 4); |
| EXPECT_EQ(v_init[1], 5); |
| EXPECT_EQ(v_init[2], 6); |
| |
| cpp26::inplace_vector<int, 4> v_copy(v_init); |
| EXPECT_EQ(v_copy.size(), 3u); |
| EXPECT_EQ(v_copy[1], 5); |
| |
| v = v_init; |
| EXPECT_EQ(v.size(), 3u); |
| EXPECT_EQ(v[2], 6); |
| |
| cpp26::inplace_vector<int, 5> v1(3); |
| EXPECT_EQ(v1.size(), 3u); |
| EXPECT_EQ(v1[0], 0); |
| EXPECT_EQ(v1[1], 0); |
| EXPECT_EQ(v1[2], 0); |
| |
| cpp26::inplace_vector<int, 5> v2(3, 42); |
| EXPECT_EQ(v2.size(), 3u); |
| EXPECT_EQ(v2[0], 42); |
| EXPECT_EQ(v2[1], 42); |
| EXPECT_EQ(v2[2], 42); |
| |
| std::vector<int> source{1, 2, 3}; |
| cpp26::inplace_vector<int, 4> v3(source.begin(), source.end()); |
| EXPECT_EQ(v3.size(), 3u); |
| EXPECT_EQ(v3[0], 1); |
| EXPECT_EQ(v3[1], 2); |
| EXPECT_EQ(v3[2], 3); |
| |
| std::vector<int> source2{7, 8, 9}; |
| cpp26::inplace_vector<int, 4> v4(cpp23::from_range, source2); |
| EXPECT_EQ(v4.size(), 3u); |
| EXPECT_EQ(v4[0], 7); |
| EXPECT_EQ(v4[1], 8); |
| EXPECT_EQ(v4[2], 9); |
| |
| cpp26::inplace_vector<S, 2> v5; |
| v5.emplace_back(42); |
| EXPECT_EQ(v5[0].x, 42); |
| |
| cpp26::inplace_vector<int, 3> v6{1, 2, 3}; |
| int sum = 0; |
| std::for_each(v6.begin(), v6.end(), [&](int x) { sum += x; }); |
| EXPECT_EQ(sum, 6); |
| std::reverse(v6.begin(), v6.end()); |
| EXPECT_EQ(v6[0], 3); |
| EXPECT_EQ(v6[2], 1); |
| } |
| |
| // Test iterator functionality: front/back/data access, reverse iterators, and validity. |
| TEST(InplaceVectorTest, IteratorFunctionality) { |
| cpp26::inplace_vector<int, 3> v{7, 8, 9}; |
| EXPECT_EQ(v.front(), 7); |
| EXPECT_EQ(v.back(), 9); |
| EXPECT_EQ(v.data()[1], 8); |
| int sum = 0; |
| for (auto it = v.begin(); it != v.end(); ++it) { |
| sum += *it; |
| } |
| EXPECT_EQ(sum, 24); |
| const auto& cv = v; |
| EXPECT_EQ(*(cv.cbegin()), 7); |
| EXPECT_EQ(*(cv.cend() - 1), 9); |
| EXPECT_EQ(cv.front(), 7); |
| EXPECT_EQ(cv.back(), 9); |
| |
| cpp26::inplace_vector<int, 2> v2; |
| v2.push_back(42); |
| EXPECT_EQ(v2.front(), 42); |
| EXPECT_EQ(v2.back(), 42); |
| |
| v2.push_back(99); |
| EXPECT_EQ(v2.front(), 42); |
| EXPECT_EQ(v2.back(), 99); |
| |
| cpp26::inplace_vector<int, 5> v3{1, 2, 3}; |
| auto rit = v3.rbegin(); |
| EXPECT_EQ(*rit, 3); |
| ++rit; |
| EXPECT_EQ(*rit, 2); |
| ++rit; |
| EXPECT_EQ(*rit, 1); |
| ++rit; |
| EXPECT_EQ(rit, v3.rend()); |
| |
| const auto& cv3 = v3; |
| auto crit = cv3.crbegin(); |
| EXPECT_EQ(*crit, 3); |
| EXPECT_EQ(cv3.crend() - cv3.crbegin(), 3); |
| |
| cpp26::inplace_vector<int, 5> v4{1, 2, 3}; |
| auto it = v4.begin() + 1; |
| EXPECT_EQ(*it, 2); |
| |
| v4.push_back(4); |
| EXPECT_EQ(*it, 2); |
| |
| v4.insert(v4.begin(), 0); |
| EXPECT_EQ(v4.size(), 5u); |
| } |
| |
| // Test move-only types like std::unique_ptr and move semantics. |
| TEST(InplaceVectorTest, MoveOnlyTypeAndMoveSemantics) { |
| cpp26::inplace_vector<std::unique_ptr<int>, 2> v; |
| v.push_back(std::make_unique<int>(42)); |
| v.emplace_back(new int(99)); |
| EXPECT_EQ(*v[0], 42); |
| EXPECT_EQ(*v[1], 99); |
| |
| cpp26::inplace_vector<std::unique_ptr<int>, 3> v1; |
| v1.emplace_back(std::make_unique<int>(42)); |
| v1.emplace_back(std::make_unique<int>(99)); |
| |
| auto original_size = v1.size(); |
| cpp26::inplace_vector<std::unique_ptr<int>, 3> v2(std::move(v1)); |
| EXPECT_EQ(v2.size(), original_size); |
| EXPECT_EQ(*v2[0], 42); |
| EXPECT_EQ(*v2[1], 99); |
| EXPECT_TRUE(v1.empty()); |
| |
| cpp26::inplace_vector<std::unique_ptr<int>, 3> v3; |
| v3.emplace_back(std::make_unique<int>(1)); |
| v3.emplace_back(std::make_unique<int>(2)); |
| |
| cpp26::inplace_vector<std::unique_ptr<int>, 3> v4; |
| v4.emplace_back(std::make_unique<int>(99)); |
| |
| v4 = std::move(v3); |
| EXPECT_EQ(v4.size(), 2u); |
| EXPECT_EQ(*v4[0], 1); |
| EXPECT_EQ(*v4[1], 2); |
| EXPECT_TRUE(v3.empty()); |
| |
| cpp26::inplace_vector<std::unique_ptr<int>, 2> v5(std::move(v)); |
| EXPECT_EQ(*v5[0], 42); |
| EXPECT_EQ(*v5[1], 99); |
| |
| cpp26::inplace_vector<std::unique_ptr<int>, 2> v6; |
| v6 = std::move(v5); |
| EXPECT_EQ(*v6[0], 42); |
| EXPECT_EQ(*v6[1], 99); |
| } |
| |
| // Test try_*, unchecked_*, and return value operations for insertion methods. |
| TEST(InplaceVectorTest, SafeAndUnsafeInsertionOperations) { |
| cpp26::inplace_vector<int, 3> v1; |
| auto* result1 = v1.try_push_back(42); |
| ASSERT_NE(result1, nullptr); |
| EXPECT_EQ(*result1, 42); |
| EXPECT_EQ(v1.size(), 1u); |
| |
| auto* result2 = v1.try_push_back(std::move(43)); |
| ASSERT_NE(result2, nullptr); |
| EXPECT_EQ(*result2, 43); |
| EXPECT_EQ(v1.size(), 2u); |
| |
| cpp26::inplace_vector<int, 1> v2; |
| v2.push_back(1); |
| auto* result3 = v2.try_push_back(2); |
| EXPECT_EQ(result3, nullptr); |
| EXPECT_EQ(v2.size(), 1u); |
| |
| cpp26::inplace_vector<S, 2> v3; |
| auto* result4 = v3.try_emplace_back(99); |
| ASSERT_NE(result4, nullptr); |
| EXPECT_EQ(result4->x, 99); |
| EXPECT_EQ(v3.size(), 1u); |
| |
| cpp26::inplace_vector<S, 1> v4; |
| v4.emplace_back(1); |
| auto* result5 = v4.try_emplace_back(2); |
| EXPECT_EQ(result5, nullptr); |
| EXPECT_EQ(v4.size(), 1u); |
| |
| cpp26::inplace_vector<int, 3> v5; |
| auto& ref1 = v5.unchecked_push_back(10); |
| EXPECT_EQ(ref1, 10); |
| EXPECT_EQ(v5.size(), 1u); |
| |
| auto& ref2 = v5.unchecked_push_back(std::move(20)); |
| EXPECT_EQ(ref2, 20); |
| EXPECT_EQ(v5.size(), 2u); |
| |
| cpp26::inplace_vector<S, 2> v6; |
| auto& ref3 = v6.unchecked_emplace_back(77); |
| EXPECT_EQ(ref3.x, 77); |
| EXPECT_EQ(v6.size(), 1u); |
| |
| cpp26::inplace_vector<int, 2> v7; |
| auto& ref4 = v7.push_back(5); |
| EXPECT_EQ(ref4, 5); |
| EXPECT_EQ(&ref4, &v7.back()); |
| |
| auto& ref5 = v7.push_back(std::move(10)); |
| EXPECT_EQ(ref5, 10); |
| EXPECT_EQ(&ref5, &v7.back()); |
| |
| cpp26::inplace_vector<S, 2> v8; |
| auto& ref6 = v8.emplace_back(33); |
| EXPECT_EQ(ref6.x, 33); |
| EXPECT_EQ(&ref6, &v8.back()); |
| } |
| |
| // Test comprehensive range operations: append_range, assign_range, and insert_range. |
| TEST(InplaceVectorTest, RangeOperations) { |
| cpp26::inplace_vector<int, 5> v{1, 2}; |
| std::vector<int> extra{3, 4}; |
| v.append_range(extra); |
| EXPECT_EQ(v.size(), 4u); |
| EXPECT_EQ(v[0], 1); |
| EXPECT_EQ(v[1], 2); |
| EXPECT_EQ(v[2], 3); |
| EXPECT_EQ(v[3], 4); |
| |
| cpp26::inplace_vector<int, 5> v1{1, 2}; |
| std::vector<int> empty_range; |
| v1.append_range(empty_range); |
| EXPECT_EQ(v1.size(), 2u); |
| EXPECT_EQ(v1[0], 1); |
| EXPECT_EQ(v1[1], 2); |
| |
| cpp26::inplace_vector<int, 5> v2; |
| std::vector<int> source{3, 4, 5}; |
| v2.append_range(source); |
| EXPECT_EQ(v2.size(), 3u); |
| EXPECT_EQ(v2[0], 3); |
| EXPECT_EQ(v2[1], 4); |
| EXPECT_EQ(v2[2], 5); |
| |
| std::list<int> list_source{6, 7}; |
| v2.append_range(list_source); |
| EXPECT_EQ(v2.size(), 5u); |
| EXPECT_EQ(v2[3], 6); |
| EXPECT_EQ(v2[4], 7); |
| |
| cpp26::inplace_vector<int, 5> v3{1, 2, 3}; |
| std::vector<int> assign_source{4, 5, 6}; |
| v3.assign_range(assign_source); |
| EXPECT_EQ(v3.size(), 3u); |
| EXPECT_EQ(v3[0], 4); |
| EXPECT_EQ(v3[1], 5); |
| EXPECT_EQ(v3[2], 6); |
| |
| cpp26::inplace_vector<int, 5> v4{1, 2, 3}; |
| v4.assign_range(empty_range); |
| EXPECT_EQ(v4.size(), 0u); |
| EXPECT_TRUE(v4.empty()); |
| |
| cpp26::inplace_vector<int, 6> v5{1, 4}; |
| std::vector<int> insert_source{2, 3}; |
| auto it = v5.insert_range(v5.begin() + 1, insert_source); |
| EXPECT_EQ(v5.size(), 4u); |
| EXPECT_EQ(v5[0], 1); |
| EXPECT_EQ(v5[1], 2); |
| EXPECT_EQ(v5[2], 3); |
| EXPECT_EQ(v5[3], 4); |
| EXPECT_EQ(it, v5.begin() + 1); |
| } |
| |
| // Test resize operations with and without default values, including edge cases. |
| TEST(InplaceVectorTest, ResizeOperations) { |
| cpp26::inplace_vector<int, 5> v{1, 2}; |
| v.resize(4); |
| EXPECT_EQ(v.size(), 4u); |
| EXPECT_EQ(v[0], 1); |
| EXPECT_EQ(v[1], 2); |
| EXPECT_EQ(v[2], 0); |
| EXPECT_EQ(v[3], 0); |
| |
| v.resize(2); |
| EXPECT_EQ(v.size(), 2u); |
| EXPECT_EQ(v[0], 1); |
| EXPECT_EQ(v[1], 2); |
| |
| v.resize(4, 99); |
| EXPECT_EQ(v.size(), 4u); |
| EXPECT_EQ(v[0], 1); |
| EXPECT_EQ(v[1], 2); |
| EXPECT_EQ(v[2], 99); |
| EXPECT_EQ(v[3], 99); |
| |
| cpp26::inplace_vector<int, 5> v1{1, 2, 3}; |
| v1.resize(3); |
| EXPECT_EQ(v1.size(), 3u); |
| EXPECT_EQ(v1[0], 1); |
| EXPECT_EQ(v1[1], 2); |
| EXPECT_EQ(v1[2], 3); |
| |
| v1.resize(3, 99); |
| EXPECT_EQ(v1.size(), 3u); |
| EXPECT_EQ(v1[0], 1); |
| EXPECT_EQ(v1[1], 2); |
| EXPECT_EQ(v1[2], 3); |
| |
| v1.resize(0); |
| EXPECT_EQ(v1.size(), 0u); |
| EXPECT_TRUE(v1.empty()); |
| |
| v1.resize(0, 42); |
| EXPECT_EQ(v1.size(), 0u); |
| EXPECT_TRUE(v1.empty()); |
| |
| v1.resize(2, 77); |
| EXPECT_EQ(v1.size(), 2u); |
| EXPECT_EQ(v1[0], 77); |
| EXPECT_EQ(v1[1], 77); |
| } |
| |
| // Test assign operations (iterators, count, initializer_list) - excluding ranges. |
| TEST(InplaceVectorTest, AssignOperations) { |
| cpp26::inplace_vector<int, 5> v1{1, 2, 3}; |
| std::vector<int> source{4, 5}; |
| v1.assign(source.begin(), source.end()); |
| EXPECT_EQ(v1.size(), 2u); |
| EXPECT_EQ(v1[0], 4); |
| EXPECT_EQ(v1[1], 5); |
| |
| cpp26::inplace_vector<int, 5> v2{1, 2, 3}; |
| v2.assign(2, 99); |
| EXPECT_EQ(v2.size(), 2u); |
| EXPECT_EQ(v2[0], 99); |
| EXPECT_EQ(v2[1], 99); |
| |
| cpp26::inplace_vector<int, 5> v3{1, 2, 3}; |
| v3.assign({7, 8, 9}); |
| EXPECT_EQ(v3.size(), 3u); |
| EXPECT_EQ(v3[0], 7); |
| EXPECT_EQ(v3[1], 8); |
| EXPECT_EQ(v3[2], 9); |
| |
| cpp26::inplace_vector<int, 5> v4{1, 2, 3}; |
| v4.assign(0, 42); |
| EXPECT_EQ(v4.size(), 0u); |
| EXPECT_TRUE(v4.empty()); |
| |
| cpp26::inplace_vector<int, 5> v5{1, 2, 3}; |
| v5.assign({}); |
| EXPECT_EQ(v5.size(), 0u); |
| EXPECT_TRUE(v5.empty()); |
| |
| std::vector<int> empty_source; |
| cpp26::inplace_vector<int, 5> v6{1, 2, 3}; |
| v6.assign(empty_source.begin(), empty_source.end()); |
| EXPECT_EQ(v6.size(), 0u); |
| EXPECT_TRUE(v6.empty()); |
| } |
| |
| // Test all insert operation variants. |
| TEST(InplaceVectorTest, InsertOperations) { |
| cpp26::inplace_vector<int, 6> v1{1, 4}; |
| auto it = v1.insert(v1.begin() + 1, 2); |
| EXPECT_EQ(v1.size(), 3u); |
| EXPECT_EQ(v1[0], 1); |
| EXPECT_EQ(v1[1], 2); |
| EXPECT_EQ(v1[2], 4); |
| EXPECT_EQ(it, v1.begin() + 1); |
| |
| cpp26::inplace_vector<std::unique_ptr<int>, 3> v2; |
| v2.emplace_back(std::make_unique<int>(1)); |
| v2.emplace_back(std::make_unique<int>(3)); |
| auto ptr = std::make_unique<int>(2); |
| auto it2 = v2.insert(v2.begin() + 1, std::move(ptr)); |
| EXPECT_EQ(v2.size(), 3u); |
| EXPECT_EQ(*v2[0], 1); |
| EXPECT_EQ(*v2[1], 2); |
| EXPECT_EQ(*v2[2], 3); |
| EXPECT_EQ(it2, v2.begin() + 1); |
| |
| cpp26::inplace_vector<int, 6> v3{1, 4}; |
| auto it3 = v3.insert(v3.begin() + 1, 2, 99); |
| EXPECT_EQ(v3.size(), 4u); |
| EXPECT_EQ(v3[0], 1); |
| EXPECT_EQ(v3[1], 99); |
| EXPECT_EQ(v3[2], 99); |
| EXPECT_EQ(v3[3], 4); |
| EXPECT_EQ(it3, v3.begin() + 1); |
| |
| cpp26::inplace_vector<int, 6> v4{1, 4}; |
| std::vector<int> source{2, 3}; |
| auto it4 = v4.insert(v4.begin() + 1, source.begin(), source.end()); |
| EXPECT_EQ(v4.size(), 4u); |
| EXPECT_EQ(v4[0], 1); |
| EXPECT_EQ(v4[1], 2); |
| EXPECT_EQ(v4[2], 3); |
| EXPECT_EQ(v4[3], 4); |
| EXPECT_EQ(it4, v4.begin() + 1); |
| |
| cpp26::inplace_vector<int, 6> v5{1, 4}; |
| auto it5 = v5.insert(v5.begin() + 1, {2, 3}); |
| EXPECT_EQ(v5.size(), 4u); |
| EXPECT_EQ(v5[0], 1); |
| EXPECT_EQ(v5[1], 2); |
| EXPECT_EQ(v5[2], 3); |
| EXPECT_EQ(v5[3], 4); |
| EXPECT_EQ(it5, v5.begin() + 1); |
| |
| cpp26::inplace_vector<S, 3> v6; |
| v6.emplace_back(1); |
| v6.emplace_back(3); |
| auto it6 = v6.emplace(v6.begin() + 1, 2); |
| EXPECT_EQ(v6.size(), 3u); |
| EXPECT_EQ(v6[0].x, 1); |
| EXPECT_EQ(v6[1].x, 2); |
| EXPECT_EQ(v6[2].x, 3); |
| EXPECT_EQ(it6, v6.begin() + 1); |
| } |
| |
| // Test erase operations (single element and range) including edge cases. |
| TEST(InplaceVectorTest, EraseOperations) { |
| cpp26::inplace_vector<int, 5> v1{1, 2, 3, 4}; |
| auto it = v1.erase(v1.begin() + 1); |
| EXPECT_EQ(v1.size(), 3u); |
| EXPECT_EQ(v1[0], 1); |
| EXPECT_EQ(v1[1], 3); |
| EXPECT_EQ(v1[2], 4); |
| EXPECT_EQ(it, v1.begin() + 1); |
| |
| cpp26::inplace_vector<int, 5> v2{1, 2, 3, 4, 5}; |
| auto it2 = v2.erase(v2.begin() + 1, v2.begin() + 3); |
| EXPECT_EQ(v2.size(), 3u); |
| EXPECT_EQ(v2[0], 1); |
| EXPECT_EQ(v2[1], 4); |
| EXPECT_EQ(v2[2], 5); |
| EXPECT_EQ(it2, v2.begin() + 1); |
| |
| cpp26::inplace_vector<int, 3> v3; |
| auto it3 = v3.erase(v3.begin()); |
| EXPECT_EQ(it3, v3.end()); |
| auto it4 = v3.erase(v3.begin(), v3.end()); |
| EXPECT_EQ(it4, v3.end()); |
| |
| cpp26::inplace_vector<int, 5> v4{1, 2, 3, 4, 5}; |
| auto it5 = v4.erase(v4.begin() + 2, v4.begin() + 2); |
| EXPECT_EQ(v4.size(), 5u); |
| EXPECT_EQ(it5, v4.end()); |
| |
| auto it6 = v4.erase(v4.begin(), v4.end()); |
| EXPECT_TRUE(v4.empty()); |
| EXPECT_EQ(it6, v4.end()); |
| |
| cpp26::inplace_vector<int, 5> v5{1, 2, 3, 4, 5}; |
| auto it7 = v5.erase(v5.end()); |
| EXPECT_EQ(it7, v5.end()); |
| EXPECT_EQ(v5.size(), 5u); |
| |
| v5.assign({1, 2, 3}); |
| auto it8 = v5.erase(v5.end(), v5.end()); |
| EXPECT_EQ(v5.size(), 3u); |
| EXPECT_EQ(it8, v5.end()); |
| } |
| |
| // Test swap operations (member function and global function) with different sizes. |
| TEST(InplaceVectorTest, SwapOperations) { |
| cpp26::inplace_vector<int, 3> v1{1, 2}; |
| cpp26::inplace_vector<int, 3> v2{3, 4, 5}; |
| |
| v1.swap(v2); |
| |
| EXPECT_EQ(v1.size(), 3u); |
| EXPECT_EQ(v1[0], 3); |
| EXPECT_EQ(v1[1], 4); |
| EXPECT_EQ(v1[2], 5); |
| |
| EXPECT_EQ(v2.size(), 2u); |
| EXPECT_EQ(v2[0], 1); |
| EXPECT_EQ(v2[1], 2); |
| |
| cpp26::inplace_vector<int, 3> v3{1, 2}; |
| cpp26::inplace_vector<int, 3> v4{3, 4, 5}; |
| |
| using std::swap; |
| swap(v3, v4); |
| |
| EXPECT_EQ(v3.size(), 3u); |
| EXPECT_EQ(v3[0], 3); |
| EXPECT_EQ(v3[1], 4); |
| EXPECT_EQ(v3[2], 5); |
| |
| EXPECT_EQ(v4.size(), 2u); |
| EXPECT_EQ(v4[0], 1); |
| EXPECT_EQ(v4[1], 2); |
| |
| cpp26::inplace_vector<int, 5> v5{1, 2, 3, 4}; |
| cpp26::inplace_vector<int, 5> v6{5}; |
| |
| v5.swap(v6); |
| |
| EXPECT_EQ(v5.size(), 1u); |
| EXPECT_EQ(v5[0], 5); |
| |
| EXPECT_EQ(v6.size(), 4u); |
| EXPECT_EQ(v6[0], 1); |
| EXPECT_EQ(v6[1], 2); |
| EXPECT_EQ(v6[2], 3); |
| EXPECT_EQ(v6[3], 4); |
| |
| cpp26::inplace_vector<int, 0> v7; |
| cpp26::inplace_vector<int, 0> v8; |
| |
| v7.swap(v8); |
| EXPECT_EQ(v7.size(), 0u); |
| EXPECT_EQ(v8.size(), 0u); |
| |
| using std::swap; |
| swap(v7, v8); |
| EXPECT_EQ(v7.size(), 0u); |
| EXPECT_EQ(v8.size(), 0u); |
| } |
| |
| // Test comparison operators (==, !=, <, <=, >, >=, <=>). |
| TEST(InplaceVectorTest, ComparisonOperators) { |
| cpp26::inplace_vector<int, 3> v1{1, 2, 3}; |
| cpp26::inplace_vector<int, 3> v2{1, 2, 3}; |
| cpp26::inplace_vector<int, 3> v3{1, 2, 4}; |
| cpp26::inplace_vector<int, 3> v4{1, 2}; |
| |
| EXPECT_TRUE(v1 == v2); |
| EXPECT_FALSE(v1 != v2); |
| EXPECT_FALSE(v1 == v3); |
| EXPECT_TRUE(v1 != v3); |
| EXPECT_FALSE(v1 == v4); |
| |
| cpp26::inplace_vector<int, 5> v5{1, 2}; |
| cpp26::inplace_vector<int, 5> v6{1, 2, 3}; |
| |
| EXPECT_FALSE(v5 == v6); |
| EXPECT_TRUE(v5 != v6); |
| |
| #if __cpp_lib_three_way_comparison >= 201907L |
| EXPECT_TRUE((v1 <=> v2) == std::strong_ordering::equal); |
| EXPECT_TRUE((v1 <=> v3) == std::strong_ordering::less); |
| EXPECT_TRUE((v3 <=> v1) == std::strong_ordering::greater); |
| EXPECT_TRUE((v5 <=> v6) == std::strong_ordering::less); |
| #else |
| EXPECT_TRUE(v1 < v3); |
| EXPECT_FALSE(v3 < v1); |
| EXPECT_TRUE(v1 <= v2); |
| EXPECT_TRUE(v1 <= v3); |
| EXPECT_FALSE(v3 <= v1); |
| EXPECT_TRUE(v3 > v1); |
| EXPECT_FALSE(v1 > v3); |
| EXPECT_TRUE(v2 >= v1); |
| EXPECT_TRUE(v3 >= v1); |
| EXPECT_FALSE(v1 >= v3); |
| EXPECT_TRUE(v5 < v6); |
| EXPECT_FALSE(v5 > v6); |
| EXPECT_TRUE(v5 <= v6); |
| EXPECT_FALSE(v5 >= v6); |
| #endif |
| } |
| |
| // Test global erase and erase_if algorithms. |
| TEST(InplaceVectorTest, GlobalEraseOperations) { |
| cpp26::inplace_vector<int, 5> v1{1, 2, 2, 3, 2}; |
| auto erase_count = stdcompat::erase(v1, 2); |
| EXPECT_EQ(erase_count, 3u); |
| EXPECT_EQ(v1.size(), 2u); |
| EXPECT_EQ(v1[0], 1); |
| EXPECT_EQ(v1[1], 3); |
| |
| cpp26::inplace_vector<int, 5> v2{1, 2, 3, 4, 5}; |
| auto erase_if_count = stdcompat::erase_if(v2, [](int x) { return x % 2 == 0; }); |
| EXPECT_EQ(erase_if_count, 2u); |
| EXPECT_EQ(v2.size(), 3u); |
| EXPECT_EQ(v2[0], 1); |
| EXPECT_EQ(v2[1], 3); |
| EXPECT_EQ(v2[2], 5); |
| |
| cpp26::inplace_vector<int, 5> v3{1, 3, 5}; |
| auto no_erase_count = stdcompat::erase(v3, 2); |
| EXPECT_EQ(no_erase_count, 0u); |
| EXPECT_EQ(v3.size(), 3u); |
| |
| auto no_erase_if_count = stdcompat::erase_if(v3, [](int x) { return x > 10; }); |
| EXPECT_EQ(no_erase_if_count, 0u); |
| EXPECT_EQ(v3.size(), 3u); |
| } |
| |
| // Test container management: reserve, capacity, max_size, and self-operation safety. |
| TEST(InplaceVectorTest, ContainerManagement) { |
| cpp26::inplace_vector<int, 5> v{1, 2, 3}; |
| |
| v.reserve(5); |
| EXPECT_EQ(v.size(), 3u); |
| |
| v.shrink_to_fit(); |
| EXPECT_EQ(v.size(), 3u); |
| |
| EXPECT_DEATH(v.reserve(10), ""); |
| |
| EXPECT_EQ(v.max_size(), 5u); |
| EXPECT_EQ(v.capacity(), 5u); |
| |
| cpp26::inplace_vector<int, 3> v2{1, 2, 3}; |
| auto* ptr = &v2; |
| |
| v2 = *ptr; |
| EXPECT_EQ(v2.size(), 3u); |
| EXPECT_EQ(v2[0], 1); |
| EXPECT_EQ(v2[1], 2); |
| EXPECT_EQ(v2[2], 3); |
| |
| v2 = std::move(*ptr); |
| EXPECT_EQ(v2.size(), 3u); |
| EXPECT_EQ(v2[0], 1); |
| EXPECT_EQ(v2[1], 2); |
| EXPECT_EQ(v2[2], 3); |
| |
| v2.swap(v2); |
| EXPECT_EQ(v2.size(), 3u); |
| EXPECT_EQ(v2[0], 1); |
| EXPECT_EQ(v2[1], 2); |
| EXPECT_EQ(v2[2], 3); |
| } |
| |
| // Test type aliases functionality, constexpr operations, and move semantics through runtime |
| // behavior. |
| TEST(InplaceVectorTest, TypeAliasesAndRuntimeBehavior) { |
| constexpr auto capacity_5 = cpp26::inplace_vector<int, 5>::capacity(); |
| EXPECT_EQ(capacity_5, 5u); |
| constexpr auto max_size_10 = cpp26::inplace_vector<int, 10>::max_size(); |
| EXPECT_EQ(max_size_10, 10u); |
| |
| cpp26::inplace_vector<int, 3> v; |
| EXPECT_TRUE(v.empty()); |
| EXPECT_EQ(v.size(), 0u); |
| EXPECT_EQ(v.capacity(), 3u); |
| EXPECT_EQ(v.max_size(), 3u); |
| |
| v.push_back(1); |
| v.push_back(2); |
| EXPECT_EQ(v.size(), 2u); |
| EXPECT_EQ(v[0], 1); |
| EXPECT_EQ(v[1], 2); |
| |
| using Vec = cpp26::inplace_vector<int, 5>; |
| Vec v3{1, 2, 3}; |
| |
| Vec::value_type val = 42; |
| v3.push_back(val); |
| EXPECT_EQ(v3.back(), 42); |
| |
| Vec::size_type expected_size = 4; |
| EXPECT_EQ(v3.size(), expected_size); |
| EXPECT_TRUE(v3.size() < Vec::size_type{10}); |
| |
| Vec::difference_type distance = v3.end() - v3.begin(); |
| EXPECT_EQ(distance, 4); |
| EXPECT_TRUE(distance > Vec::difference_type{0}); |
| |
| Vec::reference ref = v3[0]; |
| EXPECT_EQ(ref, 1); |
| ref = 100; |
| EXPECT_EQ(v3[0], 100); |
| |
| const Vec& cv3 = v3; |
| Vec::const_reference const_ref = cv3[0]; |
| EXPECT_EQ(const_ref, 100); |
| |
| Vec::pointer ptr = v3.data(); |
| EXPECT_EQ(*ptr, 100); |
| *ptr = 200; |
| EXPECT_EQ(v3[0], 200); |
| |
| Vec::const_pointer const_ptr = cv3.data(); |
| EXPECT_EQ(*const_ptr, 200); |
| |
| constexpr auto capacity_7 = cpp26::inplace_vector<int, 7>::capacity(); |
| EXPECT_EQ(capacity_7, 7u); |
| constexpr auto max_size_7 = cpp26::inplace_vector<int, 7>::max_size(); |
| EXPECT_EQ(max_size_7, 7u); |
| |
| EXPECT_EQ(v3.at(0), 200); |
| EXPECT_EQ(v3.at(1), 2); |
| EXPECT_EQ(v3.at(2), 3); |
| EXPECT_EQ(v3.at(3), 42); |
| |
| const Vec& cv3_at = v3; |
| EXPECT_EQ(cv3_at.at(0), 200); |
| EXPECT_EQ(cv3_at.at(1), 2); |
| EXPECT_EQ(cv3_at.at(2), 3); |
| EXPECT_EQ(cv3_at.at(3), 42); |
| |
| auto it = v3.begin(); |
| EXPECT_EQ(*it, 200); |
| *it = 300; |
| EXPECT_EQ(v3[0], 300); |
| |
| auto cit = cv3_at.cbegin(); |
| EXPECT_EQ(*cit, 300); |
| |
| auto rit = v3.rbegin(); |
| EXPECT_EQ(*rit, 42); |
| |
| auto crit = cv3_at.crbegin(); |
| EXPECT_EQ(*crit, 42); |
| |
| EXPECT_EQ(std::distance(v3.begin(), v3.end()), 4); |
| EXPECT_EQ(std::distance(v3.rbegin(), v3.rend()), 4); |
| |
| cpp26::inplace_vector<int, 2> safe_test; |
| auto* result = safe_test.try_push_back(1); |
| EXPECT_NE(result, nullptr); |
| EXPECT_EQ(*result, 1); |
| |
| auto* emplace_result = safe_test.try_emplace_back(2); |
| EXPECT_NE(emplace_result, nullptr); |
| EXPECT_EQ(*emplace_result, 2); |
| |
| cpp26::inplace_vector<int, 3> move_test1{1, 2, 3}; |
| cpp26::inplace_vector<int, 3> move_test2{std::move(move_test1)}; |
| EXPECT_EQ(move_test2.size(), 3u); |
| EXPECT_EQ(move_test2[0], 1); |
| EXPECT_EQ(move_test2[1], 2); |
| EXPECT_EQ(move_test2[2], 3); |
| EXPECT_TRUE(move_test1.empty()); |
| |
| cpp26::inplace_vector<int, 3> move_test3; |
| move_test3 = std::move(move_test2); |
| EXPECT_EQ(move_test3.size(), 3u); |
| EXPECT_EQ(move_test3[0], 1); |
| EXPECT_EQ(move_test3[1], 2); |
| EXPECT_EQ(move_test3[2], 3); |
| EXPECT_TRUE(move_test2.empty()); |
| } |
| |
| // Test constructor SFINAE, template constraints, and from_range variants. |
| TEST(InplaceVectorTest, ConstructorSFINAE) { |
| cpp26::inplace_vector<int, 5> v1(3, 42); |
| EXPECT_EQ(v1.size(), 3u); |
| EXPECT_EQ(v1[0], 42); |
| EXPECT_EQ(v1[1], 42); |
| EXPECT_EQ(v1[2], 42); |
| |
| std::vector<int> source{1, 2, 3}; |
| cpp26::inplace_vector<int, 5> v2(source.begin(), source.end()); |
| EXPECT_EQ(v2.size(), 3u); |
| EXPECT_EQ(v2[0], 1); |
| EXPECT_EQ(v2[1], 2); |
| EXPECT_EQ(v2[2], 3); |
| |
| std::vector<int> source1{1, 2, 3}; |
| cpp26::inplace_vector<int, 5> v3(cpp23::from_range, source1); |
| EXPECT_EQ(v3.size(), 3u); |
| EXPECT_EQ(v3[0], 1); |
| EXPECT_EQ(v3[1], 2); |
| EXPECT_EQ(v3[2], 3); |
| |
| int source2[] = {4, 5, 6, 7}; |
| cpp26::inplace_vector<int, 6> v4(cpp23::from_range, source2); |
| EXPECT_EQ(v4.size(), 4u); |
| EXPECT_EQ(v4[0], 4); |
| EXPECT_EQ(v4[1], 5); |
| EXPECT_EQ(v4[2], 6); |
| EXPECT_EQ(v4[3], 7); |
| |
| std::list<int> source3{8, 9}; |
| cpp26::inplace_vector<int, 4> v5(cpp23::from_range, source3); |
| EXPECT_EQ(v5.size(), 2u); |
| EXPECT_EQ(v5[0], 8); |
| EXPECT_EQ(v5[1], 9); |
| |
| std::vector<int> empty_source; |
| cpp26::inplace_vector<int, 3> v6(cpp23::from_range, empty_source); |
| EXPECT_EQ(v6.size(), 0u); |
| EXPECT_TRUE(v6.empty()); |
| } |
| |
| // Test batch insert implementation edge cases and iterator optimization. |
| TEST(InplaceVectorTest, BatchInsertEdgeCases) { |
| cpp26::inplace_vector<int, 5> v1{1, 3}; |
| std::vector<int> empty_range; |
| auto it1 = v1.insert(v1.begin() + 1, empty_range.begin(), empty_range.end()); |
| EXPECT_EQ(v1.size(), 2u); |
| EXPECT_EQ(v1[0], 1); |
| EXPECT_EQ(v1[1], 3); |
| EXPECT_EQ(it1, v1.begin() + 1); |
| |
| auto it2 = v1.insert(v1.begin() + 1, 0, 42); |
| EXPECT_EQ(v1.size(), 2u); |
| EXPECT_EQ(v1[0], 1); |
| EXPECT_EQ(v1[1], 3); |
| EXPECT_EQ(it2, v1.begin() + 1); |
| |
| auto it3 = v1.insert(v1.end(), 2, 99); |
| EXPECT_EQ(v1.size(), 4u); |
| EXPECT_EQ(v1[0], 1); |
| EXPECT_EQ(v1[1], 3); |
| EXPECT_EQ(v1[2], 99); |
| EXPECT_EQ(v1[3], 99); |
| EXPECT_EQ(it3, v1.begin() + 2); |
| |
| cpp26::inplace_vector<int, 5> v2{3, 4}; |
| auto it4 = v2.insert(v2.begin(), 2, 1); |
| EXPECT_EQ(v2.size(), 4u); |
| EXPECT_EQ(v2[0], 1); |
| EXPECT_EQ(v2[1], 1); |
| EXPECT_EQ(v2[2], 3); |
| EXPECT_EQ(v2[3], 4); |
| EXPECT_EQ(it4, v2.begin()); |
| |
| std::vector<int> source{1, 2, 3}; |
| cpp26::inplace_vector<int, 6> v3{0, 4}; |
| auto it5 = v3.insert(v3.begin() + 1, source.begin(), source.end()); |
| EXPECT_EQ(v3.size(), 5u); |
| EXPECT_EQ(v3[0], 0); |
| EXPECT_EQ(v3[1], 1); |
| EXPECT_EQ(v3[2], 2); |
| EXPECT_EQ(v3[3], 3); |
| EXPECT_EQ(v3[4], 4); |
| EXPECT_EQ(it5, v3.begin() + 1); |
| |
| std::list<int> list_source{5, 6, 7}; |
| cpp26::inplace_vector<int, 6> v4{0, 8}; |
| auto it6 = v4.insert(v4.begin() + 1, list_source.begin(), list_source.end()); |
| EXPECT_EQ(v4.size(), 5u); |
| EXPECT_EQ(v4[0], 0); |
| EXPECT_EQ(v4[1], 5); |
| EXPECT_EQ(v4[2], 6); |
| EXPECT_EQ(v4[3], 7); |
| EXPECT_EQ(v4[4], 8); |
| EXPECT_EQ(it6, v4.begin() + 1); |
| } |
| |
| // Test zero-capacity edge cases more thoroughly. |
| TEST(InplaceVectorTest, ZeroCapacityEdgeCases) { |
| cpp26::inplace_vector<int, 0> v; |
| |
| EXPECT_EQ(v.size(), 0u); |
| EXPECT_EQ(v.capacity(), 0u); |
| EXPECT_EQ(v.max_size(), 0u); |
| EXPECT_TRUE(v.empty()); |
| EXPECT_TRUE(v.size() == v.capacity()); |
| |
| EXPECT_DEATH(v.push_back(1), ""); |
| |
| EXPECT_EQ(v.begin(), v.end()); |
| EXPECT_EQ(v.cbegin(), v.cend()); |
| EXPECT_EQ(v.rbegin(), v.rend()); |
| EXPECT_EQ(v.crbegin(), v.crend()); |
| |
| v.resize(0); |
| EXPECT_EQ(v.size(), 0u); |
| |
| v.clear(); |
| EXPECT_EQ(v.size(), 0u); |
| |
| v.reserve(0); |
| EXPECT_EQ(v.capacity(), 0u); |
| |
| v.shrink_to_fit(); |
| EXPECT_EQ(v.capacity(), 0u); |
| |
| EXPECT_NE(v.data(), nullptr); |
| |
| cpp26::inplace_vector<int, 0> v2(v); |
| EXPECT_EQ(v2.size(), 0u); |
| |
| cpp26::inplace_vector<int, 0> v3; |
| v3 = v; |
| EXPECT_EQ(v3.size(), 0u); |
| |
| cpp26::inplace_vector<int, 0> v4(std::move(v)); |
| EXPECT_EQ(v4.size(), 0u); |
| EXPECT_EQ(v.size(), 0u); |
| |
| cpp26::inplace_vector<int, 0> v5; |
| v5 = std::move(v4); |
| EXPECT_EQ(v5.size(), 0u); |
| |
| v.swap(v2); |
| EXPECT_EQ(v.size(), 0u); |
| EXPECT_EQ(v2.size(), 0u); |
| |
| EXPECT_TRUE(v == v2); |
| EXPECT_FALSE(v != v2); |
| |
| std::vector<int> empty_source; |
| auto it1 = v.insert(v.begin(), empty_source.begin(), empty_source.end()); |
| EXPECT_EQ(it1, v.begin()); |
| EXPECT_EQ(v.size(), 0u); |
| |
| auto it2 = v.insert(v.begin(), 0, 42); |
| EXPECT_EQ(it2, v.begin()); |
| EXPECT_EQ(v.size(), 0u); |
| |
| auto it3 = v.insert(v.begin(), {}); |
| EXPECT_EQ(it3, v.begin()); |
| EXPECT_EQ(v.size(), 0u); |
| } |
| |
| TEST(InplaceVectorTest, ConstructionIsConstexprForTrivialTypes) { |
| constexpr cpp26::inplace_vector<int, 5> kEmptyVector; |
| EXPECT_TRUE(kEmptyVector.empty()); |
| |
| constexpr cpp26::inplace_vector<int, 5> kVectorFromInitializerList{1, 2, 3}; |
| EXPECT_EQ(kVectorFromInitializerList.size(), 3u); |
| EXPECT_THAT(kVectorFromInitializerList, ::testing::ElementsAre(1, 2, 3)); |
| |
| constexpr cpp26::inplace_vector<int, 5> kCopyConstructedVector(kVectorFromInitializerList); |
| EXPECT_EQ(kCopyConstructedVector.size(), 3u); |
| EXPECT_THAT(kCopyConstructedVector, ::testing::ElementsAre(1, 2, 3)); |
| |
| constexpr cpp26::inplace_vector<int, 5> kCopyAssignedVector = kVectorFromInitializerList; |
| EXPECT_EQ(kCopyAssignedVector.size(), 3u); |
| EXPECT_THAT(kCopyAssignedVector, ::testing::ElementsAre(1, 2, 3)); |
| } |
| |
| } // namespace |