diff options
Diffstat (limited to 'abseil-cpp/absl/container/inlined_vector_test.cc')
-rw-r--r-- | abseil-cpp/absl/container/inlined_vector_test.cc | 763 |
1 files changed, 539 insertions, 224 deletions
diff --git a/abseil-cpp/absl/container/inlined_vector_test.cc b/abseil-cpp/absl/container/inlined_vector_test.cc index 415c60d..b9a79f5 100644 --- a/abseil-cpp/absl/container/inlined_vector_test.cc +++ b/abseil-cpp/absl/container/inlined_vector_test.cc @@ -15,25 +15,28 @@ #include "absl/container/inlined_vector.h" #include <algorithm> +#include <cstddef> #include <forward_list> +#include <iterator> #include <list> #include <memory> #include <scoped_allocator> #include <sstream> #include <stdexcept> #include <string> +#include <utility> #include <vector> #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/base/attributes.h" #include "absl/base/internal/exception_testing.h" -#include "absl/base/internal/raw_logging.h" #include "absl/base/macros.h" #include "absl/base/options.h" #include "absl/container/internal/counting_allocator.h" #include "absl/container/internal/test_instance_tracker.h" #include "absl/hash/hash_testing.h" +#include "absl/log/check.h" #include "absl/memory/memory.h" #include "absl/strings/str_cat.h" @@ -49,14 +52,13 @@ using testing::ElementsAre; using testing::ElementsAreArray; using testing::Eq; using testing::Gt; +using testing::Pointee; +using testing::Pointwise; using testing::PrintToString; +using testing::SizeIs; using IntVec = absl::InlinedVector<int, 8>; -MATCHER_P(SizeIs, n, "") { - return testing::ExplainMatchResult(n, arg.size(), result_listener); -} - MATCHER_P(CapacityIs, n, "") { return testing::ExplainMatchResult(n, arg.capacity(), result_listener); } @@ -101,13 +103,13 @@ class RefCounted { } void Ref() const { - ABSL_RAW_CHECK(count_ != nullptr, ""); + CHECK_NE(count_, nullptr); ++(*count_); } void Unref() const { --(*count_); - ABSL_RAW_CHECK(*count_ >= 0, ""); + CHECK_GE(*count_, 0); } int value_; @@ -126,20 +128,20 @@ using DynamicVec = absl::InlinedVector<Dynamic, 8>; // Append 0..len-1 to *v template <typename Container> -static void Fill(Container* v, int len, int offset = 0) { - for (int i = 0; i < len; i++) { - v->push_back(i + offset); +static void Fill(Container* v, size_t len, int offset = 0) { + for (size_t i = 0; i < len; i++) { + v->push_back(static_cast<int>(i) + offset); } } -static IntVec Fill(int len, int offset = 0) { +static IntVec Fill(size_t len, int offset = 0) { IntVec v; Fill(&v, len, offset); return v; } TEST(IntVec, SimpleOps) { - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { IntVec v; const IntVec& cv = v; // const alias @@ -147,42 +149,42 @@ TEST(IntVec, SimpleOps) { EXPECT_EQ(len, v.size()); EXPECT_LE(len, v.capacity()); - for (int i = 0; i < len; i++) { - EXPECT_EQ(i, v[i]); - EXPECT_EQ(i, v.at(i)); + for (size_t i = 0; i < len; i++) { + EXPECT_EQ(static_cast<int>(i), v[i]); + EXPECT_EQ(static_cast<int>(i), v.at(i)); } EXPECT_EQ(v.begin(), v.data()); EXPECT_EQ(cv.begin(), cv.data()); - int counter = 0; + size_t counter = 0; for (IntVec::iterator iter = v.begin(); iter != v.end(); ++iter) { - EXPECT_EQ(counter, *iter); + EXPECT_EQ(static_cast<int>(counter), *iter); counter++; } EXPECT_EQ(counter, len); counter = 0; for (IntVec::const_iterator iter = v.begin(); iter != v.end(); ++iter) { - EXPECT_EQ(counter, *iter); + EXPECT_EQ(static_cast<int>(counter), *iter); counter++; } EXPECT_EQ(counter, len); counter = 0; for (IntVec::const_iterator iter = v.cbegin(); iter != v.cend(); ++iter) { - EXPECT_EQ(counter, *iter); + EXPECT_EQ(static_cast<int>(counter), *iter); counter++; } EXPECT_EQ(counter, len); if (len > 0) { EXPECT_EQ(0, v.front()); - EXPECT_EQ(len - 1, v.back()); + EXPECT_EQ(static_cast<int>(len - 1), v.back()); v.pop_back(); EXPECT_EQ(len - 1, v.size()); - for (int i = 0; i < v.size(); ++i) { - EXPECT_EQ(i, v[i]); - EXPECT_EQ(i, v.at(i)); + for (size_t i = 0; i < v.size(); ++i) { + EXPECT_EQ(static_cast<int>(i), v[i]); + EXPECT_EQ(static_cast<int>(i), v.at(i)); } } } @@ -191,7 +193,7 @@ TEST(IntVec, SimpleOps) { TEST(IntVec, PopBackNoOverflow) { IntVec v = {1}; v.pop_back(); - EXPECT_EQ(v.size(), 0); + EXPECT_EQ(v.size(), 0u); } TEST(IntVec, AtThrows) { @@ -202,47 +204,47 @@ TEST(IntVec, AtThrows) { } TEST(IntVec, ReverseIterator) { - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { IntVec v; Fill(&v, len); - int counter = len; + size_t counter = len; for (IntVec::reverse_iterator iter = v.rbegin(); iter != v.rend(); ++iter) { counter--; - EXPECT_EQ(counter, *iter); + EXPECT_EQ(static_cast<int>(counter), *iter); } - EXPECT_EQ(counter, 0); + EXPECT_EQ(counter, 0u); counter = len; for (IntVec::const_reverse_iterator iter = v.rbegin(); iter != v.rend(); ++iter) { counter--; - EXPECT_EQ(counter, *iter); + EXPECT_EQ(static_cast<int>(counter), *iter); } - EXPECT_EQ(counter, 0); + EXPECT_EQ(counter, 0u); counter = len; for (IntVec::const_reverse_iterator iter = v.crbegin(); iter != v.crend(); ++iter) { counter--; - EXPECT_EQ(counter, *iter); + EXPECT_EQ(static_cast<int>(counter), *iter); } - EXPECT_EQ(counter, 0); + EXPECT_EQ(counter, 0u); } } TEST(IntVec, Erase) { - for (int len = 1; len < 20; len++) { - for (int i = 0; i < len; ++i) { + for (size_t len = 1; len < 20; len++) { + for (size_t i = 0; i < len; ++i) { IntVec v; Fill(&v, len); v.erase(v.begin() + i); EXPECT_EQ(len - 1, v.size()); - for (int j = 0; j < i; ++j) { - EXPECT_EQ(j, v[j]); + for (size_t j = 0; j < i; ++j) { + EXPECT_EQ(static_cast<int>(j), v[j]); } - for (int j = i; j < len - 1; ++j) { - EXPECT_EQ(j + 1, v[j]); + for (size_t j = i; j < len - 1; ++j) { + EXPECT_EQ(static_cast<int>(j + 1), v[j]); } } } @@ -254,51 +256,95 @@ TEST(IntVec, Hardened) { EXPECT_EQ(v[9], 9); #if !defined(NDEBUG) || ABSL_OPTION_HARDENED EXPECT_DEATH_IF_SUPPORTED(v[10], ""); - EXPECT_DEATH_IF_SUPPORTED(v[-1], ""); + EXPECT_DEATH_IF_SUPPORTED(v[static_cast<size_t>(-1)], ""); + EXPECT_DEATH_IF_SUPPORTED(v.resize(v.max_size() + 1), ""); #endif } +// Move construction of a container of unique pointers should work fine, with no +// leaks, despite the fact that unique pointers are trivially relocatable but +// not trivially destructible. +TEST(UniquePtr, MoveConstruct) { + for (size_t size = 0; size < 16; ++size) { + SCOPED_TRACE(size); + + absl::InlinedVector<std::unique_ptr<size_t>, 2> a; + for (size_t i = 0; i < size; ++i) { + a.push_back(std::make_unique<size_t>(i)); + } + + absl::InlinedVector<std::unique_ptr<size_t>, 2> b(std::move(a)); + + ASSERT_THAT(b, SizeIs(size)); + for (size_t i = 0; i < size; ++i) { + ASSERT_THAT(b[i], Pointee(i)); + } + } +} + +// Move assignment of a container of unique pointers should work fine, with no +// leaks, despite the fact that unique pointers are trivially relocatable but +// not trivially destructible. +TEST(UniquePtr, MoveAssign) { + for (size_t size = 0; size < 16; ++size) { + SCOPED_TRACE(size); + + absl::InlinedVector<std::unique_ptr<size_t>, 2> a; + for (size_t i = 0; i < size; ++i) { + a.push_back(std::make_unique<size_t>(i)); + } + + absl::InlinedVector<std::unique_ptr<size_t>, 2> b; + b = std::move(a); + + ASSERT_THAT(b, SizeIs(size)); + for (size_t i = 0; i < size; ++i) { + ASSERT_THAT(b[i], Pointee(i)); + } + } +} + // At the end of this test loop, the elements between [erase_begin, erase_end) // should have reference counts == 0, and all others elements should have // reference counts == 1. TEST(RefCountedVec, EraseBeginEnd) { - for (int len = 1; len < 20; ++len) { - for (int erase_begin = 0; erase_begin < len; ++erase_begin) { - for (int erase_end = erase_begin; erase_end <= len; ++erase_end) { + for (size_t len = 1; len < 20; ++len) { + for (size_t erase_begin = 0; erase_begin < len; ++erase_begin) { + for (size_t erase_end = erase_begin; erase_end <= len; ++erase_end) { std::vector<int> counts(len, 0); RefCountedVec v; - for (int i = 0; i < len; ++i) { - v.push_back(RefCounted(i, &counts[i])); + for (size_t i = 0; i < len; ++i) { + v.push_back(RefCounted(static_cast<int>(i), &counts[i])); } - int erase_len = erase_end - erase_begin; + size_t erase_len = erase_end - erase_begin; v.erase(v.begin() + erase_begin, v.begin() + erase_end); EXPECT_EQ(len - erase_len, v.size()); // Check the elements before the first element erased. - for (int i = 0; i < erase_begin; ++i) { - EXPECT_EQ(i, v[i].value_); + for (size_t i = 0; i < erase_begin; ++i) { + EXPECT_EQ(static_cast<int>(i), v[i].value_); } // Check the elements after the first element erased. - for (int i = erase_begin; i < v.size(); ++i) { - EXPECT_EQ(i + erase_len, v[i].value_); + for (size_t i = erase_begin; i < v.size(); ++i) { + EXPECT_EQ(static_cast<int>(i + erase_len), v[i].value_); } // Check that the elements at the beginning are preserved. - for (int i = 0; i < erase_begin; ++i) { + for (size_t i = 0; i < erase_begin; ++i) { EXPECT_EQ(1, counts[i]); } // Check that the erased elements are destroyed - for (int i = erase_begin; i < erase_end; ++i) { + for (size_t i = erase_begin; i < erase_end; ++i) { EXPECT_EQ(0, counts[i]); } // Check that the elements at the end are preserved. - for (int i = erase_end; i < len; ++i) { + for (size_t i = erase_end; i < len; ++i) { EXPECT_EQ(1, counts[i]); } } @@ -377,21 +423,21 @@ TEST(InlinedVectorTest, ShrinkToFitGrowingVector) { absl::InlinedVector<std::pair<std::string, int>, 1> v; v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 1); + EXPECT_EQ(v.capacity(), 1u); v.emplace_back("answer", 42); v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 1); + EXPECT_EQ(v.capacity(), 1u); v.emplace_back("taxicab", 1729); - EXPECT_GE(v.capacity(), 2); + EXPECT_GE(v.capacity(), 2u); v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 2); + EXPECT_EQ(v.capacity(), 2u); v.reserve(100); - EXPECT_GE(v.capacity(), 100); + EXPECT_GE(v.capacity(), 100u); v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 2); + EXPECT_EQ(v.capacity(), 2u); } TEST(InlinedVectorTest, ShrinkToFitEdgeCases) { @@ -399,10 +445,10 @@ TEST(InlinedVectorTest, ShrinkToFitEdgeCases) { absl::InlinedVector<std::pair<std::string, int>, 1> v; v.emplace_back("answer", 42); v.emplace_back("taxicab", 1729); - EXPECT_GE(v.capacity(), 2); + EXPECT_GE(v.capacity(), 2u); v.pop_back(); v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 1); + EXPECT_EQ(v.capacity(), 1u); EXPECT_EQ(v[0].first, "answer"); EXPECT_EQ(v[0].second, 42); } @@ -411,34 +457,34 @@ TEST(InlinedVectorTest, ShrinkToFitEdgeCases) { absl::InlinedVector<std::string, 2> v(100); v.resize(0); v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 2); // inlined capacity + EXPECT_EQ(v.capacity(), 2u); // inlined capacity } { absl::InlinedVector<std::string, 2> v(100); v.resize(1); v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 2); // inlined capacity + EXPECT_EQ(v.capacity(), 2u); // inlined capacity } { absl::InlinedVector<std::string, 2> v(100); v.resize(2); v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 2); + EXPECT_EQ(v.capacity(), 2u); } { absl::InlinedVector<std::string, 2> v(100); v.resize(3); v.shrink_to_fit(); - EXPECT_EQ(v.capacity(), 3); + EXPECT_EQ(v.capacity(), 3u); } } TEST(IntVec, Insert) { - for (int len = 0; len < 20; len++) { - for (int pos = 0; pos <= len; pos++) { + for (size_t len = 0; len < 20; len++) { + for (ptrdiff_t pos = 0; pos <= static_cast<ptrdiff_t>(len); pos++) { { // Single element std::vector<int> std_v; @@ -526,16 +572,16 @@ TEST(IntVec, Insert) { TEST(RefCountedVec, InsertConstructorDestructor) { // Make sure the proper construction/destruction happen during insert // operations. - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { SCOPED_TRACE(len); - for (int pos = 0; pos <= len; pos++) { + for (size_t pos = 0; pos <= len; pos++) { SCOPED_TRACE(pos); std::vector<int> counts(len, 0); int inserted_count = 0; RefCountedVec v; - for (int i = 0; i < len; ++i) { + for (size_t i = 0; i < len; ++i) { SCOPED_TRACE(i); - v.push_back(RefCounted(i, &counts[i])); + v.push_back(RefCounted(static_cast<int>(i), &counts[i])); } EXPECT_THAT(counts, Each(Eq(1))); @@ -552,20 +598,20 @@ TEST(RefCountedVec, InsertConstructorDestructor) { } TEST(IntVec, Resize) { - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { IntVec v; Fill(&v, len); // Try resizing up and down by k elements static const int kResizeElem = 1000000; - for (int k = 0; k < 10; k++) { + for (size_t k = 0; k < 10; k++) { // Enlarging resize v.resize(len + k, kResizeElem); EXPECT_EQ(len + k, v.size()); EXPECT_LE(len + k, v.capacity()); - for (int i = 0; i < len + k; i++) { + for (size_t i = 0; i < len + k; i++) { if (i < len) { - EXPECT_EQ(i, v[i]); + EXPECT_EQ(static_cast<int>(i), v[i]); } else { EXPECT_EQ(kResizeElem, v[i]); } @@ -575,26 +621,26 @@ TEST(IntVec, Resize) { v.resize(len, kResizeElem); EXPECT_EQ(len, v.size()); EXPECT_LE(len, v.capacity()); - for (int i = 0; i < len; i++) { - EXPECT_EQ(i, v[i]); + for (size_t i = 0; i < len; i++) { + EXPECT_EQ(static_cast<int>(i), v[i]); } } } } TEST(IntVec, InitWithLength) { - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { IntVec v(len, 7); EXPECT_EQ(len, v.size()); EXPECT_LE(len, v.capacity()); - for (int i = 0; i < len; i++) { + for (size_t i = 0; i < len; i++) { EXPECT_EQ(7, v[i]); } } } TEST(IntVec, CopyConstructorAndAssignment) { - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { IntVec v; Fill(&v, len); EXPECT_EQ(len, v.size()); @@ -603,7 +649,7 @@ TEST(IntVec, CopyConstructorAndAssignment) { IntVec v2(v); EXPECT_TRUE(v == v2) << PrintToString(v) << PrintToString(v2); - for (int start_len = 0; start_len < 20; start_len++) { + for (size_t start_len = 0; start_len < 20; start_len++) { IntVec v3; Fill(&v3, start_len, 99); // Add dummy elements that should go away v3 = v; @@ -613,7 +659,7 @@ TEST(IntVec, CopyConstructorAndAssignment) { } TEST(IntVec, AliasingCopyAssignment) { - for (int len = 0; len < 20; ++len) { + for (size_t len = 0; len < 20; ++len) { IntVec original; Fill(&original, len); IntVec dup = original; @@ -623,9 +669,9 @@ TEST(IntVec, AliasingCopyAssignment) { } TEST(IntVec, MoveConstructorAndAssignment) { - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { IntVec v_in; - const int inlined_capacity = v_in.capacity(); + const size_t inlined_capacity = v_in.capacity(); Fill(&v_in, len); EXPECT_EQ(len, v_in.size()); EXPECT_LE(len, v_in.capacity()); @@ -642,7 +688,7 @@ TEST(IntVec, MoveConstructorAndAssignment) { EXPECT_FALSE(v_out.data() == old_data); } } - for (int start_len = 0; start_len < 20; start_len++) { + for (size_t start_len = 0; start_len < 20; start_len++) { IntVec v_out; Fill(&v_out, start_len, 99); // Add dummy elements that should go away IntVec v_temp(v_in); @@ -681,10 +727,10 @@ class NotTriviallyDestructible { }; TEST(AliasingTest, Emplace) { - for (int i = 2; i < 20; ++i) { + for (size_t i = 2; i < 20; ++i) { absl::InlinedVector<NotTriviallyDestructible, 10> vec; - for (int j = 0; j < i; ++j) { - vec.push_back(NotTriviallyDestructible(j)); + for (size_t j = 0; j < i; ++j) { + vec.push_back(NotTriviallyDestructible(static_cast<int>(j))); } vec.emplace(vec.begin(), vec[0]); EXPECT_EQ(vec[0], vec[1]); @@ -696,12 +742,12 @@ TEST(AliasingTest, Emplace) { } TEST(AliasingTest, InsertWithCount) { - for (int i = 1; i < 20; ++i) { + for (size_t i = 1; i < 20; ++i) { absl::InlinedVector<NotTriviallyDestructible, 10> vec; - for (int j = 0; j < i; ++j) { - vec.push_back(NotTriviallyDestructible(j)); + for (size_t j = 0; j < i; ++j) { + vec.push_back(NotTriviallyDestructible(static_cast<int>(j))); } - for (int n = 0; n < 5; ++n) { + for (size_t n = 0; n < 5; ++n) { // We use back where we can because it's guaranteed to become invalidated vec.insert(vec.begin(), n, vec.back()); auto b = vec.begin(); @@ -736,41 +782,45 @@ TEST(OverheadTest, Storage) { // In particular, ensure that std::allocator doesn't cost anything to store. // The union should be absorbing some of the allocation bookkeeping overhead // in the larger vectors, leaving only the size_ field as overhead. - EXPECT_EQ(2 * sizeof(int*), - sizeof(absl::InlinedVector<int*, 1>) - 1 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector<int*, 2>) - 2 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector<int*, 3>) - 3 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector<int*, 4>) - 4 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector<int*, 5>) - 5 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector<int*, 6>) - 6 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector<int*, 7>) - 7 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector<int*, 8>) - 8 * sizeof(int*)); + + struct T { void* val; }; + size_t expected_overhead = sizeof(T); + + EXPECT_EQ((2 * expected_overhead), + sizeof(absl::InlinedVector<T, 1>) - sizeof(T[1])); + EXPECT_EQ(expected_overhead, + sizeof(absl::InlinedVector<T, 2>) - sizeof(T[2])); + EXPECT_EQ(expected_overhead, + sizeof(absl::InlinedVector<T, 3>) - sizeof(T[3])); + EXPECT_EQ(expected_overhead, + sizeof(absl::InlinedVector<T, 4>) - sizeof(T[4])); + EXPECT_EQ(expected_overhead, + sizeof(absl::InlinedVector<T, 5>) - sizeof(T[5])); + EXPECT_EQ(expected_overhead, + sizeof(absl::InlinedVector<T, 6>) - sizeof(T[6])); + EXPECT_EQ(expected_overhead, + sizeof(absl::InlinedVector<T, 7>) - sizeof(T[7])); + EXPECT_EQ(expected_overhead, + sizeof(absl::InlinedVector<T, 8>) - sizeof(T[8])); } TEST(IntVec, Clear) { - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { SCOPED_TRACE(len); IntVec v; Fill(&v, len); v.clear(); - EXPECT_EQ(0, v.size()); + EXPECT_EQ(0u, v.size()); EXPECT_EQ(v.begin(), v.end()); } } TEST(IntVec, Reserve) { - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { IntVec v; Fill(&v, len); - for (int newlen = 0; newlen < 100; newlen++) { + for (size_t newlen = 0; newlen < 100; newlen++) { const int* start_rep = v.data(); v.reserve(newlen); const int* final_rep = v.data(); @@ -837,9 +887,9 @@ TEST(StringVec, SelfMove) { } TEST(IntVec, Swap) { - for (int l1 = 0; l1 < 20; l1++) { + for (size_t l1 = 0; l1 < 20; l1++) { SCOPED_TRACE(l1); - for (int l2 = 0; l2 < 20; l2++) { + for (size_t l2 = 0; l2 < 20; l2++) { SCOPED_TRACE(l2); IntVec a = Fill(l1, 0); IntVec b = Fill(l2, 100); @@ -849,13 +899,13 @@ TEST(IntVec, Swap) { } EXPECT_EQ(l1, b.size()); EXPECT_EQ(l2, a.size()); - for (int i = 0; i < l1; i++) { + for (size_t i = 0; i < l1; i++) { SCOPED_TRACE(i); - EXPECT_EQ(i, b[i]); + EXPECT_EQ(static_cast<int>(i), b[i]); } - for (int i = 0; i < l2; i++) { + for (size_t i = 0; i < l2; i++) { SCOPED_TRACE(i); - EXPECT_EQ(100 + i, a[i]); + EXPECT_EQ(100 + static_cast<int>(i), a[i]); } } } @@ -864,46 +914,48 @@ TEST(IntVec, Swap) { TYPED_TEST_P(InstanceTest, Swap) { using Instance = TypeParam; using InstanceVec = absl::InlinedVector<Instance, 8>; - for (int l1 = 0; l1 < 20; l1++) { + for (size_t l1 = 0; l1 < 20; l1++) { SCOPED_TRACE(l1); - for (int l2 = 0; l2 < 20; l2++) { + for (size_t l2 = 0; l2 < 20; l2++) { SCOPED_TRACE(l2); InstanceTracker tracker; InstanceVec a, b; const size_t inlined_capacity = a.capacity(); auto min_len = std::min(l1, l2); auto max_len = std::max(l1, l2); - for (int i = 0; i < l1; i++) a.push_back(Instance(i)); - for (int i = 0; i < l2; i++) b.push_back(Instance(100 + i)); - EXPECT_EQ(tracker.instances(), l1 + l2); + for (size_t i = 0; i < l1; i++) + a.push_back(Instance(static_cast<int>(i))); + for (size_t i = 0; i < l2; i++) + b.push_back(Instance(100 + static_cast<int>(i))); + EXPECT_EQ(tracker.instances(), static_cast<int>(l1 + l2)); tracker.ResetCopiesMovesSwaps(); { using std::swap; swap(a, b); } - EXPECT_EQ(tracker.instances(), l1 + l2); + EXPECT_EQ(tracker.instances(), static_cast<int>(l1 + l2)); if (a.size() > inlined_capacity && b.size() > inlined_capacity) { EXPECT_EQ(tracker.swaps(), 0); // Allocations are swapped. EXPECT_EQ(tracker.moves(), 0); } else if (a.size() <= inlined_capacity && b.size() <= inlined_capacity) { - EXPECT_EQ(tracker.swaps(), min_len); + EXPECT_EQ(tracker.swaps(), static_cast<int>(min_len)); EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()), - max_len - min_len); + static_cast<int>(max_len - min_len)); } else { // One is allocated and the other isn't. The allocation is transferred // without copying elements, and the inlined instances are copied/moved. EXPECT_EQ(tracker.swaps(), 0); EXPECT_EQ((tracker.moves() ? tracker.moves() : tracker.copies()), - min_len); + static_cast<int>(min_len)); } EXPECT_EQ(l1, b.size()); EXPECT_EQ(l2, a.size()); - for (int i = 0; i < l1; i++) { - EXPECT_EQ(i, b[i].value()); + for (size_t i = 0; i < l1; i++) { + EXPECT_EQ(static_cast<int>(i), b[i].value()); } - for (int i = 0; i < l2; i++) { - EXPECT_EQ(100 + i, a[i].value()); + for (size_t i = 0; i < l2; i++) { + EXPECT_EQ(100 + static_cast<int>(i), a[i].value()); } } } @@ -932,9 +984,9 @@ TEST(IntVec, EqualAndNotEqual) { a.clear(); b.clear(); - for (int i = 0; i < 100; i++) { - a.push_back(i); - b.push_back(i); + for (size_t i = 0; i < 100; i++) { + a.push_back(static_cast<int>(i)); + b.push_back(static_cast<int>(i)); EXPECT_TRUE(a == b); EXPECT_FALSE(a != b); @@ -973,26 +1025,26 @@ TYPED_TEST_P(InstanceTest, CountConstructorsDestructors) { using Instance = TypeParam; using InstanceVec = absl::InlinedVector<Instance, 8>; InstanceTracker tracker; - for (int len = 0; len < 20; len++) { + for (size_t len = 0; len < 20; len++) { SCOPED_TRACE(len); tracker.ResetCopiesMovesSwaps(); InstanceVec v; const size_t inlined_capacity = v.capacity(); - for (int i = 0; i < len; i++) { - v.push_back(Instance(i)); + for (size_t i = 0; i < len; i++) { + v.push_back(Instance(static_cast<int>(i))); } - EXPECT_EQ(tracker.instances(), len); + EXPECT_EQ(tracker.instances(), static_cast<int>(len)); EXPECT_GE(tracker.copies() + tracker.moves(), - len); // More due to reallocation. + static_cast<int>(len)); // More due to reallocation. tracker.ResetCopiesMovesSwaps(); // Enlarging resize() must construct some objects tracker.ResetCopiesMovesSwaps(); v.resize(len + 10, Instance(100)); - EXPECT_EQ(tracker.instances(), len + 10); + EXPECT_EQ(tracker.instances(), static_cast<int>(len) + 10); if (len <= inlined_capacity && len + 10 > inlined_capacity) { - EXPECT_EQ(tracker.copies() + tracker.moves(), 10 + len); + EXPECT_EQ(tracker.copies() + tracker.moves(), 10 + static_cast<int>(len)); } else { // Only specify a minimum number of copies + moves. We don't want to // depend on the reallocation policy here. @@ -1003,29 +1055,30 @@ TYPED_TEST_P(InstanceTest, CountConstructorsDestructors) { // Shrinking resize() must destroy some objects tracker.ResetCopiesMovesSwaps(); v.resize(len, Instance(100)); - EXPECT_EQ(tracker.instances(), len); + EXPECT_EQ(tracker.instances(), static_cast<int>(len)); EXPECT_EQ(tracker.copies(), 0); EXPECT_EQ(tracker.moves(), 0); // reserve() must not increase the number of initialized objects SCOPED_TRACE("reserve"); v.reserve(len + 1000); - EXPECT_EQ(tracker.instances(), len); - EXPECT_EQ(tracker.copies() + tracker.moves(), len); + EXPECT_EQ(tracker.instances(), static_cast<int>(len)); + EXPECT_EQ(tracker.copies() + tracker.moves(), static_cast<int>(len)); // pop_back() and erase() must destroy one object if (len > 0) { tracker.ResetCopiesMovesSwaps(); v.pop_back(); - EXPECT_EQ(tracker.instances(), len - 1); + EXPECT_EQ(tracker.instances(), static_cast<int>(len) - 1); EXPECT_EQ(tracker.copies(), 0); EXPECT_EQ(tracker.moves(), 0); if (!v.empty()) { tracker.ResetCopiesMovesSwaps(); v.erase(v.begin()); - EXPECT_EQ(tracker.instances(), len - 2); - EXPECT_EQ(tracker.copies() + tracker.moves(), len - 2); + EXPECT_EQ(tracker.instances(), static_cast<int>(len) - 2); + EXPECT_EQ(tracker.copies() + tracker.moves(), + static_cast<int>(len) - 2); } } @@ -1082,12 +1135,12 @@ TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveConstruction) { tracker.ResetCopiesMovesSwaps(); { InstanceVec v_copy(std::move(v)); - if (len > inlined_capacity) { + if (static_cast<size_t>(len) > inlined_capacity) { // Allocation is moved as a whole. EXPECT_EQ(tracker.instances(), len); EXPECT_EQ(tracker.live_instances(), len); // Tests an implementation detail, don't rely on this in your code. - EXPECT_EQ(v.size(), 0); // NOLINT misc-use-after-move + EXPECT_EQ(v.size(), 0u); // NOLINT misc-use-after-move EXPECT_EQ(tracker.copies(), 0); EXPECT_EQ(tracker.moves(), 0); } else { @@ -1153,7 +1206,7 @@ TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveAssignment) { tracker.ResetCopiesMovesSwaps(); InstanceVec longer, shorter; - const int inlined_capacity = longer.capacity(); + const size_t inlined_capacity = longer.capacity(); for (int i = 0; i < len; i++) { longer.push_back(Instance(i)); shorter.push_back(Instance(i)); @@ -1172,7 +1225,7 @@ TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveAssignment) { src_len = len; longer = std::move(shorter); } - if (src_len > inlined_capacity) { + if (static_cast<size_t>(src_len) > inlined_capacity) { // Allocation moved as a whole. EXPECT_EQ(tracker.instances(), src_len); EXPECT_EQ(tracker.live_instances(), src_len); @@ -1197,6 +1250,8 @@ TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveAssignment) { } TEST(CountElemAssign, SimpleTypeWithInlineBacking) { + const size_t inlined_capacity = absl::InlinedVector<int, 2>().capacity(); + for (size_t original_size = 0; original_size <= 5; ++original_size) { SCOPED_TRACE(original_size); // Original contents are [12345, 12345, ...] @@ -1205,10 +1260,10 @@ TEST(CountElemAssign, SimpleTypeWithInlineBacking) { absl::InlinedVector<int, 2> v(original_contents.begin(), original_contents.end()); v.assign(2, 123); - EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(123, 123))); - if (original_size <= 2) { + EXPECT_THAT(v, AllOf(SizeIs(2u), ElementsAre(123, 123))); + if (original_size <= inlined_capacity) { // If the original had inline backing, it should stay inline. - EXPECT_EQ(2, v.capacity()); + EXPECT_EQ(v.capacity(), inlined_capacity); } } } @@ -1222,7 +1277,7 @@ TEST(CountElemAssign, SimpleTypeWithAllocation) { absl::InlinedVector<int, 2> v(original_contents.begin(), original_contents.end()); v.assign(3, 123); - EXPECT_THAT(v, AllOf(SizeIs(3), ElementsAre(123, 123, 123))); + EXPECT_THAT(v, AllOf(SizeIs(3u), ElementsAre(123, 123, 123))); EXPECT_LE(v.size(), v.capacity()); } } @@ -1237,10 +1292,10 @@ TYPED_TEST_P(InstanceTest, CountElemAssignInlineBacking) { absl::InlinedVector<Instance, 2> v(original_contents.begin(), original_contents.end()); v.assign(2, Instance(123)); - EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(ValueIs(123), ValueIs(123)))); + EXPECT_THAT(v, AllOf(SizeIs(2u), ElementsAre(ValueIs(123), ValueIs(123)))); if (original_size <= 2) { // If the original had inline backing, it should stay inline. - EXPECT_EQ(2, v.capacity()); + EXPECT_EQ(2u, v.capacity()); } } } @@ -1255,8 +1310,8 @@ void InstanceCountElemAssignWithAllocationTest() { absl::InlinedVector<Instance, 2> v(original_contents.begin(), original_contents.end()); v.assign(3, Instance(123)); - EXPECT_THAT(v, AllOf(SizeIs(3), ElementsAre(ValueIs(123), ValueIs(123), - ValueIs(123)))); + EXPECT_THAT(v, AllOf(SizeIs(3u), ElementsAre(ValueIs(123), ValueIs(123), + ValueIs(123)))); EXPECT_LE(v.size(), v.capacity()); } } @@ -1271,16 +1326,17 @@ TEST(RangedConstructor, SimpleType) { std::vector<int> source_v = {4, 5, 6}; // First try to fit in inline backing absl::InlinedVector<int, 4> v(source_v.begin(), source_v.end()); - EXPECT_EQ(3, v.size()); - EXPECT_EQ(4, v.capacity()); // Indication that we're still on inlined storage + EXPECT_EQ(3u, v.size()); + EXPECT_EQ(4u, + v.capacity()); // Indication that we're still on inlined storage EXPECT_EQ(4, v[0]); EXPECT_EQ(5, v[1]); EXPECT_EQ(6, v[2]); // Now, force a re-allocate absl::InlinedVector<int, 2> realloc_v(source_v.begin(), source_v.end()); - EXPECT_EQ(3, realloc_v.size()); - EXPECT_LT(2, realloc_v.capacity()); + EXPECT_EQ(3u, realloc_v.size()); + EXPECT_LT(2u, realloc_v.capacity()); EXPECT_EQ(4, realloc_v[0]); EXPECT_EQ(5, realloc_v[1]); EXPECT_EQ(6, realloc_v[2]); @@ -1295,8 +1351,8 @@ void InstanceRangedConstructorTestForContainer() { tracker.ResetCopiesMovesSwaps(); absl::InlinedVector<Instance, inlined_capacity> v(source_v.begin(), source_v.end()); - EXPECT_EQ(2, v.size()); - EXPECT_LT(1, v.capacity()); + EXPECT_EQ(2u, v.size()); + EXPECT_LT(1u, v.capacity()); EXPECT_EQ(0, v[0].value()); EXPECT_EQ(1, v[1].value()); EXPECT_EQ(tracker.copies(), 2); @@ -1348,6 +1404,8 @@ TEST(RangedConstructor, ElementsAreConstructed) { } TEST(RangedAssign, SimpleType) { + const size_t inlined_capacity = absl::InlinedVector<int, 3>().capacity(); + // Test for all combinations of original sizes (empty and non-empty inline, // and out of line) and target sizes. for (size_t original_size = 0; original_size <= 5; ++original_size) { @@ -1361,7 +1419,7 @@ TEST(RangedAssign, SimpleType) { // New contents are [3, 4, ...] std::vector<int> new_contents; for (size_t i = 0; i < target_size; ++i) { - new_contents.push_back(i + 3); + new_contents.push_back(static_cast<int>(i + 3)); } absl::InlinedVector<int, 3> v(original_contents.begin(), @@ -1370,9 +1428,10 @@ TEST(RangedAssign, SimpleType) { EXPECT_EQ(new_contents.size(), v.size()); EXPECT_LE(new_contents.size(), v.capacity()); - if (target_size <= 3 && original_size <= 3) { + if (target_size <= inlined_capacity && + original_size <= inlined_capacity) { // Storage should stay inline when target size is small. - EXPECT_EQ(3, v.capacity()); + EXPECT_EQ(v.capacity(), inlined_capacity); } EXPECT_THAT(v, ElementsAreArray(new_contents)); } @@ -1405,7 +1464,7 @@ void InstanceRangedAssignTestForContainer() { // TODO(bsamwel): Test with an input iterator. std::vector<Instance> new_contents_in; for (size_t i = 0; i < target_size; ++i) { - new_contents_in.push_back(Instance(i + 3)); + new_contents_in.push_back(Instance(static_cast<int>(i) + 3)); } SourceContainer new_contents(new_contents_in.begin(), new_contents_in.end()); @@ -1418,7 +1477,7 @@ void InstanceRangedAssignTestForContainer() { EXPECT_LE(new_contents.size(), v.capacity()); if (target_size <= 3 && original_size <= 3) { // Storage should stay inline when target size is small. - EXPECT_EQ(3, v.capacity()); + EXPECT_EQ(3u, v.capacity()); } EXPECT_TRUE(std::equal(v.begin(), v.end(), new_contents.begin(), InstanceValuesEqual<Instance>)); @@ -1442,12 +1501,12 @@ TYPED_TEST_P(InstanceTest, RangedAssign) { TEST(InitializerListConstructor, SimpleTypeWithInlineBacking) { EXPECT_THAT((absl::InlinedVector<int, 4>{4, 5, 6}), - AllOf(SizeIs(3), CapacityIs(4), ElementsAre(4, 5, 6))); + AllOf(SizeIs(3u), CapacityIs(4u), ElementsAre(4, 5, 6))); } TEST(InitializerListConstructor, SimpleTypeWithReallocationRequired) { EXPECT_THAT((absl::InlinedVector<int, 2>{4, 5, 6}), - AllOf(SizeIs(3), CapacityIs(Gt(2)), ElementsAre(4, 5, 6))); + AllOf(SizeIs(3u), CapacityIs(Gt(2u)), ElementsAre(4, 5, 6))); } TEST(InitializerListConstructor, DisparateTypesInList) { @@ -1458,16 +1517,19 @@ TEST(InitializerListConstructor, DisparateTypesInList) { } TEST(InitializerListConstructor, ComplexTypeWithInlineBacking) { - EXPECT_THAT((absl::InlinedVector<CopyableMovableInstance, 1>{ - CopyableMovableInstance(0)}), - AllOf(SizeIs(1), CapacityIs(1), ElementsAre(ValueIs(0)))); + const size_t inlined_capacity = + absl::InlinedVector<CopyableMovableInstance, 1>().capacity(); + EXPECT_THAT( + (absl::InlinedVector<CopyableMovableInstance, 1>{ + CopyableMovableInstance(0)}), + AllOf(SizeIs(1u), CapacityIs(inlined_capacity), ElementsAre(ValueIs(0)))); } TEST(InitializerListConstructor, ComplexTypeWithReallocationRequired) { - EXPECT_THAT( - (absl::InlinedVector<CopyableMovableInstance, 1>{ - CopyableMovableInstance(0), CopyableMovableInstance(1)}), - AllOf(SizeIs(2), CapacityIs(Gt(1)), ElementsAre(ValueIs(0), ValueIs(1)))); + EXPECT_THAT((absl::InlinedVector<CopyableMovableInstance, 1>{ + CopyableMovableInstance(0), CopyableMovableInstance(1)}), + AllOf(SizeIs(2u), CapacityIs(Gt(1u)), + ElementsAre(ValueIs(0), ValueIs(1)))); } TEST(InitializerListAssign, SimpleTypeFitsInlineBacking) { @@ -1477,14 +1539,14 @@ TEST(InitializerListAssign, SimpleTypeFitsInlineBacking) { absl::InlinedVector<int, 2> v1(original_size, 12345); const size_t original_capacity_v1 = v1.capacity(); v1.assign({3}); - EXPECT_THAT( - v1, AllOf(SizeIs(1), CapacityIs(original_capacity_v1), ElementsAre(3))); + EXPECT_THAT(v1, AllOf(SizeIs(1u), CapacityIs(original_capacity_v1), + ElementsAre(3))); absl::InlinedVector<int, 2> v2(original_size, 12345); const size_t original_capacity_v2 = v2.capacity(); v2 = {3}; - EXPECT_THAT( - v2, AllOf(SizeIs(1), CapacityIs(original_capacity_v2), ElementsAre(3))); + EXPECT_THAT(v2, AllOf(SizeIs(1u), CapacityIs(original_capacity_v2), + ElementsAre(3))); } } @@ -1493,13 +1555,13 @@ TEST(InitializerListAssign, SimpleTypeDoesNotFitInlineBacking) { SCOPED_TRACE(original_size); absl::InlinedVector<int, 2> v1(original_size, 12345); v1.assign({3, 4, 5}); - EXPECT_THAT(v1, AllOf(SizeIs(3), ElementsAre(3, 4, 5))); - EXPECT_LE(3, v1.capacity()); + EXPECT_THAT(v1, AllOf(SizeIs(3u), ElementsAre(3, 4, 5))); + EXPECT_LE(3u, v1.capacity()); absl::InlinedVector<int, 2> v2(original_size, 12345); v2 = {3, 4, 5}; - EXPECT_THAT(v2, AllOf(SizeIs(3), ElementsAre(3, 4, 5))); - EXPECT_LE(3, v2.capacity()); + EXPECT_THAT(v2, AllOf(SizeIs(3u), ElementsAre(3, 4, 5))); + EXPECT_LE(3u, v2.capacity()); } } @@ -1528,7 +1590,7 @@ TYPED_TEST_P(InstanceTest, InitializerListAssign) { absl::InlinedVector<Instance, 2> v(original_size, Instance(12345)); const size_t original_capacity = v.capacity(); v.assign({Instance(3)}); - EXPECT_THAT(v, AllOf(SizeIs(1), CapacityIs(original_capacity), + EXPECT_THAT(v, AllOf(SizeIs(1u), CapacityIs(original_capacity), ElementsAre(ValueIs(3)))); } for (size_t original_size = 0; original_size <= 4; ++original_size) { @@ -1536,28 +1598,53 @@ TYPED_TEST_P(InstanceTest, InitializerListAssign) { absl::InlinedVector<Instance, 2> v(original_size, Instance(12345)); v.assign({Instance(3), Instance(4), Instance(5)}); EXPECT_THAT( - v, AllOf(SizeIs(3), ElementsAre(ValueIs(3), ValueIs(4), ValueIs(5)))); - EXPECT_LE(3, v.capacity()); + v, AllOf(SizeIs(3u), ElementsAre(ValueIs(3), ValueIs(4), ValueIs(5)))); + EXPECT_LE(3u, v.capacity()); } } -REGISTER_TYPED_TEST_CASE_P(InstanceTest, Swap, CountConstructorsDestructors, - CountConstructorsDestructorsOnCopyConstruction, - CountConstructorsDestructorsOnMoveConstruction, - CountConstructorsDestructorsOnAssignment, - CountConstructorsDestructorsOnMoveAssignment, - CountElemAssignInlineBacking, RangedConstructor, - RangedAssign, InitializerListAssign); +REGISTER_TYPED_TEST_SUITE_P(InstanceTest, Swap, CountConstructorsDestructors, + CountConstructorsDestructorsOnCopyConstruction, + CountConstructorsDestructorsOnMoveConstruction, + CountConstructorsDestructorsOnAssignment, + CountConstructorsDestructorsOnMoveAssignment, + CountElemAssignInlineBacking, RangedConstructor, + RangedAssign, InitializerListAssign); using InstanceTypes = ::testing::Types<CopyableOnlyInstance, CopyableMovableInstance>; -INSTANTIATE_TYPED_TEST_CASE_P(InstanceTestOnTypes, InstanceTest, InstanceTypes); +INSTANTIATE_TYPED_TEST_SUITE_P(InstanceTestOnTypes, InstanceTest, + InstanceTypes); TEST(DynamicVec, DynamicVecCompiles) { DynamicVec v; (void)v; } +TEST(DynamicVec, CreateNonEmptyDynamicVec) { + DynamicVec v(1); + EXPECT_EQ(v.size(), 1u); +} + +TEST(DynamicVec, EmplaceBack) { + DynamicVec v; + v.emplace_back(Dynamic{}); + EXPECT_EQ(v.size(), 1u); +} + +TEST(DynamicVec, EmplaceBackAfterHeapAllocation) { + DynamicVec v; + v.reserve(10); + v.emplace_back(Dynamic{}); + EXPECT_EQ(v.size(), 1u); +} + +TEST(DynamicVec, EmptyIteratorComparison) { + DynamicVec v; + EXPECT_EQ(v.begin(), v.end()); + EXPECT_EQ(v.cbegin(), v.cend()); +} + TEST(AllocatorSupportTest, Constructors) { using MyAlloc = CountingAllocator<int>; using AllocVec = absl::InlinedVector<int, 4, MyAlloc>; @@ -1582,54 +1669,54 @@ TEST(AllocatorSupportTest, CountAllocations) { MyAlloc alloc(&allocated); { AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + 4, alloc); - EXPECT_THAT(allocated, 0); + EXPECT_THAT(allocated, Eq(0)); } - EXPECT_THAT(allocated, 0); + EXPECT_THAT(allocated, Eq(0)); { AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc); - EXPECT_THAT(allocated, v.size() * sizeof(int)); + EXPECT_THAT(allocated, Eq(static_cast<int64_t>(v.size() * sizeof(int)))); } - EXPECT_THAT(allocated, 0); + EXPECT_THAT(allocated, Eq(0)); { AllocVec v(4, 1, alloc); - EXPECT_THAT(allocated, 0); + EXPECT_THAT(allocated, Eq(0)); int64_t allocated2 = 0; MyAlloc alloc2(&allocated2); AllocVec v2(v, alloc2); - EXPECT_THAT(allocated2, 0); + EXPECT_THAT(allocated2, Eq(0)); int64_t allocated3 = 0; MyAlloc alloc3(&allocated3); AllocVec v3(std::move(v), alloc3); - EXPECT_THAT(allocated3, 0); + EXPECT_THAT(allocated3, Eq(0)); } EXPECT_THAT(allocated, 0); { AllocVec v(8, 2, alloc); - EXPECT_THAT(allocated, v.size() * sizeof(int)); + EXPECT_THAT(allocated, Eq(static_cast<int64_t>(v.size() * sizeof(int)))); int64_t allocated2 = 0; MyAlloc alloc2(&allocated2); AllocVec v2(v, alloc2); - EXPECT_THAT(allocated2, v2.size() * sizeof(int)); + EXPECT_THAT(allocated2, Eq(static_cast<int64_t>(v2.size() * sizeof(int)))); int64_t allocated3 = 0; MyAlloc alloc3(&allocated3); AllocVec v3(std::move(v), alloc3); - EXPECT_THAT(allocated3, v3.size() * sizeof(int)); + EXPECT_THAT(allocated3, Eq(static_cast<int64_t>(v3.size() * sizeof(int)))); } EXPECT_EQ(allocated, 0); { // Test shrink_to_fit deallocations. AllocVec v(8, 2, alloc); - EXPECT_EQ(allocated, 8 * sizeof(int)); + EXPECT_EQ(allocated, static_cast<int64_t>(8 * sizeof(int))); v.resize(5); - EXPECT_EQ(allocated, 8 * sizeof(int)); + EXPECT_EQ(allocated, static_cast<int64_t>(8 * sizeof(int))); v.shrink_to_fit(); - EXPECT_EQ(allocated, 5 * sizeof(int)); + EXPECT_EQ(allocated, static_cast<int64_t>(5 * sizeof(int))); v.resize(4); - EXPECT_EQ(allocated, 5 * sizeof(int)); + EXPECT_EQ(allocated, static_cast<int64_t>(5 * sizeof(int))); v.shrink_to_fit(); EXPECT_EQ(allocated, 0); } @@ -1648,13 +1735,17 @@ TEST(AllocatorSupportTest, SwapBothAllocated) { AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1); AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2); EXPECT_LT(v1.capacity(), v2.capacity()); - EXPECT_THAT(allocated1, v1.capacity() * sizeof(int)); - EXPECT_THAT(allocated2, v2.capacity() * sizeof(int)); + EXPECT_THAT(allocated1, + Eq(static_cast<int64_t>(v1.capacity() * sizeof(int)))); + EXPECT_THAT(allocated2, + Eq(static_cast<int64_t>(v2.capacity() * sizeof(int)))); v1.swap(v2); EXPECT_THAT(v1, ElementsAreArray(ia2)); EXPECT_THAT(v2, ElementsAreArray(ia1)); - EXPECT_THAT(allocated1, v2.capacity() * sizeof(int)); - EXPECT_THAT(allocated2, v1.capacity() * sizeof(int)); + EXPECT_THAT(allocated1, + Eq(static_cast<int64_t>(v2.capacity() * sizeof(int)))); + EXPECT_THAT(allocated2, + Eq(static_cast<int64_t>(v1.capacity() * sizeof(int)))); } EXPECT_THAT(allocated1, 0); EXPECT_THAT(allocated2, 0); @@ -1672,13 +1763,15 @@ TEST(AllocatorSupportTest, SwapOneAllocated) { MyAlloc a2(&allocated2); AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1); AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2); - EXPECT_THAT(allocated1, v1.capacity() * sizeof(int)); - EXPECT_THAT(allocated2, 0); + EXPECT_THAT(allocated1, + Eq(static_cast<int64_t>(v1.capacity() * sizeof(int)))); + EXPECT_THAT(allocated2, Eq(0)); v1.swap(v2); EXPECT_THAT(v1, ElementsAreArray(ia2)); EXPECT_THAT(v2, ElementsAreArray(ia1)); - EXPECT_THAT(allocated1, v2.capacity() * sizeof(int)); - EXPECT_THAT(allocated2, 0); + EXPECT_THAT(allocated1, + Eq(static_cast<int64_t>(v2.capacity() * sizeof(int)))); + EXPECT_THAT(allocated2, Eq(0)); EXPECT_TRUE(v2.get_allocator() == a1); EXPECT_TRUE(v1.get_allocator() == a2); } @@ -1740,7 +1833,7 @@ TEST(AllocatorSupportTest, ScopedAllocatorWorksAllocated) { } TEST(AllocatorSupportTest, SizeAllocConstructor) { - constexpr int inlined_size = 4; + constexpr size_t inlined_size = 4; using Alloc = CountingAllocator<int>; using AllocVec = absl::InlinedVector<int, inlined_size, Alloc>; @@ -1750,7 +1843,7 @@ TEST(AllocatorSupportTest, SizeAllocConstructor) { auto v = AllocVec(len, Alloc(&allocated)); // Inline storage used; allocator should not be invoked - EXPECT_THAT(allocated, 0); + EXPECT_THAT(allocated, Eq(0)); EXPECT_THAT(v, AllOf(SizeIs(len), Each(0))); } @@ -1760,7 +1853,7 @@ TEST(AllocatorSupportTest, SizeAllocConstructor) { auto v = AllocVec(len, Alloc(&allocated)); // Out of line storage used; allocation of 8 elements expected - EXPECT_THAT(allocated, len * sizeof(int)); + EXPECT_THAT(allocated, Eq(static_cast<int64_t>(len * sizeof(int)))); EXPECT_THAT(v, AllOf(SizeIs(len), Each(0))); } } @@ -1795,9 +1888,9 @@ TEST(InlinedVectorTest, AbslHashValueWorks) { // Generate a variety of vectors some of these are small enough for the inline // space but are stored out of line. - for (int i = 0; i < 10; ++i) { + for (size_t i = 0; i < 10; ++i) { V v; - for (int j = 0; j < i; ++j) { + for (int j = 0; j < static_cast<int>(i); ++j) { v.push_back(j); } cases.push_back(v); @@ -1808,4 +1901,226 @@ TEST(InlinedVectorTest, AbslHashValueWorks) { EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases)); } +class MoveConstructibleOnlyInstance + : public absl::test_internal::BaseCountedInstance { + public: + explicit MoveConstructibleOnlyInstance(int x) : BaseCountedInstance(x) {} + MoveConstructibleOnlyInstance(MoveConstructibleOnlyInstance&& other) = + default; + MoveConstructibleOnlyInstance& operator=( + MoveConstructibleOnlyInstance&& other) = delete; +}; + +MATCHER(HasValue, "") { + return ::testing::get<0>(arg).value() == ::testing::get<1>(arg); +} + +TEST(NonAssignableMoveAssignmentTest, AllocatedToInline) { + using X = MoveConstructibleOnlyInstance; + InstanceTracker tracker; + absl::InlinedVector<X, 2> inlined; + inlined.emplace_back(1); + absl::InlinedVector<X, 2> allocated; + allocated.emplace_back(1); + allocated.emplace_back(2); + allocated.emplace_back(3); + tracker.ResetCopiesMovesSwaps(); + + inlined = std::move(allocated); + // passed ownership of the allocated storage + EXPECT_EQ(tracker.moves(), 0); + EXPECT_EQ(tracker.live_instances(), 3); + + EXPECT_THAT(inlined, Pointwise(HasValue(), {1, 2, 3})); +} + +TEST(NonAssignableMoveAssignmentTest, InlineToAllocated) { + using X = MoveConstructibleOnlyInstance; + InstanceTracker tracker; + absl::InlinedVector<X, 2> inlined; + inlined.emplace_back(1); + absl::InlinedVector<X, 2> allocated; + allocated.emplace_back(1); + allocated.emplace_back(2); + allocated.emplace_back(3); + tracker.ResetCopiesMovesSwaps(); + + allocated = std::move(inlined); + // Moved elements + EXPECT_EQ(tracker.moves(), 1); + EXPECT_EQ(tracker.live_instances(), 1); + + EXPECT_THAT(allocated, Pointwise(HasValue(), {1})); +} + +TEST(NonAssignableMoveAssignmentTest, InlineToInline) { + using X = MoveConstructibleOnlyInstance; + InstanceTracker tracker; + absl::InlinedVector<X, 2> inlined_a; + inlined_a.emplace_back(1); + absl::InlinedVector<X, 2> inlined_b; + inlined_b.emplace_back(1); + tracker.ResetCopiesMovesSwaps(); + + inlined_a = std::move(inlined_b); + // Moved elements + EXPECT_EQ(tracker.moves(), 1); + EXPECT_EQ(tracker.live_instances(), 1); + + EXPECT_THAT(inlined_a, Pointwise(HasValue(), {1})); +} + +TEST(NonAssignableMoveAssignmentTest, AllocatedToAllocated) { + using X = MoveConstructibleOnlyInstance; + InstanceTracker tracker; + absl::InlinedVector<X, 2> allocated_a; + allocated_a.emplace_back(1); + allocated_a.emplace_back(2); + allocated_a.emplace_back(3); + absl::InlinedVector<X, 2> allocated_b; + allocated_b.emplace_back(4); + allocated_b.emplace_back(5); + allocated_b.emplace_back(6); + allocated_b.emplace_back(7); + tracker.ResetCopiesMovesSwaps(); + + allocated_a = std::move(allocated_b); + // passed ownership of the allocated storage + EXPECT_EQ(tracker.moves(), 0); + EXPECT_EQ(tracker.live_instances(), 4); + + EXPECT_THAT(allocated_a, Pointwise(HasValue(), {4, 5, 6, 7})); +} + +TEST(NonAssignableMoveAssignmentTest, AssignThis) { + using X = MoveConstructibleOnlyInstance; + InstanceTracker tracker; + absl::InlinedVector<X, 2> v; + v.emplace_back(1); + v.emplace_back(2); + v.emplace_back(3); + + tracker.ResetCopiesMovesSwaps(); + + // Obfuscated in order to pass -Wself-move. + v = std::move(*std::addressof(v)); + // nothing happens + EXPECT_EQ(tracker.moves(), 0); + EXPECT_EQ(tracker.live_instances(), 3); + + EXPECT_THAT(v, Pointwise(HasValue(), {1, 2, 3})); +} + +class NonSwappableInstance : public absl::test_internal::BaseCountedInstance { + public: + explicit NonSwappableInstance(int x) : BaseCountedInstance(x) {} + NonSwappableInstance(const NonSwappableInstance& other) = default; + NonSwappableInstance& operator=(const NonSwappableInstance& other) = default; + NonSwappableInstance(NonSwappableInstance&& other) = default; + NonSwappableInstance& operator=(NonSwappableInstance&& other) = default; +}; + +void swap(NonSwappableInstance&, NonSwappableInstance&) = delete; + +TEST(NonSwappableSwapTest, InlineAndAllocatedTransferStorageAndMove) { + using X = NonSwappableInstance; + InstanceTracker tracker; + absl::InlinedVector<X, 2> inlined; + inlined.emplace_back(1); + absl::InlinedVector<X, 2> allocated; + allocated.emplace_back(1); + allocated.emplace_back(2); + allocated.emplace_back(3); + tracker.ResetCopiesMovesSwaps(); + + inlined.swap(allocated); + EXPECT_EQ(tracker.moves(), 1); + EXPECT_EQ(tracker.live_instances(), 4); + + EXPECT_THAT(inlined, Pointwise(HasValue(), {1, 2, 3})); +} + +TEST(NonSwappableSwapTest, InlineAndInlineMoveIndividualElements) { + using X = NonSwappableInstance; + InstanceTracker tracker; + absl::InlinedVector<X, 2> inlined_a; + inlined_a.emplace_back(1); + absl::InlinedVector<X, 2> inlined_b; + inlined_b.emplace_back(2); + tracker.ResetCopiesMovesSwaps(); + + inlined_a.swap(inlined_b); + EXPECT_EQ(tracker.moves(), 3); + EXPECT_EQ(tracker.live_instances(), 2); + + EXPECT_THAT(inlined_a, Pointwise(HasValue(), {2})); + EXPECT_THAT(inlined_b, Pointwise(HasValue(), {1})); +} + +TEST(NonSwappableSwapTest, AllocatedAndAllocatedOnlyTransferStorage) { + using X = NonSwappableInstance; + InstanceTracker tracker; + absl::InlinedVector<X, 2> allocated_a; + allocated_a.emplace_back(1); + allocated_a.emplace_back(2); + allocated_a.emplace_back(3); + absl::InlinedVector<X, 2> allocated_b; + allocated_b.emplace_back(4); + allocated_b.emplace_back(5); + allocated_b.emplace_back(6); + allocated_b.emplace_back(7); + tracker.ResetCopiesMovesSwaps(); + + allocated_a.swap(allocated_b); + EXPECT_EQ(tracker.moves(), 0); + EXPECT_EQ(tracker.live_instances(), 7); + + EXPECT_THAT(allocated_a, Pointwise(HasValue(), {4, 5, 6, 7})); + EXPECT_THAT(allocated_b, Pointwise(HasValue(), {1, 2, 3})); +} + +TEST(NonSwappableSwapTest, SwapThis) { + using X = NonSwappableInstance; + InstanceTracker tracker; + absl::InlinedVector<X, 2> v; + v.emplace_back(1); + v.emplace_back(2); + v.emplace_back(3); + + tracker.ResetCopiesMovesSwaps(); + + v.swap(v); + EXPECT_EQ(tracker.moves(), 0); + EXPECT_EQ(tracker.live_instances(), 3); + + EXPECT_THAT(v, Pointwise(HasValue(), {1, 2, 3})); +} + +template <size_t N> +using CharVec = absl::InlinedVector<char, N>; + +// Warning: This struct "simulates" the type `InlinedVector::Storage::Allocated` +// to make reasonable expectations for inlined storage capacity optimization. If +// implementation changes `Allocated`, then `MySpan` and tests that use it need +// to be updated accordingly. +template <typename T> +struct MySpan { + T* data; + size_t size; +}; + +TEST(StorageTest, InlinedCapacityAutoIncrease) { + // The requested capacity is auto increased to `sizeof(MySpan<char>)`. + EXPECT_GT(CharVec<1>().capacity(), 1); + EXPECT_EQ(CharVec<1>().capacity(), sizeof(MySpan<char>)); + EXPECT_EQ(CharVec<1>().capacity(), CharVec<2>().capacity()); + EXPECT_EQ(sizeof(CharVec<1>), sizeof(CharVec<2>)); + + // The requested capacity is auto increased to + // `sizeof(MySpan<int>) / sizeof(int)`. + EXPECT_GT((absl::InlinedVector<int, 1>().capacity()), 1); + EXPECT_EQ((absl::InlinedVector<int, 1>().capacity()), + sizeof(MySpan<int>) / sizeof(int)); +} + } // anonymous namespace |