| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509 | /* * * Copyright 2017 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */#include "src/core/lib/gprpp/inlined_vector.h"#include <grpc/support/log.h>#include <gtest/gtest.h>#include "src/core/lib/gprpp/memory.h"#include "test/core/util/test_config.h"namespace grpc_core {namespace testing {namespace {template <typename Vector>static void FillVector(Vector* v, int len, int start = 0) {  for (int i = 0; i < len; i++) {    v->push_back(i + start);    EXPECT_EQ(i + 1UL, v->size());  }  EXPECT_EQ(static_cast<size_t>(len), v->size());  EXPECT_LE(static_cast<size_t>(len), v->capacity());}}  // namespaceTEST(InlinedVectorTest, CreateAndIterate) {  const int kNumElements = 9;  InlinedVector<int, 2> v;  EXPECT_TRUE(v.empty());  FillVector(&v, kNumElements);  EXPECT_EQ(static_cast<size_t>(kNumElements), v.size());  EXPECT_FALSE(v.empty());  for (int i = 0; i < kNumElements; ++i) {    EXPECT_EQ(i, v[i]);    EXPECT_EQ(i, &v[i] - &v[0]);  // Ensure contiguous allocation.  }}TEST(InlinedVectorTest, ValuesAreInlined) {  const int kNumElements = 5;  InlinedVector<int, 10> v;  FillVector(&v, kNumElements);  EXPECT_EQ(static_cast<size_t>(kNumElements), v.size());  for (int i = 0; i < kNumElements; ++i) {    EXPECT_EQ(i, v[i]);  }}TEST(InlinedVectorTest, PushBackWithMove) {  InlinedVector<std::unique_ptr<int>, 1> v;  std::unique_ptr<int> i = grpc_core::MakeUnique<int>(3);  v.push_back(std::move(i));  EXPECT_EQ(nullptr, i.get());  EXPECT_EQ(1UL, v.size());  EXPECT_EQ(3, *v[0]);}TEST(InlinedVectorTest, EmplaceBack) {  InlinedVector<std::unique_ptr<int>, 1> v;  v.emplace_back(new int(3));  EXPECT_EQ(1UL, v.size());  EXPECT_EQ(3, *v[0]);}TEST(InlinedVectorTest, ClearAndRepopulate) {  const int kNumElements = 10;  InlinedVector<int, 5> v;  EXPECT_EQ(0UL, v.size());  FillVector(&v, kNumElements);  for (int i = 0; i < kNumElements; ++i) {    EXPECT_EQ(i, v[i]);  }  v.clear();  EXPECT_EQ(0UL, v.size());  FillVector(&v, kNumElements, kNumElements);  for (int i = 0; i < kNumElements; ++i) {    EXPECT_EQ(kNumElements + i, v[i]);  }}TEST(InlinedVectorTest, ConstIndexOperator) {  constexpr int kNumElements = 10;  InlinedVector<int, 5> v;  EXPECT_EQ(0UL, v.size());  FillVector(&v, kNumElements);  // The following lambda function is exceptionally allowed to use an anonymous  // capture due to the erroneous behavior of the MSVC compiler, that refuses to  // capture the kNumElements constexpr, something allowed by the standard.  auto const_func = [&](const InlinedVector<int, 5>& v) {    for (int i = 0; i < kNumElements; ++i) {      EXPECT_EQ(i, v[i]);    }  };  const_func(v);}TEST(InlinedVectorTest, EqualOperator) {  constexpr int kNumElements = 10;  // Both v1 and v2 are empty.  InlinedVector<int, 5> v1;  InlinedVector<int, 5> v2;  EXPECT_TRUE(v1 == v2);  // Both v1 and v2 contains the same data.  FillVector(&v1, kNumElements);  FillVector(&v2, kNumElements);  EXPECT_TRUE(v1 == v2);  // The sizes of v1 and v2 are different.  v1.push_back(0);  EXPECT_FALSE(v1 == v2);  // The contents of v1 and v2 are different although their sizes are the same.  v2.push_back(1);  EXPECT_FALSE(v1 == v2);}TEST(InlinedVectorTest, NotEqualOperator) {  constexpr int kNumElements = 10;  // Both v1 and v2 are empty.  InlinedVector<int, 5> v1;  InlinedVector<int, 5> v2;  EXPECT_FALSE(v1 != v2);  // Both v1 and v2 contains the same data.  FillVector(&v1, kNumElements);  FillVector(&v2, kNumElements);  EXPECT_FALSE(v1 != v2);  // The sizes of v1 and v2 are different.  v1.push_back(0);  EXPECT_TRUE(v1 != v2);  // The contents of v1 and v2 are different although their sizes are the same.  v2.push_back(1);  EXPECT_TRUE(v1 != v2);}// the following constants and typedefs are used for copy/move// construction/assignmentconst size_t kInlinedLength = 8;typedef InlinedVector<int, kInlinedLength> IntVec8;const size_t kInlinedFillSize = kInlinedLength - 1;const size_t kAllocatedFillSize = kInlinedLength + 1;TEST(InlinedVectorTest, CopyConstructorInlined) {  IntVec8 original;  FillVector(&original, kInlinedFillSize);  IntVec8 copy_constructed(original);  for (size_t i = 0; i < original.size(); ++i) {    EXPECT_EQ(original[i], copy_constructed[i]);  }}TEST(InlinedVectorTest, CopyConstructorAllocated) {  IntVec8 original;  FillVector(&original, kAllocatedFillSize);  IntVec8 copy_constructed(original);  for (size_t i = 0; i < original.size(); ++i) {    EXPECT_EQ(original[i], copy_constructed[i]);  }}TEST(InlinedVectorTest, CopyAssignementInlinedInlined) {  IntVec8 original;  FillVector(&original, kInlinedFillSize);  IntVec8 copy_assigned;  FillVector(©_assigned, kInlinedFillSize, 99);  copy_assigned = original;  for (size_t i = 0; i < original.size(); ++i) {    EXPECT_EQ(original[i], copy_assigned[i]);  }}TEST(InlinedVectorTest, CopyAssignementInlinedAllocated) {  IntVec8 original;  FillVector(&original, kInlinedFillSize);  IntVec8 copy_assigned;  FillVector(©_assigned, kAllocatedFillSize, 99);  copy_assigned = original;  for (size_t i = 0; i < original.size(); ++i) {    EXPECT_EQ(original[i], copy_assigned[i]);  }}TEST(InlinedVectorTest, CopyAssignementAllocatedInlined) {  IntVec8 original;  FillVector(&original, kAllocatedFillSize);  IntVec8 copy_assigned;  FillVector(©_assigned, kInlinedFillSize, 99);  copy_assigned = original;  for (size_t i = 0; i < original.size(); ++i) {    EXPECT_EQ(original[i], copy_assigned[i]);  }}TEST(InlinedVectorTest, CopyAssignementAllocatedAllocated) {  IntVec8 original;  FillVector(&original, kAllocatedFillSize);  IntVec8 copy_assigned;  FillVector(©_assigned, kAllocatedFillSize, 99);  copy_assigned = original;  for (size_t i = 0; i < original.size(); ++i) {    EXPECT_EQ(original[i], copy_assigned[i]);  }}TEST(InlinedVectorTest, MoveConstructorInlined) {  IntVec8 original;  FillVector(&original, kInlinedFillSize);  IntVec8 tmp(original);  auto* old_data = tmp.data();  IntVec8 move_constructed(std::move(tmp));  for (size_t i = 0; i < original.size(); ++i) {    EXPECT_EQ(original[i], move_constructed[i]);  }  // original data was inlined so it should have been copied, not moved.  EXPECT_NE(move_constructed.data(), old_data);}TEST(InlinedVectorTest, MoveConstructorAllocated) {  IntVec8 original;  FillVector(&original, kAllocatedFillSize);  IntVec8 tmp(original);  auto* old_data = tmp.data();  IntVec8 move_constructed(std::move(tmp));  for (size_t i = 0; i < original.size(); ++i) {    EXPECT_EQ(original[i], move_constructed[i]);  }  // original data was allocated, so it should been moved, not copied  EXPECT_EQ(move_constructed.data(), old_data);}TEST(InlinedVectorTest, MoveAssignmentInlinedInlined) {  IntVec8 original;  FillVector(&original, kInlinedFillSize);  IntVec8 move_assigned;  FillVector(&move_assigned, kInlinedFillSize, 99);  // Add dummy elements  IntVec8 tmp(original);  auto* old_data = tmp.data();  move_assigned = std::move(tmp);  for (size_t i = 0; i < original.size(); ++i) {    EXPECT_EQ(original[i], move_assigned[i]);  }  // original data was inlined so it should have been copied, not moved.  EXPECT_NE(move_assigned.data(), old_data);}TEST(InlinedVectorTest, MoveAssignmentInlinedAllocated) {  IntVec8 original;  FillVector(&original, kInlinedFillSize);  IntVec8 move_assigned;  FillVector(&move_assigned, kAllocatedFillSize, 99);  // Add dummy elements  IntVec8 tmp(original);  auto* old_data = tmp.data();  move_assigned = std::move(tmp);  for (size_t i = 0; i < original.size(); ++i) {    EXPECT_EQ(original[i], move_assigned[i]);  }  // original data was inlined so it should have been copied, not moved.  EXPECT_NE(move_assigned.data(), old_data);}TEST(InlinedVectorTest, MoveAssignmentAllocatedInlined) {  IntVec8 original;  FillVector(&original, kAllocatedFillSize);  IntVec8 move_assigned;  FillVector(&move_assigned, kInlinedFillSize, 99);  // Add dummy elements  IntVec8 tmp(original);  auto* old_data = tmp.data();  move_assigned = std::move(tmp);  for (size_t i = 0; i < original.size(); ++i) {    EXPECT_EQ(original[i], move_assigned[i]);  }  // original data was allocated so it should have been moved, not copied.  EXPECT_EQ(move_assigned.data(), old_data);}TEST(InlinedVectorTest, MoveAssignmentAllocatedAllocated) {  IntVec8 original;  FillVector(&original, kAllocatedFillSize);  IntVec8 move_assigned;  FillVector(&move_assigned, kAllocatedFillSize, 99);  // Add dummy elements  IntVec8 tmp(original);  auto* old_data = tmp.data();  move_assigned = std::move(tmp);  for (size_t i = 0; i < original.size(); ++i) {    EXPECT_EQ(original[i], move_assigned[i]);  }  // original data was allocated so it should have been moved, not copied.  EXPECT_EQ(move_assigned.data(), old_data);}// A copyable and movable value class, used to test that elements' copy// and move methods are called correctly.class Value { public:  explicit Value(int v) : value_(grpc_core::MakeUnique<int>(v)) {}  // copyable  Value(const Value& v) {    value_ = grpc_core::MakeUnique<int>(*v.value_);    copied_ = true;  }  Value& operator=(const Value& v) {    value_ = grpc_core::MakeUnique<int>(*v.value_);    copied_ = true;    return *this;  }  // movable  Value(Value&& v) {    value_ = std::move(v.value_);    moved_ = true;  }  Value& operator=(Value&& v) {    value_ = std::move(v.value_);    moved_ = true;    return *this;  }  const std::unique_ptr<int>& value() const { return value_; }  bool copied() const { return copied_; }  bool moved() const { return moved_; } private:  std::unique_ptr<int> value_;  bool copied_ = false;  bool moved_ = false;};TEST(InlinedVectorTest, CopyConstructorCopiesElementsInlined) {  InlinedVector<Value, 1> v1;  v1.emplace_back(3);  InlinedVector<Value, 1> v2(v1);  EXPECT_EQ(v2.size(), 1UL);  EXPECT_EQ(*v2[0].value(), 3);  // Addresses should differ.  EXPECT_NE(v1[0].value().get(), v2[0].value().get());  EXPECT_TRUE(v2[0].copied());}TEST(InlinedVectorTest, CopyConstructorCopiesElementsAllocated) {  InlinedVector<Value, 1> v1;  v1.reserve(2);  v1.emplace_back(3);  v1.emplace_back(5);  InlinedVector<Value, 1> v2(v1);  EXPECT_EQ(v2.size(), 2UL);  EXPECT_EQ(*v2[0].value(), 3);  EXPECT_EQ(*v2[1].value(), 5);  // Addresses should differ.  EXPECT_NE(v1[0].value().get(), v2[0].value().get());  EXPECT_NE(v1[1].value().get(), v2[1].value().get());  EXPECT_TRUE(v2[0].copied());  EXPECT_TRUE(v2[1].copied());}TEST(InlinedVectorTest, CopyAssignmentCopiesElementsInlined) {  InlinedVector<Value, 1> v1;  v1.emplace_back(3);  InlinedVector<Value, 1> v2;  EXPECT_EQ(v2.size(), 0UL);  v2 = v1;  EXPECT_EQ(v2.size(), 1UL);  EXPECT_EQ(*v2[0].value(), 3);  // Addresses should differ.  EXPECT_NE(v1[0].value().get(), v2[0].value().get());  EXPECT_TRUE(v2[0].copied());}TEST(InlinedVectorTest, CopyAssignmentCopiesElementsAllocated) {  InlinedVector<Value, 1> v1;  v1.reserve(2);  v1.emplace_back(3);  v1.emplace_back(5);  InlinedVector<Value, 1> v2;  EXPECT_EQ(v2.size(), 0UL);  v2 = v1;  EXPECT_EQ(v2.size(), 2UL);  EXPECT_EQ(*v2[0].value(), 3);  EXPECT_EQ(*v2[1].value(), 5);  // Addresses should differ.  EXPECT_NE(v1[0].value().get(), v2[0].value().get());  EXPECT_NE(v1[1].value().get(), v2[1].value().get());  EXPECT_TRUE(v2[0].copied());  EXPECT_TRUE(v2[1].copied());}TEST(InlinedVectorTest, MoveConstructorMovesElementsInlined) {  InlinedVector<Value, 1> v1;  v1.emplace_back(3);  int* addr = v1[0].value().get();  InlinedVector<Value, 1> v2(std::move(v1));  EXPECT_EQ(v2.size(), 1UL);  EXPECT_EQ(*v2[0].value(), 3);  EXPECT_EQ(addr, v2[0].value().get());  EXPECT_TRUE(v2[0].moved());}TEST(InlinedVectorTest, MoveConstructorMovesElementsAllocated) {  InlinedVector<Value, 1> v1;  v1.reserve(2);  v1.emplace_back(3);  v1.emplace_back(5);  int* addr1 = v1[0].value().get();  int* addr2 = v1[1].value().get();  Value* data1 = v1.data();  InlinedVector<Value, 1> v2(std::move(v1));  EXPECT_EQ(v2.size(), 2UL);  EXPECT_EQ(*v2[0].value(), 3);  EXPECT_EQ(*v2[1].value(), 5);  EXPECT_EQ(addr1, v2[0].value().get());  EXPECT_EQ(addr2, v2[1].value().get());  // In this case, elements won't be moved, because we have just stolen  // the underlying storage.  EXPECT_EQ(data1, v2.data());}TEST(InlinedVectorTest, MoveAssignmentMovesElementsInlined) {  InlinedVector<Value, 1> v1;  v1.emplace_back(3);  int* addr = v1[0].value().get();  InlinedVector<Value, 1> v2;  EXPECT_EQ(v2.size(), 0UL);  v2 = std::move(v1);  EXPECT_EQ(v2.size(), 1UL);  EXPECT_EQ(*v2[0].value(), 3);  EXPECT_EQ(addr, v2[0].value().get());  EXPECT_TRUE(v2[0].moved());}TEST(InlinedVectorTest, MoveAssignmentMovesElementsAllocated) {  InlinedVector<Value, 1> v1;  v1.reserve(2);  v1.emplace_back(3);  v1.emplace_back(5);  int* addr1 = v1[0].value().get();  int* addr2 = v1[1].value().get();  Value* data1 = v1.data();  InlinedVector<Value, 1> v2;  EXPECT_EQ(v2.size(), 0UL);  v2 = std::move(v1);  EXPECT_EQ(v2.size(), 2UL);  EXPECT_EQ(*v2[0].value(), 3);  EXPECT_EQ(*v2[1].value(), 5);  EXPECT_EQ(addr1, v2[0].value().get());  EXPECT_EQ(addr2, v2[1].value().get());  // In this case, elements won't be moved, because we have just stolen  // the underlying storage.  EXPECT_EQ(data1, v2.data());}TEST(InlinedVectorTest, PopBackInlined) {  InlinedVector<std::unique_ptr<int>, 2> v;  // Add two elements, pop one out  v.push_back(grpc_core::MakeUnique<int>(3));  EXPECT_EQ(1UL, v.size());  EXPECT_EQ(3, *v[0]);  v.push_back(grpc_core::MakeUnique<int>(5));  EXPECT_EQ(2UL, v.size());  EXPECT_EQ(5, *v[1]);  v.pop_back();  EXPECT_EQ(1UL, v.size());}TEST(InlinedVectorTest, PopBackAllocated) {  const int kInlinedSize = 2;  InlinedVector<std::unique_ptr<int>, kInlinedSize> v;  // Add elements to ensure allocated backing.  for (size_t i = 0; i < kInlinedSize + 1; ++i) {    v.push_back(grpc_core::MakeUnique<int>(3));    EXPECT_EQ(i + 1, v.size());  }  size_t sz = v.size();  v.pop_back();  EXPECT_EQ(sz - 1, v.size());}TEST(InlinedVectorTest, Resize) {  const int kInlinedSize = 2;  InlinedVector<std::unique_ptr<int>, kInlinedSize> v;  // Size up.  v.resize(5);  EXPECT_EQ(5UL, v.size());  EXPECT_EQ(nullptr, v[4]);  // Size down.  v[4] = grpc_core::MakeUnique<int>(5);  v.resize(1);  EXPECT_EQ(1UL, v.size());}}  // namespace testing}  // namespace grpc_coreint main(int argc, char** argv) {  grpc::testing::TestEnvironment env(argc, argv);  ::testing::InitGoogleTest(&argc, argv);  return RUN_ALL_TESTS();}
 |