ADT: Add SmallVectorImpl::truncate() to replace uses of set_size()

Add `SmallVectorImpl::truncate()`, a variant of `resize()` that cannot
increase the size.

- Compared to `resize()`, this has no code path for growing the
  allocation and can be better optimized.
- Compared to `set_size()`, this formally calls destructors, and does
  not skip any constructors.
- Compared to `pop_back_n()`, this takes the new desired size, which in
  many contexts is more intuitive than the number of elements to remove.

The immediate motivation is to pair this with `resize_for_overwrite()`
to remove uses of `set_size()`, which can then be made private.

Differential Revision: https://reviews.llvm.org/D115383
This commit is contained in:
Duncan P. N. Exon Smith 2021-12-07 16:20:18 -08:00
parent 1225c8a061
commit ca451d3fa4
2 changed files with 36 additions and 4 deletions

View File

@ -593,7 +593,7 @@ private:
return;
if (N < this->size()) {
this->pop_back_n(this->size() - N);
this->truncate(N);
return;
}
@ -612,12 +612,19 @@ public:
/// Like resize, but \ref T is POD, the new values won't be initialized.
void resize_for_overwrite(size_type N) { resizeImpl<true>(N); }
/// Like resize, but requires that \p N is less than \a size().
void truncate(size_type N) {
assert(this->size() >= N && "Cannot increase size with truncate");
this->destroy_range(this->begin() + N, this->end());
this->set_size(N);
}
void resize(size_type N, ValueParamT NV) {
if (N == this->size())
return;
if (N < this->size()) {
this->pop_back_n(this->size() - N);
this->truncate(N);
return;
}
@ -632,8 +639,7 @@ public:
void pop_back_n(size_type NumItems) {
assert(this->size() >= NumItems);
this->destroy_range(this->end() - NumItems, this->end());
this->set_size(this->size() - NumItems);
truncate(this->size() - NumItems);
}
LLVM_NODISCARD T pop_back_val() {

View File

@ -309,6 +309,32 @@ TYPED_TEST(SmallVectorTest, ResizeShrinkTest) {
EXPECT_EQ(5, Constructable::getNumDestructorCalls());
}
// Truncate test.
TYPED_TEST(SmallVectorTest, TruncateTest) {
SCOPED_TRACE("TruncateTest");
this->theVector.reserve(3);
this->makeSequence(this->theVector, 1, 3);
this->theVector.truncate(1);
this->assertValuesInOrder(this->theVector, 1u, 1);
EXPECT_EQ(6, Constructable::getNumConstructorCalls());
EXPECT_EQ(5, Constructable::getNumDestructorCalls());
#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
EXPECT_DEATH(this->theVector.truncate(2), "Cannot increase size");
#endif
this->theVector.truncate(1);
this->assertValuesInOrder(this->theVector, 1u, 1);
EXPECT_EQ(6, Constructable::getNumConstructorCalls());
EXPECT_EQ(5, Constructable::getNumDestructorCalls());
this->theVector.truncate(0);
this->assertEmpty(this->theVector);
EXPECT_EQ(6, Constructable::getNumConstructorCalls());
EXPECT_EQ(6, Constructable::getNumDestructorCalls());
}
// Resize bigger test.
TYPED_TEST(SmallVectorTest, ResizeGrowTest) {
SCOPED_TRACE("ResizeGrowTest");