Add copy and move ctor to InlinedVector

reviewable/pr15980/r2
ncteisen 7 years ago
parent 82e9cb66ff
commit 2d2854a1ce
  1. 73
      src/core/lib/gprpp/inlined_vector.h
  2. 101
      test/core/gprpp/inlined_vector_test.cc

@ -50,9 +50,76 @@ class InlinedVector {
InlinedVector() { init_data(); }
~InlinedVector() { destroy_elements(); }
// For now, we do not support copying.
InlinedVector(const InlinedVector&) = delete;
InlinedVector& operator=(const InlinedVector&) = delete;
// copy constructors
InlinedVector(const InlinedVector& v) {
init_data();
// if v is allocated, then we copy it's buffer
if (v.dynamic_ != nullptr) {
reserve(v.capacity_);
memcpy(dynamic_, v.dynamic_, v.capacity_ * sizeof(T));
} else {
memcpy(inline_, v.inline_, v.capacity_ * sizeof(T));
dynamic_ = nullptr;
}
// copy over metadata
size_ = v.size_;
capacity_ = v.capacity_;
}
InlinedVector& operator=(const InlinedVector& v) {
if (this != &v) {
clear();
// if v is allocated, then we copy it's buffer
if (v.dynamic_ != nullptr) {
reserve(v.capacity_);
memcpy(dynamic_, v.dynamic_, v.capacity_ * sizeof(T));
} else {
memcpy(inline_, v.inline_, v.capacity_ * sizeof(T));
dynamic_ = nullptr;
}
// copy over metadata
size_ = v.size_;
capacity_ = v.capacity_;
}
return *this;
}
// move constructors
InlinedVector(InlinedVector&& v) {
// if v is allocated, then we steal it's buffer
if (v.dynamic_ != nullptr) {
dynamic_ = v.dynamic_;
} else {
memcpy(inline_, v.inline_, v.capacity_ * sizeof(T));
dynamic_ = nullptr;
}
// copy over metadata
size_ = v.size_;
capacity_ = v.capacity_;
// null out the original
v.dynamic_ = nullptr;
v.size_ = 0;
v.capacity_ = 0;
}
InlinedVector& operator=(InlinedVector&& v) {
if (this != &v) {
clear();
// if v is allocated, then we steal it's buffer
if (v.dynamic_ != nullptr) {
dynamic_ = v.dynamic_;
} else {
memcpy(inline_, v.inline_, v.capacity_ * sizeof(T));
dynamic_ = nullptr;
}
// copy over metadata
size_ = v.size_;
capacity_ = v.capacity_;
// null out the original
v.dynamic_ = nullptr;
v.size_ = 0;
v.capacity_ = 0;
}
return *this;
}
T* data() {
return dynamic_ != nullptr ? dynamic_ : reinterpret_cast<T*>(inline_);

@ -17,20 +17,30 @@
*/
#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 offset = 0) {
for (int i = 0; i < len; i++) {
v->push_back(i + offset);
EXPECT_EQ(i + 1UL, v->size());
}
}
} // namespace
TEST(InlinedVectorTest, CreateAndIterate) {
const int kNumElements = 9;
InlinedVector<int, 2> v;
EXPECT_TRUE(v.empty());
for (int i = 0; i < kNumElements; ++i) {
v.push_back(i);
}
FillVector(&v, kNumElements);
EXPECT_EQ(static_cast<size_t>(kNumElements), v.size());
EXPECT_FALSE(v.empty());
for (int i = 0; i < kNumElements; ++i) {
@ -42,9 +52,7 @@ TEST(InlinedVectorTest, CreateAndIterate) {
TEST(InlinedVectorTest, ValuesAreInlined) {
const int kNumElements = 5;
InlinedVector<int, 10> v;
for (int i = 0; i < kNumElements; ++i) {
v.push_back(i);
}
FillVector(&v, kNumElements);
EXPECT_EQ(static_cast<size_t>(kNumElements), v.size());
for (int i = 0; i < kNumElements; ++i) {
EXPECT_EQ(i, v[i]);
@ -71,19 +79,13 @@ TEST(InlinedVectorTest, ClearAndRepopulate) {
const int kNumElements = 10;
InlinedVector<int, 5> v;
EXPECT_EQ(0UL, v.size());
for (int i = 0; i < kNumElements; ++i) {
v.push_back(i);
EXPECT_EQ(i + 1UL, v.size());
}
FillVector(&v, kNumElements);
for (int i = 0; i < kNumElements; ++i) {
EXPECT_EQ(i, v[i]);
}
v.clear();
EXPECT_EQ(0UL, v.size());
for (int i = 0; i < kNumElements; ++i) {
v.push_back(kNumElements + i);
EXPECT_EQ(i + 1UL, v.size());
}
FillVector(&v, kNumElements, kNumElements);
for (int i = 0; i < kNumElements; ++i) {
EXPECT_EQ(kNumElements + i, v[i]);
}
@ -93,10 +95,7 @@ TEST(InlinedVectorTest, ConstIndexOperator) {
constexpr int kNumElements = 10;
InlinedVector<int, 5> v;
EXPECT_EQ(0UL, v.size());
for (int i = 0; i < kNumElements; ++i) {
v.push_back(i);
EXPECT_EQ(i + 1UL, 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.
@ -108,6 +107,72 @@ TEST(InlinedVectorTest, ConstIndexOperator) {
const_func(v);
}
TEST(InlinedVectorTest, CopyConstructorAndAssignment) {
typedef InlinedVector<int, 8> IntVec8;
for (size_t len = 0; len < 20; len++) {
IntVec8 original;
FillVector(&original, len);
EXPECT_EQ(len, original.size());
EXPECT_LE(len, original.capacity());
IntVec8 copy_constructed(original);
for (size_t i = 0; i < original.size(); ++i) {
EXPECT_TRUE(original[i] == copy_constructed[i]);
}
for (size_t start_len = 0; start_len < 20; start_len++) {
IntVec8 copy_assigned;
FillVector(&copy_assigned, start_len, 99); // Add dummy elements
copy_assigned = original;
for (size_t i = 0; i < original.size(); ++i) {
EXPECT_TRUE(original[i] == copy_assigned[i]);
}
}
}
}
TEST(InlinedVectorTest, MoveConstructorAndAssignment) {
typedef InlinedVector<int, 8> IntVec8;
for (size_t len = 0; len < 20; len++) {
IntVec8 original;
const size_t inlined_capacity = original.capacity();
FillVector(&original, len);
EXPECT_EQ(len, original.size());
EXPECT_LE(len, original.capacity());
{
IntVec8 tmp(original);
auto* old_data = tmp.data();
IntVec8 move_constructed(std::move(tmp));
for (size_t i = 0; i < original.size(); ++i) {
EXPECT_TRUE(original[i] == move_constructed[i]);
}
if (original.size() > inlined_capacity) {
// Allocation is moved as a whole, data stays in place.
EXPECT_TRUE(move_constructed.data() == old_data);
} else {
EXPECT_FALSE(move_constructed.data() == old_data);
}
}
for (size_t start_len = 0; start_len < 20; start_len++) {
IntVec8 move_assigned;
FillVector(&move_assigned, start_len, 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_TRUE(original[i] == move_assigned[i]);
}
if (original.size() > inlined_capacity) {
// Allocation is moved as a whole, data stays in place.
EXPECT_TRUE(move_assigned.data() == old_data);
} else {
EXPECT_FALSE(move_assigned.data() == old_data);
}
}
}
}
} // namespace testing
} // namespace grpc_core

Loading…
Cancel
Save