Skip to content

Commit

Permalink
Add negative index to Array.remove_at and Array.insert
Browse files Browse the repository at this point in the history
  • Loading branch information
rarysson committed Oct 11, 2023
1 parent 6916349 commit c110a3e
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 3 deletions.
29 changes: 29 additions & 0 deletions core/variant/array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,21 @@ Error Array::insert(int p_pos, const Variant &p_value) {
ERR_FAIL_COND_V_MSG(_p->read_only, ERR_LOCKED, "Array is in read-only state.");
Variant value = p_value;
ERR_FAIL_COND_V(!_p->typed.validate(value, "insert"), ERR_INVALID_PARAMETER);

if (p_pos < 0) {
// Relative offset from the end.
p_pos = _p->array.size() + p_pos;
}

ERR_FAIL_INDEX_V_MSG(
p_pos,
_p->array.size(),
ERR_INVALID_PARAMETER,
vformat(
"The calculated index %i is out of bounds (the array has %i elements). Leaving the array untouched.",
p_pos,
_p->array.size()));

return _p->array.insert(p_pos, value);
}

Expand Down Expand Up @@ -404,6 +419,20 @@ bool Array::has(const Variant &p_value) const {

void Array::remove_at(int p_pos) {
ERR_FAIL_COND_MSG(_p->read_only, "Array is in read-only state.");

if (p_pos < 0) {
// Relative offset from the end.
p_pos = _p->array.size() + p_pos;
}

ERR_FAIL_INDEX_MSG(
p_pos,
_p->array.size(),
vformat(
"The calculated index %i is out of bounds (the array has %i elements). Leaving the array untouched.",
p_pos,
_p->array.size()));

_p->array.remove_at(p_pos);
}

Expand Down
5 changes: 2 additions & 3 deletions doc/classes/Array.xml
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@
<param index="0" name="position" type="int" />
<param index="1" name="value" type="Variant" />
<description>
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]pos == size()[/code]). Returns [constant OK] on success, or one of the other [enum Error] values if the operation failed.
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]pos == size()[/code]). If negative, [param position] is considered relative to the end of the array. Returns [constant OK] on success, or one of the other [enum Error] values if the operation failed.
[b]Note:[/b] This method acts in-place and doesn't return a modified array.
[b]Note:[/b] On large arrays, this method will be slower if the inserted element is close to the beginning of the array (index 0). This is because all elements placed after the newly inserted element have to be reindexed.
</description>
Expand Down Expand Up @@ -533,10 +533,9 @@
<return type="void" />
<param index="0" name="position" type="int" />
<description>
Removes an element from the array by index. If the index does not exist in the array, nothing happens. To remove an element by searching for its value, use [method erase] instead.
Removes an element from the array by index. If the index does not exist in the array, nothing happens. If negative, [param position] is considered relative to the end of the array. To remove an element by searching for its value, use [method erase] instead.
[b]Note:[/b] This method acts in-place and doesn't return a modified array.
[b]Note:[/b] On large arrays, this method will be slower if the removed element is close to the beginning of the array (index 0). This is because all elements placed after the removed element have to be reindexed.
[b]Note:[/b] [param position] cannot be negative. To remove an element relative to the end of the array, use [code]arr.remove_at(arr.size() - (i + 1))[/code]. To remove the last element from the array without returning the value, use [code]arr.resize(arr.size() - 1)[/code].
</description>
</method>
<method name="resize">
Expand Down
15 changes: 15 additions & 0 deletions tests/core/variant/test_array.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ TEST_CASE("[Array] resize(), insert(), and erase()") {
CHECK(int(arr[0]) == 2);
arr.erase(2);
CHECK(int(arr[0]) == 1);

// Negative index on insert.
CHECK(arr.size() == 3);
arr.insert(-1, 3);
CHECK(int(arr[2]) == 3);
CHECK(arr.size() == 4);
}

TEST_CASE("[Array] front() and back()") {
Expand Down Expand Up @@ -139,6 +145,15 @@ TEST_CASE("[Array] remove_at()") {
arr.remove_at(0);
CHECK(arr.size() == 0);

// Negative index.
arr.push_back(3);
arr.push_back(4);
arr.remove_at(-1);
CHECK(arr.size() == 1);
CHECK(int(arr[0]) == 3);
arr.remove_at(-1);
CHECK(arr.size() == 0);

// The array is now empty; try to use `remove_at()` again.
// Normally, this prints an error message so we silence it.
ERR_PRINT_OFF;
Expand Down

0 comments on commit c110a3e

Please sign in to comment.