Commit 5bd967f2 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Optimize PySequence_GetSlice

- copy CPython's implementation (that uses C slots)
- implement the C slots for str and list
- avoid doing a division for non-step slices
parent 36581431
...@@ -1441,14 +1441,55 @@ extern "C" PyObject* PySequence_GetItem(PyObject* o, Py_ssize_t i) noexcept { ...@@ -1441,14 +1441,55 @@ extern "C" PyObject* PySequence_GetItem(PyObject* o, Py_ssize_t i) noexcept {
} }
} }
extern "C" PyObject* PySequence_GetSlice(PyObject* o, Py_ssize_t i1, Py_ssize_t i2) noexcept { PyObject* _PySlice_FromIndices(Py_ssize_t istart, Py_ssize_t istop) {
try { PyObject* start, *end, *slice;
// Not sure if this is really the same: start = PyInt_FromSsize_t(istart);
return getitem(o, createSlice(boxInt(i1), boxInt(i2), None)); if (!start)
} catch (ExcInfo e) { return NULL;
fatalOrError(PyExc_NotImplementedError, "unimplemented"); end = PyInt_FromSsize_t(istop);
return nullptr; if (!end) {
Py_DECREF(start);
return NULL;
} }
slice = PySlice_New(start, end, NULL);
Py_DECREF(start);
Py_DECREF(end);
return slice;
}
extern "C" PyObject* PySequence_GetSlice(PyObject* s, Py_ssize_t i1, Py_ssize_t i2) noexcept {
PySequenceMethods* m;
PyMappingMethods* mp;
if (!s)
return null_error();
m = s->cls->tp_as_sequence;
if (m && m->sq_slice) {
if (i1 < 0 || i2 < 0) {
if (m->sq_length) {
Py_ssize_t l = (*m->sq_length)(s);
if (l < 0)
return NULL;
if (i1 < 0)
i1 += l;
if (i2 < 0)
i2 += l;
}
}
return m->sq_slice(s, i1, i2);
} else if ((mp = s->cls->tp_as_mapping) && mp->mp_subscript) {
PyObject* res;
PyObject* slice = _PySlice_FromIndices(i1, i2);
if (!slice)
return NULL;
res = mp->mp_subscript(s, slice);
Py_DECREF(slice);
return res;
}
return type_error("'%.200s' object is unsliceable", s);
} }
extern "C" int PySequence_SetItem(PyObject* o, Py_ssize_t i, PyObject* v) noexcept { extern "C" int PySequence_SetItem(PyObject* o, Py_ssize_t i, PyObject* v) noexcept {
......
...@@ -1112,12 +1112,14 @@ static int slot_sq_ass_slice(PyObject* self, Py_ssize_t i, Py_ssize_t j, PyObjec ...@@ -1112,12 +1112,14 @@ static int slot_sq_ass_slice(PyObject* self, Py_ssize_t i, Py_ssize_t j, PyObjec
// Copied from CPython: // Copied from CPython:
#define SLOT0(FUNCNAME, OPSTR) \ #define SLOT0(FUNCNAME, OPSTR) \
static PyObject* FUNCNAME(PyObject* self) noexcept { \ static PyObject* FUNCNAME(PyObject* self) noexcept { \
STAT_TIMER(t0, "us_timer_" #FUNCNAME, SLOT_AVOIDABILITY(self)); \
static PyObject* cache_str; \ static PyObject* cache_str; \
return call_method(self, OPSTR, &cache_str, "()"); \ return call_method(self, OPSTR, &cache_str, "()"); \
} }
#define SLOT1(FUNCNAME, OPSTR, ARG1TYPE, ARGCODES) \ #define SLOT1(FUNCNAME, OPSTR, ARG1TYPE, ARGCODES) \
/* Pyston change: static */ PyObject* FUNCNAME(PyObject* self, ARG1TYPE arg1) noexcept { \ /* Pyston change: static */ PyObject* FUNCNAME(PyObject* self, ARG1TYPE arg1) noexcept { \
STAT_TIMER(t0, "us_timer_" #FUNCNAME, SLOT_AVOIDABILITY(self)); \
static PyObject* cache_str; \ static PyObject* cache_str; \
return call_method(self, OPSTR, &cache_str, "(" ARGCODES ")", arg1); \ return call_method(self, OPSTR, &cache_str, "(" ARGCODES ")", arg1); \
} }
......
...@@ -133,6 +133,10 @@ extern "C" Box* listLen(BoxedList* self) { ...@@ -133,6 +133,10 @@ extern "C" Box* listLen(BoxedList* self) {
return boxInt(self->size); return boxInt(self->size);
} }
static Py_ssize_t list_length(Box* self) noexcept {
return static_cast<BoxedList*>(self)->size;
}
Box* _listSlice(BoxedList* self, i64 start, i64 stop, i64 step, i64 length) { Box* _listSlice(BoxedList* self, i64 start, i64 stop, i64 step, i64 length) {
// printf("%ld %ld %ld\n", start, stop, step); // printf("%ld %ld %ld\n", start, stop, step);
assert(step != 0); assert(step != 0);
...@@ -153,6 +157,38 @@ Box* _listSlice(BoxedList* self, i64 start, i64 stop, i64 step, i64 length) { ...@@ -153,6 +157,38 @@ Box* _listSlice(BoxedList* self, i64 start, i64 stop, i64 step, i64 length) {
return rtn; return rtn;
} }
static Box* list_slice(Box* o, Py_ssize_t ilow, Py_ssize_t ihigh) noexcept {
BoxedList* a = static_cast<BoxedList*>(o);
PyObject** src, **dest;
Py_ssize_t i, len;
if (ilow < 0)
ilow = 0;
else if (ilow > Py_SIZE(a))
ilow = Py_SIZE(a);
if (ihigh < ilow)
ihigh = ilow;
else if (ihigh > Py_SIZE(a))
ihigh = Py_SIZE(a);
len = ihigh - ilow;
BoxedList* np = new BoxedList();
np->ensure(len);
if (len) {
src = a->elts->elts + ilow;
dest = np->elts->elts;
for (i = 0; i < len; i++) {
PyObject* v = src[i];
Py_INCREF(v);
dest[i] = v;
}
}
np->size = len;
return (PyObject*)np;
}
extern "C" Box* listGetitemUnboxed(BoxedList* self, int64_t n) { extern "C" Box* listGetitemUnboxed(BoxedList* self, int64_t n) {
LOCK_REGION(self->lock.asRead()); LOCK_REGION(self->lock.asRead());
...@@ -1143,6 +1179,9 @@ void setupList() { ...@@ -1143,6 +1179,9 @@ void setupList() {
list_cls->giveAttr("__hash__", None); list_cls->giveAttr("__hash__", None);
list_cls->freeze(); list_cls->freeze();
list_cls->tp_as_sequence->sq_slice = list_slice;
list_cls->tp_as_sequence->sq_length = list_length;
CLFunction* hasnext = boxRTFunction((void*)listiterHasnextUnboxed, BOOL, 1); CLFunction* hasnext = boxRTFunction((void*)listiterHasnextUnboxed, BOOL, 1);
addRTFunction(hasnext, (void*)listiterHasnext, BOXED_BOOL); addRTFunction(hasnext, (void*)listiterHasnext, BOXED_BOOL);
list_iterator_cls->giveAttr("__hasnext__", new BoxedFunction(hasnext)); list_iterator_cls->giveAttr("__hasnext__", new BoxedFunction(hasnext));
......
...@@ -1591,6 +1591,28 @@ Box* _strSlice(BoxedString* self, i64 start, i64 stop, i64 step, i64 length) { ...@@ -1591,6 +1591,28 @@ Box* _strSlice(BoxedString* self, i64 start, i64 stop, i64 step, i64 length) {
return bs; return bs;
} }
static Box* str_slice(Box* o, Py_ssize_t i, Py_ssize_t j) {
BoxedString* a = static_cast<BoxedString*>(o);
if (i < 0)
i = 0;
if (j < 0)
j = 0; /* Avoid signed/unsigned bug in next line */
if (j > Py_SIZE(a))
j = Py_SIZE(a);
if (i == 0 && j == Py_SIZE(a) && PyString_CheckExact(a)) {
/* It's the same as a */
Py_INCREF(a);
return (PyObject*)a;
}
if (j < i)
j = i;
return PyString_FromStringAndSize(a->data() + i, j - i);
}
static Py_ssize_t str_length(Box* a) {
return Py_SIZE(a);
}
Box* strIsAlpha(BoxedString* self) { Box* strIsAlpha(BoxedString* self) {
assert(PyString_Check(self)); assert(PyString_Check(self));
...@@ -2745,6 +2767,9 @@ void setupStr() { ...@@ -2745,6 +2767,9 @@ void setupStr() {
add_operators(str_cls); add_operators(str_cls);
str_cls->freeze(); str_cls->freeze();
str_cls->tp_as_sequence->sq_slice = str_slice;
str_cls->tp_as_sequence->sq_length = str_length;
basestring_cls->giveAttr("__doc__", basestring_cls->giveAttr("__doc__",
boxString("Type basestring cannot be instantiated; it is the base for str and unicode.")); boxString("Type basestring cannot be instantiated; it is the base for str and unicode."));
basestring_cls->giveAttr("__new__", basestring_cls->giveAttr("__new__",
......
...@@ -1669,6 +1669,8 @@ extern "C" int PySlice_GetIndicesEx(PySliceObject* _r, Py_ssize_t length, Py_ssi ...@@ -1669,6 +1669,8 @@ extern "C" int PySlice_GetIndicesEx(PySliceObject* _r, Py_ssize_t length, Py_ssi
if ((*step < 0 && *stop >= *start) || (*step > 0 && *start >= *stop)) { if ((*step < 0 && *stop >= *start) || (*step > 0 && *start >= *stop)) {
*slicelength = 0; *slicelength = 0;
} else if (*step == 1) { // Pyston change: added this branch to make the common step==1 case avoid the div:
*slicelength = (*stop - *start - 1) + 1;
} else if (*step < 0) { } else if (*step < 0) {
*slicelength = (*stop - *start + 1) / (*step) + 1; *slicelength = (*stop - *start + 1) / (*step) + 1;
} else { } else {
......
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