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.
This commit is contained in:
Rémi Verschelde
2022-01-10 13:56:55 +01:00
parent 4acc819f9b
commit c6cefb1b79
16 changed files with 129 additions and 52 deletions

View File

@ -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();
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_INDEX_V(p_begin, size(), result);
ERR_FAIL_INDEX_V(p_end, size() + 1, result);
ERR_FAIL_COND_V(begin > end, result);
ERR_FAIL_COND_V(p_begin > p_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;