2024-07-10 11:56:31 +08:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "irrt_utils.hpp"
|
|
|
|
#include "irrt_typedefs.hpp"
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
struct Slice {
|
2024-07-11 16:54:40 +08:00
|
|
|
SliceIndex start;
|
|
|
|
SliceIndex stop;
|
|
|
|
SliceIndex step;
|
2024-07-10 14:05:08 +08:00
|
|
|
|
|
|
|
// The length/The number of elements of the slice if it were a range,
|
|
|
|
// i.e., the value of `len(range(this->start, this->stop, this->end))`
|
2024-07-11 16:54:40 +08:00
|
|
|
SliceIndex len() {
|
|
|
|
SliceIndex diff = stop - start;
|
2024-07-10 14:05:08 +08:00
|
|
|
if (diff > 0 && step > 0) {
|
|
|
|
return ((diff - 1) / step) + 1;
|
|
|
|
} else if (diff < 0 && step < 0) {
|
|
|
|
return ((diff + 1) / step) + 1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2024-07-10 11:56:31 +08:00
|
|
|
};
|
|
|
|
|
2024-07-11 16:54:40 +08:00
|
|
|
SliceIndex resolve_index_in_length(SliceIndex length, SliceIndex index) {
|
2024-07-10 14:05:08 +08:00
|
|
|
irrt_assert(length >= 0);
|
2024-07-10 11:56:31 +08:00
|
|
|
if (index < 0) {
|
|
|
|
// Remember that index is negative, so do a plus here
|
2024-07-11 16:54:40 +08:00
|
|
|
return max<SliceIndex>(length + index, 0);
|
2024-07-10 11:56:31 +08:00
|
|
|
} else {
|
2024-07-11 16:54:40 +08:00
|
|
|
return min<SliceIndex>(length, index);
|
2024-07-10 11:56:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-11 16:54:40 +08:00
|
|
|
// A user-written Python-like slice.
|
|
|
|
//
|
|
|
|
// i.e., this slice is a triple of either an int or nothing. (e.g., `my_array[:10:2]`, `start` is None)
|
|
|
|
//
|
|
|
|
// You can "resolve" a `UserSlice` by using `UserSlice::indices(<length>)`
|
|
|
|
//
|
2024-07-10 11:56:31 +08:00
|
|
|
// NOTE: using a bitfield for the `*_defined` is better, at the
|
|
|
|
// cost of a more annoying implementation in nac3core inkwell
|
|
|
|
struct UserSlice {
|
2024-07-11 16:54:40 +08:00
|
|
|
// Did the user specify `start`? If 0, `start` is undefined (and contains an empty value)
|
2024-07-10 11:56:31 +08:00
|
|
|
uint8_t start_defined;
|
2024-07-11 16:54:40 +08:00
|
|
|
SliceIndex start;
|
2024-07-10 11:56:31 +08:00
|
|
|
|
2024-07-11 16:54:40 +08:00
|
|
|
// Similar to `start_defined`
|
2024-07-10 11:56:31 +08:00
|
|
|
uint8_t stop_defined;
|
2024-07-11 16:54:40 +08:00
|
|
|
SliceIndex stop;
|
2024-07-10 11:56:31 +08:00
|
|
|
|
2024-07-11 16:54:40 +08:00
|
|
|
// Similar to `start_defined`
|
2024-07-10 11:56:31 +08:00
|
|
|
uint8_t step_defined;
|
2024-07-11 16:54:40 +08:00
|
|
|
SliceIndex step;
|
2024-07-10 11:56:31 +08:00
|
|
|
|
|
|
|
// Like Python's `slice(start, stop, step).indices(length)`
|
2024-07-11 16:54:40 +08:00
|
|
|
Slice indices(SliceIndex length) {
|
2024-07-10 11:56:31 +08:00
|
|
|
// NOTE: This function implements Python's `slice.indices` *FAITHFULLY*.
|
|
|
|
// SEE: https://github.com/python/cpython/blob/f62161837e68c1c77961435f1b954412dd5c2b65/Objects/sliceobject.c#L546
|
2024-07-10 14:05:08 +08:00
|
|
|
irrt_assert(length >= 0);
|
|
|
|
irrt_assert(!step_defined || step != 0); // step_defined -> step != 0; step cannot be zero if specified by user
|
2024-07-10 11:56:31 +08:00
|
|
|
|
2024-07-11 16:54:40 +08:00
|
|
|
Slice result;
|
2024-07-10 11:56:31 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|