summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2022-01-10 13:56:55 +0100
committerRémi Verschelde <rverschelde@gmail.com>2022-01-10 22:42:03 +0100
commitc6cefb1b79d207af1bc78ce20c01b5788e806252 (patch)
treeca713ba3bf904b57a7408ec50029c9fbcc275d40 /core
parent4acc819f9bafacf5f912caf5ba2ebc15f70e3dbb (diff)
`Array`: Relax `slice` bound checks to properly handle negative indices
The same is done for `Vector` (and thus `Packed*Array`). `begin` and `end` can now take any value and will be clamped to `[-size(), size()]`. Negative values are a shorthand for indexing the array from the last element upward. `end` is given a default `INT_MAX` value (which will be clamped to `size()`) so that the `end` parameter can be omitted to go from `begin` to the max size of the array. This makes `slice` works similarly to numpy's and JavaScript's.
Diffstat (limited to 'core')
-rw-r--r--core/templates/vector.h23
-rw-r--r--core/variant/array.cpp22
-rw-r--r--core/variant/array.h4
-rw-r--r--core/variant/variant_call.cpp20
4 files changed, 40 insertions, 29 deletions
diff --git a/core/templates/vector.h b/core/templates/vector.h
index 4ada3b597a..d1408125c8 100644
--- a/core/templates/vector.h
+++ b/core/templates/vector.h
@@ -43,6 +43,7 @@
#include "core/templates/search_array.h"
#include "core/templates/sort_array.h"
+#include <climits>
#include <initializer_list>
template <class T>
@@ -145,25 +146,29 @@ public:
return ret;
}
- Vector<T> slice(int p_begin, int p_end) const {
+ Vector<T> slice(int p_begin, int p_end = INT_MAX) const {
Vector<T> result;
- if (p_end < 0) {
- p_end += size() + 1;
- }
+ const int s = size();
- ERR_FAIL_INDEX_V(p_begin, size(), result);
- ERR_FAIL_INDEX_V(p_end, size() + 1, result);
+ int begin = CLAMP(p_begin, -s, s);
+ if (begin < 0) {
+ begin += s;
+ }
+ int end = CLAMP(p_end, -s, s);
+ if (end < 0) {
+ end += s;
+ }
- ERR_FAIL_COND_V(p_begin > p_end, result);
+ ERR_FAIL_COND_V(begin > end, result);
- int result_size = p_end - p_begin;
+ int result_size = end - begin;
result.resize(result_size);
const T *const r = ptr();
T *const w = result.ptrw();
for (int i = 0; i < result_size; ++i) {
- w[i] = r[p_begin + i];
+ w[i] = r[begin + i];
}
return result;
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
index 8d20b1bc79..3d2f337442 100644
--- a/core/variant/array.cpp
+++ b/core/variant/array.cpp
@@ -370,20 +370,24 @@ Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const {
ERR_FAIL_COND_V_MSG(p_step == 0, result, "Slice step cannot be zero.");
- if (p_end < 0) {
- p_end += size() + 1;
- }
+ const int s = size();
- ERR_FAIL_INDEX_V(p_begin, size(), result);
- ERR_FAIL_INDEX_V(p_end, size() + 1, result);
+ int begin = CLAMP(p_begin, -s, s);
+ if (begin < 0) {
+ begin += s;
+ }
+ int end = CLAMP(p_end, -s, s);
+ if (end < 0) {
+ end += s;
+ }
- ERR_FAIL_COND_V_MSG(p_step > 0 && p_begin > p_end, result, "Slice is positive, but bounds is decreasing");
- ERR_FAIL_COND_V_MSG(p_step < 0 && p_begin < p_end, result, "Slice is negative, but bounds is increasing");
+ ERR_FAIL_COND_V_MSG(p_step > 0 && begin > end, result, "Slice is positive, but bounds is decreasing.");
+ ERR_FAIL_COND_V_MSG(p_step < 0 && begin < end, result, "Slice is negative, but bounds is increasing.");
- int result_size = (p_end - p_begin) / p_step;
+ int result_size = (end - begin) / p_step;
result.resize(result_size);
- for (int src_idx = p_begin, dest_idx = 0; dest_idx < result_size; ++dest_idx) {
+ for (int src_idx = begin, dest_idx = 0; dest_idx < result_size; ++dest_idx) {
result[dest_idx] = p_deep ? get(src_idx).duplicate(true) : get(src_idx);
src_idx += p_step;
}
diff --git a/core/variant/array.h b/core/variant/array.h
index f48444bb39..72bed5932c 100644
--- a/core/variant/array.h
+++ b/core/variant/array.h
@@ -33,6 +33,8 @@
#include "core/typedefs.h"
+#include <climits>
+
class Variant;
class ArrayPrivate;
class Object;
@@ -102,7 +104,7 @@ public:
Array duplicate(bool p_deep = false) const;
Array recursive_duplicate(bool p_deep, int recursion_count) const;
- Array slice(int p_begin, int p_end, int p_step = 1, bool p_deep = false) const;
+ Array slice(int p_begin, int p_end = INT_MAX, int p_step = 1, bool p_deep = false) const;
Array filter(const Callable &p_callable) const;
Array map(const Callable &p_callable) const;
Variant reduce(const Callable &p_callable, const Variant &p_accum) const;
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index ecf5009fb6..8dd48a4c28 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1838,7 +1838,7 @@ static void _register_variant_builtin_methods() {
bind_method(Array, bsearch_custom, sarray("value", "func", "before"), varray(true));
bind_method(Array, reverse, sarray(), varray());
bind_method(Array, duplicate, sarray("deep"), varray(false));
- bind_method(Array, slice, sarray("begin", "end", "step", "deep"), varray(1, false));
+ bind_method(Array, slice, sarray("begin", "end", "step", "deep"), varray(INT_MAX, 1, false));
bind_method(Array, filter, sarray("method"), varray());
bind_method(Array, map, sarray("method"), varray());
bind_method(Array, reduce, sarray("method", "accum"), varray(Variant()));
@@ -1858,7 +1858,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedByteArray, resize, sarray("new_size"), varray());
bind_method(PackedByteArray, has, sarray("value"), varray());
bind_method(PackedByteArray, reverse, sarray(), varray());
- bind_method(PackedByteArray, slice, sarray("begin", "end"), varray());
+ bind_method(PackedByteArray, slice, sarray("begin", "end"), varray(INT_MAX));
bind_method(PackedByteArray, sort, sarray(), varray());
bind_method(PackedByteArray, bsearch, sarray("value", "before"), varray(true));
bind_method(PackedByteArray, duplicate, sarray(), varray());
@@ -1919,7 +1919,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedInt32Array, resize, sarray("new_size"), varray());
bind_method(PackedInt32Array, has, sarray("value"), varray());
bind_method(PackedInt32Array, reverse, sarray(), varray());
- bind_method(PackedInt32Array, slice, sarray("begin", "end"), varray());
+ bind_method(PackedInt32Array, slice, sarray("begin", "end"), varray(INT_MAX));
bind_method(PackedInt32Array, to_byte_array, sarray(), varray());
bind_method(PackedInt32Array, sort, sarray(), varray());
bind_method(PackedInt32Array, bsearch, sarray("value", "before"), varray(true));
@@ -1939,7 +1939,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedInt64Array, resize, sarray("new_size"), varray());
bind_method(PackedInt64Array, has, sarray("value"), varray());
bind_method(PackedInt64Array, reverse, sarray(), varray());
- bind_method(PackedInt64Array, slice, sarray("begin", "end"), varray());
+ bind_method(PackedInt64Array, slice, sarray("begin", "end"), varray(INT_MAX));
bind_method(PackedInt64Array, to_byte_array, sarray(), varray());
bind_method(PackedInt64Array, sort, sarray(), varray());
bind_method(PackedInt64Array, bsearch, sarray("value", "before"), varray(true));
@@ -1959,7 +1959,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedFloat32Array, resize, sarray("new_size"), varray());
bind_method(PackedFloat32Array, has, sarray("value"), varray());
bind_method(PackedFloat32Array, reverse, sarray(), varray());
- bind_method(PackedFloat32Array, slice, sarray("begin", "end"), varray());
+ bind_method(PackedFloat32Array, slice, sarray("begin", "end"), varray(INT_MAX));
bind_method(PackedFloat32Array, to_byte_array, sarray(), varray());
bind_method(PackedFloat32Array, sort, sarray(), varray());
bind_method(PackedFloat32Array, bsearch, sarray("value", "before"), varray(true));
@@ -1979,7 +1979,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedFloat64Array, resize, sarray("new_size"), varray());
bind_method(PackedFloat64Array, has, sarray("value"), varray());
bind_method(PackedFloat64Array, reverse, sarray(), varray());
- bind_method(PackedFloat64Array, slice, sarray("begin", "end"), varray());
+ bind_method(PackedFloat64Array, slice, sarray("begin", "end"), varray(INT_MAX));
bind_method(PackedFloat64Array, to_byte_array, sarray(), varray());
bind_method(PackedFloat64Array, sort, sarray(), varray());
bind_method(PackedFloat64Array, bsearch, sarray("value", "before"), varray(true));
@@ -1999,7 +1999,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedStringArray, resize, sarray("new_size"), varray());
bind_method(PackedStringArray, has, sarray("value"), varray());
bind_method(PackedStringArray, reverse, sarray(), varray());
- bind_method(PackedStringArray, slice, sarray("begin", "end"), varray());
+ bind_method(PackedStringArray, slice, sarray("begin", "end"), varray(INT_MAX));
bind_method(PackedStringArray, to_byte_array, sarray(), varray());
bind_method(PackedStringArray, sort, sarray(), varray());
bind_method(PackedStringArray, bsearch, sarray("value", "before"), varray(true));
@@ -2019,7 +2019,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedVector2Array, resize, sarray("new_size"), varray());
bind_method(PackedVector2Array, has, sarray("value"), varray());
bind_method(PackedVector2Array, reverse, sarray(), varray());
- bind_method(PackedVector2Array, slice, sarray("begin", "end"), varray());
+ bind_method(PackedVector2Array, slice, sarray("begin", "end"), varray(INT_MAX));
bind_method(PackedVector2Array, to_byte_array, sarray(), varray());
bind_method(PackedVector2Array, sort, sarray(), varray());
bind_method(PackedVector2Array, bsearch, sarray("value", "before"), varray(true));
@@ -2039,7 +2039,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedVector3Array, resize, sarray("new_size"), varray());
bind_method(PackedVector3Array, has, sarray("value"), varray());
bind_method(PackedVector3Array, reverse, sarray(), varray());
- bind_method(PackedVector3Array, slice, sarray("begin", "end"), varray());
+ bind_method(PackedVector3Array, slice, sarray("begin", "end"), varray(INT_MAX));
bind_method(PackedVector3Array, to_byte_array, sarray(), varray());
bind_method(PackedVector3Array, sort, sarray(), varray());
bind_method(PackedVector3Array, bsearch, sarray("value", "before"), varray(true));
@@ -2059,7 +2059,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedColorArray, resize, sarray("new_size"), varray());
bind_method(PackedColorArray, has, sarray("value"), varray());
bind_method(PackedColorArray, reverse, sarray(), varray());
- bind_method(PackedColorArray, slice, sarray("begin", "end"), varray());
+ bind_method(PackedColorArray, slice, sarray("begin", "end"), varray(INT_MAX));
bind_method(PackedColorArray, to_byte_array, sarray(), varray());
bind_method(PackedColorArray, sort, sarray(), varray());
bind_method(PackedColorArray, bsearch, sarray("value", "before"), varray(true));