8376570: GrowableArray::remove_{till,range} should work on empty list

Reviewed-by: kbarrett, iwalulya
This commit is contained in:
Aleksey Shipilev 2026-02-02 10:32:51 +00:00
parent 90a43f8445
commit e370b8a1d8
2 changed files with 122 additions and 7 deletions

View File

@ -493,16 +493,16 @@ public:
return false;
}
// Remove all elements up to the index (exclusive). The order is preserved.
void remove_till(int idx) {
remove_range(0, idx);
// Remove all elements in the range [0; end). The order is preserved.
void remove_till(int end) {
remove_range(0, end);
}
// Remove all elements in the range [start - end). The order is preserved.
// Remove all elements in the range [start; end). The order is preserved.
void remove_range(int start, int end) {
assert(0 <= start, "illegal start index %d", start);
assert(start < end && end <= this->_len,
"erase called with invalid range (%d, %d) for length %d",
assert(start <= end && end <= this->_len,
"erase called with invalid range [%d, %d) for length %d",
start, end, this->_len);
for (int i = start, j = end; j < this->length(); i++, j++) {

View File

@ -232,12 +232,111 @@ protected:
}
}
template <typename ArrayClass>
static void test_remove_range(ArrayClass* a) {
// Seed initial
for (int i = 0; i < 10; i++) {
a->append(i);
}
ASSERT_EQ(a->length(), 10);
// Remove empty range from the non-empty list, should not modify the list.
a->remove_range(0, 0);
ASSERT_EQ(a->length(), 10);
// Remove one element from head, should result in [1 ... 9]
a->remove_range(0, 1);
ASSERT_EQ(a->length(), 9);
for (int i = 0; i < a->length(); i++) {
ASSERT_EQ(a->at(i), i + 1);
}
// Remove one element from tail, should result in [1 ... 8]
a->remove_range(8, 9);
ASSERT_EQ(a->length(), 8);
for (int i = 0; i < a->length(); i++) {
ASSERT_EQ(a->at(i), i + 1);
}
// Remove another empty range from the non-empty list, should not modify
a->remove_range(1, 1);
ASSERT_EQ(a->length(), 8);
// Remove some elements from the middle, should result in [1 2 7 8]
a->remove_range(2, 6);
ASSERT_EQ(a->length(), 4);
ASSERT_EQ(a->at(0), 1);
ASSERT_EQ(a->at(1), 2);
ASSERT_EQ(a->at(2), 7);
ASSERT_EQ(a->at(3), 8);
// Remove the rest of the elements one by one
a->remove_range(0, 1);
ASSERT_EQ(a->length(), 3);
ASSERT_EQ(a->at(0), 2);
ASSERT_EQ(a->at(1), 7);
ASSERT_EQ(a->at(2), 8);
a->remove_range(0, 1);
ASSERT_EQ(a->length(), 2);
ASSERT_EQ(a->at(0), 7);
ASSERT_EQ(a->at(1), 8);
a->remove_range(0, 1);
ASSERT_EQ(a->length(), 1);
ASSERT_EQ(a->at(0), 8);
a->remove_range(0, 1);
ASSERT_EQ(a->length(), 0);
// Remove elements from empty list with empty range, should be accepted
a->remove_range(0, 0);
ASSERT_EQ(a->length(), 0);
}
template <typename ArrayClass>
static void test_remove_till(ArrayClass* a) {
// Seed initial
for (int i = 0; i < 10; i++) {
a->append(i);
}
ASSERT_EQ(a->length(), 10);
// Remove empty range from non-empty list, should work
a->remove_till(0);
ASSERT_EQ(a->length(), 10);
// Remove one element from head, should result in [1 ... 9]
a->remove_till(1);
ASSERT_EQ(a->length(), 9);
for (int i = 0; i < a->length(); i++) {
ASSERT_EQ(a->at(i), i + 1);
}
// Remove two elements from head, should result in [3 ... 9]
a->remove_till(2);
ASSERT_EQ(a->length(), 7);
for (int i = 0; i < a->length(); i++) {
ASSERT_EQ(a->at(i), i + 3);
}
// Remove remaining elements, should result in []
a->remove_till(a->length());
ASSERT_EQ(a->length(), 0);
// Remove empty range from empty list, should work
a->remove_till(0);
ASSERT_EQ(a->length(), 0);
}
// Supported by all GrowableArrays
enum TestEnum {
Append,
Clear,
Capacity,
Iterator
Iterator,
RemoveRange,
RemoveTill
};
template <typename ArrayClass>
@ -259,6 +358,14 @@ protected:
test_iterator(a);
break;
case RemoveRange:
test_remove_range(a);
break;
case RemoveTill:
test_remove_till(a);
break;
default:
fatal("Missing dispatch");
break;
@ -451,6 +558,14 @@ TEST_VM_F(GrowableArrayTest, iterator) {
with_all_types_all_0(Iterator);
}
TEST_VM_F(GrowableArrayTest, remove_range) {
with_all_types_all_0(RemoveRange);
}
TEST_VM_F(GrowableArrayTest, remove_till) {
with_all_types_all_0(RemoveTill);
}
TEST_VM_F(GrowableArrayTest, copy) {
with_no_cheap_array_append1(Copy1);
}