From ca451d3fa40ebbd35c702ba698e9e5f29e8ed69b Mon Sep 17 00:00:00 2001 From: "Duncan P. N. Exon Smith" Date: Tue, 7 Dec 2021 16:20:18 -0800 Subject: [PATCH] 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 --- llvm/include/llvm/ADT/SmallVector.h | 14 ++++++++++---- llvm/unittests/ADT/SmallVectorTest.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/llvm/include/llvm/ADT/SmallVector.h b/llvm/include/llvm/ADT/SmallVector.h index 1f511b549c13..804567ebe3f1 100644 --- a/llvm/include/llvm/ADT/SmallVector.h +++ b/llvm/include/llvm/ADT/SmallVector.h @@ -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(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() { diff --git a/llvm/unittests/ADT/SmallVectorTest.cpp b/llvm/unittests/ADT/SmallVectorTest.cpp index 06b98efe66ef..3fbea5299501 100644 --- a/llvm/unittests/ADT/SmallVectorTest.cpp +++ b/llvm/unittests/ADT/SmallVectorTest.cpp @@ -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");