Commit 56495410 authored by Marius Wachtler's avatar Marius Wachtler

Use CPythons PySlice_GetIndicesEx it handles non int slices

parent 578f9b6a
......@@ -956,16 +956,61 @@ extern "C" int PySlice_GetIndices(PySliceObject* r, Py_ssize_t length, Py_ssize_
extern "C" int PySlice_GetIndicesEx(PySliceObject* _r, Py_ssize_t length, Py_ssize_t* start, Py_ssize_t* stop,
Py_ssize_t* step, Py_ssize_t* slicelength) noexcept {
try {
BoxedSlice* r = (BoxedSlice*)_r;
assert(r->cls == slice_cls);
// parseSlice has the exact same behaviour as CPythons PySlice_GetIndicesEx apart from throwing c++ exceptions
// on error.
parseSlice(r, length, start, stop, step, slicelength);
} catch (ExcInfo e) {
setCAPIException(e);
RELEASE_ASSERT(r->cls == slice_cls, "");
/* this is harder to get right than you might think */
Py_ssize_t defstart, defstop;
if (r->step == Py_None) {
*step = 1;
} else {
if (!_PyEval_SliceIndex(r->step, step))
return -1;
if (*step == 0) {
PyErr_SetString(PyExc_ValueError, "slice step cannot be zero");
return -1;
}
}
defstart = *step < 0 ? length - 1 : 0;
defstop = *step < 0 ? -1 : length;
if (r->start == Py_None) {
*start = defstart;
} else {
if (!_PyEval_SliceIndex(r->start, start))
return -1;
if (*start < 0)
*start += length;
if (*start < 0)
*start = (*step < 0) ? -1 : 0;
if (*start >= length)
*start = (*step < 0) ? length - 1 : length;
}
if (r->stop == Py_None) {
*stop = defstop;
} else {
if (!_PyEval_SliceIndex(r->stop, stop))
return -1;
if (*stop < 0)
*stop += length;
if (*stop < 0)
*stop = (*step < 0) ? -1 : 0;
if (*stop >= length)
*stop = (*step < 0) ? length - 1 : length;
}
if ((*step < 0 && *stop >= *start) || (*step > 0 && *start >= *stop)) {
*slicelength = 0;
} else if (*step < 0) {
*slicelength = (*stop - *start + 1) / (*step) + 1;
} else {
*slicelength = (*stop - *start - 1) / (*step) + 1;
}
return 0;
}
......
......@@ -15,84 +15,15 @@
#include "runtime/util.h"
#include "core/options.h"
#include "runtime/capi.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
namespace pyston {
// Provides the exact same behaviour as CPythons PySlice_GetIndicesEx apart from throwing c++ exceptions on error
void parseSlice(BoxedSlice* slice, int size, i64* out_start, i64* out_stop, i64* out_step, i64* out_length) {
BoxedSlice* sslice = static_cast<BoxedSlice*>(slice);
Box* start = sslice->start;
assert(start);
Box* stop = sslice->stop;
assert(stop);
Box* step = sslice->step;
assert(step);
RELEASE_ASSERT(isSubclass(start->cls, int_cls) || start->cls == none_cls, "");
RELEASE_ASSERT(isSubclass(stop->cls, int_cls) || stop->cls == none_cls, "");
RELEASE_ASSERT(isSubclass(step->cls, int_cls) || step->cls == none_cls, "");
int64_t istart;
int64_t istop;
int64_t istep = 1;
if (isSubclass(step->cls, int_cls)) {
istep = static_cast<BoxedInt*>(step)->n;
if (istep == 0) {
raiseExcHelper(ValueError, "slice step cannot be zero");
}
}
if (isSubclass(start->cls, int_cls)) {
istart = static_cast<BoxedInt*>(start)->n;
if (istart < 0)
istart = size + istart;
} else {
if (istep > 0)
istart = 0;
else
istart = size - 1;
}
if (isSubclass(stop->cls, int_cls)) {
istop = static_cast<BoxedInt*>(stop)->n;
if (istop < 0)
istop = size + istop;
} else {
if (istep > 0)
istop = size;
else
istop = -1;
}
if (istep > 0) {
if (istart < 0)
istart = 0;
if (istop > size)
istop = size;
} else {
if (istart >= size)
istart = size - 1;
if (istop < 0)
istop = -1;
}
*out_start = istart;
*out_stop = istop;
*out_step = istep;
if (out_length) {
// This is adapted from CPython's PySlice_GetIndicesEx.
if ((istep < 0 && istop >= istart) || (istep > 0 && istart >= istop))
*out_length = 0;
else if (istep < 0)
*out_length = (istop - istart + 1) / istep + 1;
else
*out_length = (istop - istart - 1) / istep + 1;
RELEASE_ASSERT(*out_length >= 0, "negative length, should never happen");
}
int ret = PySlice_GetIndicesEx((PySliceObject*)slice, size, out_start, out_stop, out_step, out_length);
if (ret == -1)
throwCAPIException();
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment