forked from M-Labs/nac3
65 lines
1.9 KiB
C++
65 lines
1.9 KiB
C++
|
#pragma once
|
||
|
|
||
|
#include "irrt_utils.hpp"
|
||
|
#include "irrt_typedefs.hpp"
|
||
|
|
||
|
namespace {
|
||
|
// A proper slice in IRRT, all negative indices have be resolved to absolute values.
|
||
|
template <typename T>
|
||
|
struct Slice {
|
||
|
T start;
|
||
|
T stop;
|
||
|
T step;
|
||
|
};
|
||
|
|
||
|
template<typename T>
|
||
|
T resolve_index_in_length(T length, T index) {
|
||
|
nac3_assert(length >= 0);
|
||
|
if (index < 0) {
|
||
|
// Remember that index is negative, so do a plus here
|
||
|
return max(length + index, 0);
|
||
|
} else {
|
||
|
return min(length, index);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NOTE: using a bitfield for the `*_defined` is better, at the
|
||
|
// cost of a more annoying implementation in nac3core inkwell
|
||
|
template <typename T>
|
||
|
struct UserSlice {
|
||
|
uint8_t start_defined;
|
||
|
T start;
|
||
|
|
||
|
uint8_t stop_defined;
|
||
|
T stop;
|
||
|
|
||
|
uint8_t step_defined;
|
||
|
T step;
|
||
|
|
||
|
// Like Python's `slice(start, stop, step).indices(length)`
|
||
|
Slice<T> indices(T length) {
|
||
|
// NOTE: This function implements Python's `slice.indices` *FAITHFULLY*.
|
||
|
// SEE: https://github.com/python/cpython/blob/f62161837e68c1c77961435f1b954412dd5c2b65/Objects/sliceobject.c#L546
|
||
|
nac3_assert(length >= 0);
|
||
|
nac3_assert(!step_defined || step != 0); // step_defined -> step != 0; step cannot be zero if specified by user
|
||
|
|
||
|
Slice<T> result;
|
||
|
result.step = step_defined ? step : 1;
|
||
|
bool step_is_negative = result.step < 0;
|
||
|
|
||
|
if (start_defined) {
|
||
|
result.start = resolve_index_in_length(length, start);
|
||
|
} else {
|
||
|
result.start = step_is_negative ? length - 1 : 0;
|
||
|
}
|
||
|
|
||
|
if (stop_defined) {
|
||
|
result.stop = resolve_index_in_length(length, stop);
|
||
|
} else {
|
||
|
result.stop = step_is_negative ? -1 : length;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
};
|
||
|
}
|