From 60116b17b59c5e137924a9669ddc9bbe58a58ef7 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Fri, 27 Aug 2021 00:51:17 +0200 Subject: [PATCH] Add an `Array.pop_at()` method to pop an element at an arbitrary index Negative indices are supported to pop an element relative from the end. --- core/variant/array.cpp | 31 ++++++++++++++++++++++++++++--- core/variant/array.h | 1 + core/variant/variant_call.cpp | 1 + doc/classes/Array.xml | 8 ++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/core/variant/array.cpp b/core/variant/array.cpp index 09cf785390b4..78ad79628310 100644 --- a/core/variant/array.cpp +++ b/core/variant/array.cpp @@ -535,8 +535,8 @@ void Array::push_front(const Variant &p_value) { Variant Array::pop_back() { if (!_p->array.is_empty()) { - int n = _p->array.size() - 1; - Variant ret = _p->array.get(n); + const int n = _p->array.size() - 1; + const Variant ret = _p->array.get(n); _p->array.resize(n); return ret; } @@ -545,13 +545,38 @@ Variant Array::pop_back() { Variant Array::pop_front() { if (!_p->array.is_empty()) { - Variant ret = _p->array.get(0); + const Variant ret = _p->array.get(0); _p->array.remove(0); return ret; } return Variant(); } +Variant Array::pop_at(int p_pos) { + if (_p->array.is_empty()) { + // Return `null` without printing an error to mimic `pop_back()` and `pop_front()` behavior. + return Variant(); + } + + 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(), + Variant(), + vformat( + "The calculated index %s is out of bounds (the array has %s elements). Leaving the array untouched and returning `null`.", + p_pos, + _p->array.size())); + + const Variant ret = _p->array.get(p_pos); + _p->array.remove(p_pos); + return ret; +} + Variant Array::min() const { Variant minval; for (int i = 0; i < size(); i++) { diff --git a/core/variant/array.h b/core/variant/array.h index 540dcb1f4e91..e9634cceceb7 100644 --- a/core/variant/array.h +++ b/core/variant/array.h @@ -97,6 +97,7 @@ class Array { void push_front(const Variant &p_value); Variant pop_back(); Variant pop_front(); + Variant pop_at(int p_pos); Array duplicate(bool p_deep = false) const; diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index a4817eb7d27f..382b256c086b 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1807,6 +1807,7 @@ static void _register_variant_builtin_methods() { bind_method(Array, has, sarray("value"), varray()); bind_method(Array, pop_back, sarray(), varray()); bind_method(Array, pop_front, sarray(), varray()); + bind_method(Array, pop_at, sarray("position"), varray()); bind_method(Array, sort, sarray(), varray()); bind_method(Array, sort_custom, sarray("func"), varray()); bind_method(Array, shuffle, sarray(), varray()); diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml index 7767a1028de3..df0e3a04595a 100644 --- a/doc/classes/Array.xml +++ b/doc/classes/Array.xml @@ -393,6 +393,14 @@ + + + + + Removes and returns the element of the array at index [code]position[/code]. If negative, [code]position[/code] is considered relative to the end of the array. Leaves the array untouched and returns [code]null[/code] if the array is empty or if it's accessed out of bounds. An error message is printed when the array is accessed out of bounds, but not when the array is empty. + [b]Note:[/b] On large arrays, this method can be slower than [method pop_back] as it will reindex the array's elements that are located after the removed element. The larger the array and the lower the index of the removed element, the slower [method pop_at] will be. + +