@az0uz/zarr
Version:
Javascript implementation of Zarr
111 lines • 3.48 kB
JavaScript
import { InvalidSliceError } from '../errors';
export function slice(start, stop = undefined, step = null) {
// tslint:disable-next-line: strict-type-predicates
if (start === undefined) { // Not possible in typescript
throw new InvalidSliceError(start, stop, step, "The first argument must not be undefined");
}
if ((typeof start === "string" && start !== ":") || (typeof stop === "string" && stop !== ":")) { // Note in typescript this will never happen with type checking.
throw new InvalidSliceError(start, stop, step, "Arguments can only be integers, \":\" or null");
}
// slice(5) === slice(null, 5)
if (stop === undefined) {
stop = start;
start = null;
}
// if (start !== null && stop !== null && start > stop) {
// throw new InvalidSliceError(start, stop, step, "to is higher than from");
// }
return {
start: start === ":" ? null : start,
stop: stop === ":" ? null : stop,
step,
_slice: true,
};
}
/**
* Port of adjustIndices
* https://github.com/python/cpython/blob/master/Objects/sliceobject.c#L243
*/
function adjustIndices(start, stop, step, length) {
if (start < 0) {
start += length;
if (start < 0) {
start = (step < 0) ? -1 : 0;
}
}
else if (start >= length) {
start = (step < 0) ? length - 1 : length;
}
if (stop < 0) {
stop += length;
if (stop < 0) {
stop = (step < 0) ? -1 : 0;
}
}
else if (stop >= length) {
stop = (step < 0) ? length - 1 : length;
}
if (step < 0) {
if (stop < start) {
const length = Math.floor((start - stop - 1) / (-step) + 1);
return [start, stop, step, length];
}
}
else {
if (start < stop) {
const length = Math.floor((stop - start - 1) / step + 1);
return [start, stop, step, length];
}
}
return [start, stop, step, 0];
}
/**
* Port of slice.indices(n) and PySlice_Unpack
* https://github.com/python/cpython/blob/master/Objects/sliceobject.c#L166
* https://github.com/python/cpython/blob/master/Objects/sliceobject.c#L198
*
* Behaviour might be slightly different as it's a weird hybrid implementation.
*/
export function sliceIndices(slice, length) {
let start;
let stop;
let step;
if (slice.step === null) {
step = 1;
}
else {
step = slice.step;
}
if (slice.start === null) {
start = step < 0 ? Number.MAX_SAFE_INTEGER : 0;
}
else {
start = slice.start;
if (start < 0) {
start += length;
}
}
if (slice.stop === null) {
stop = step < 0 ? -Number.MAX_SAFE_INTEGER : Number.MAX_SAFE_INTEGER;
}
else {
stop = slice.stop;
if (stop < 0) {
stop += length;
}
}
// This clips out of bounds slices
const s = adjustIndices(start, stop, step, length);
start = s[0];
stop = s[1];
step = s[2];
// The output length
length = s[3];
// With out of bounds slicing these two assertions are not useful.
// if (stop > length) throw new Error("Stop greater than length");
// if (start >= length) throw new Error("Start greater than or equal to length");
if (step === 0)
throw new Error("Step size 0 is invalid");
return [start, stop, step, length];
}
//# sourceMappingURL=slice.js.map