Commit f1370b3f authored by Stefan Behnel's avatar Stefan Behnel

clean up (Set|Del)ItemInt code and fix negative indexing of objects with length > max(Py_ssize_t)

parent 3cc3601c
...@@ -302,7 +302,8 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, ...@@ -302,7 +302,8 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
Py_INCREF(r); Py_INCREF(r);
return r; return r;
} }
} else { /* inlined PySequence_GetItem() + special cased length overflow */ } else {
// inlined PySequence_GetItem() + special cased length overflow
PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence; PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence;
if (likely(m && m->sq_item)) { if (likely(m && m->sq_item)) {
if (wraparound && unlikely(i < 0) && likely(m->sq_length)) { if (wraparound && unlikely(i < 0) && likely(m->sq_length)) {
...@@ -335,6 +336,12 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, ...@@ -335,6 +336,12 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
__Pyx_SetItemInt_Fast(o, i, v, is_list, wraparound, boundscheck) : \ __Pyx_SetItemInt_Fast(o, i, v, is_list, wraparound, boundscheck) : \
__Pyx_SetItemInt_Generic(o, to_py_func(i), v)) __Pyx_SetItemInt_Generic(o, to_py_func(i), v))
static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v);
static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v,
int is_list, int wraparound, int boundscheck);
/////////////// SetItemInt ///////////////
static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) { static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) {
int r; int r;
if (!j) return -1; if (!j) return -1;
...@@ -355,13 +362,21 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje ...@@ -355,13 +362,21 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje
Py_DECREF(old); Py_DECREF(old);
return 1; return 1;
} }
} else { /* inlined PySequence_SetItem() */ } else {
// inlined PySequence_SetItem() + special cased length overflow
PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence; PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence;
if (likely(m && m->sq_ass_item)) { if (likely(m && m->sq_ass_item)) {
if (wraparound && unlikely(i < 0) && likely(m->sq_length)) { if (wraparound && unlikely(i < 0) && likely(m->sq_length)) {
Py_ssize_t l = m->sq_length(o); Py_ssize_t l = m->sq_length(o);
if (unlikely(l < 0)) return -1; if (likely(l >= 0)) {
i += l; i += l;
} else {
// if length > max(Py_ssize_t), maybe the object can wrap around itself?
if (PyErr_ExceptionMatches(PyExc_OverflowError))
PyErr_Clear();
else
return -1;
}
} }
return m->sq_ass_item(o, i, v); return m->sq_ass_item(o, i, v);
} }
...@@ -386,6 +401,12 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje ...@@ -386,6 +401,12 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje
__Pyx_DelItemInt_Fast(o, i, is_list, wraparound) : \ __Pyx_DelItemInt_Fast(o, i, is_list, wraparound) : \
__Pyx_DelItem_Generic(o, to_py_func(i))) __Pyx_DelItem_Generic(o, to_py_func(i)))
static CYTHON_INLINE int __Pyx_DelItem_Generic(PyObject *o, PyObject *j);
static CYTHON_INLINE int __Pyx_DelItemInt_Fast(PyObject *o, Py_ssize_t i,
CYTHON_UNUSED int is_list, int wraparound);
/////////////// DelItemInt ///////////////
static CYTHON_INLINE int __Pyx_DelItem_Generic(PyObject *o, PyObject *j) { static CYTHON_INLINE int __Pyx_DelItem_Generic(PyObject *o, PyObject *j) {
int r; int r;
if (!j) return -1; if (!j) return -1;
...@@ -401,13 +422,20 @@ static CYTHON_INLINE int __Pyx_DelItemInt_Fast(PyObject *o, Py_ssize_t i, ...@@ -401,13 +422,20 @@ static CYTHON_INLINE int __Pyx_DelItemInt_Fast(PyObject *o, Py_ssize_t i,
return PySequence_DelItem(o, i); return PySequence_DelItem(o, i);
} }
#else #else
/* inlined PySequence_DelItem() */ // inlined PySequence_DelItem() + special cased length overflow
PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence; PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence;
if (likely(m && m->sq_ass_item)) { if (likely(m && m->sq_ass_item)) {
if (wraparound && unlikely(i < 0) && likely(m->sq_length)) { if (wraparound && unlikely(i < 0) && likely(m->sq_length)) {
Py_ssize_t l = m->sq_length(o); Py_ssize_t l = m->sq_length(o);
if (unlikely(l < 0)) return -1; if (likely(l >= 0)) {
i += l; i += l;
} else {
// if length > max(Py_ssize_t), maybe the object can wrap around itself?
if (PyErr_ExceptionMatches(PyExc_OverflowError))
PyErr_Clear();
else
return -1;
}
} }
return m->sq_ass_item(o, i, (PyObject *)NULL); return m->sq_ass_item(o, i, (PyObject *)NULL);
} }
......
...@@ -5,11 +5,15 @@ __doc__ = u""" ...@@ -5,11 +5,15 @@ __doc__ = u"""
TypeError: 'int' object ... TypeError: 'int' object ...
""" """
cdef Py_ssize_t maxsize
import sys import sys
if sys.version_info < (2,5): if sys.version_info < (2,5):
__doc__ = __doc__.replace(u"'int' object ...", u'unsubscriptable object') __doc__ = __doc__.replace(u"'int' object ...", u'unsubscriptable object')
maxsize = min(sys.maxint, 2**31-1)
else:
maxsize = getattr(sys, 'maxsize', getattr(sys, 'maxint', None))
cdef Py_ssize_t maxsize = getattr(sys, 'maxsize', getattr(sys, 'maxint', None))
py_maxsize = maxsize py_maxsize = maxsize
import cython import cython
...@@ -166,12 +170,22 @@ def large_literal_index(object o): ...@@ -166,12 +170,22 @@ def large_literal_index(object o):
class LargeIndexable(object): class LargeIndexable(object):
expected = None
def __len__(self): def __len__(self):
raise OverflowError raise OverflowError
def __getitem__(self, index): def __getitem__(self, index):
return index return index
def __setitem__(self, index, value):
assert index == value == self.expected
self.expected = None
def __delitem__(self, index):
assert self.expected == index
self.expected = None
def test_large_indexing(obj): def test_large_indexing(obj):
""" """
...@@ -199,3 +213,31 @@ def test_large_indexing(obj): ...@@ -199,3 +213,31 @@ def test_large_indexing(obj):
obj[maxsize], obj[-maxsize], obj[maxsize], obj[-maxsize],
#obj[maxsize*2], obj[-maxsize*2] # FIXME! #obj[maxsize*2], obj[-maxsize*2] # FIXME!
) )
def del_large_index(obj, Py_ssize_t index):
"""
>>> obj = LargeIndexable()
>>> del_large_index(obj, 0)
>>> del_large_index(obj, 1)
>>> del_large_index(obj, -1)
>>> del_large_index(obj, py_maxsize)
>>> del_large_index(obj, -py_maxsize)
"""
obj.expected = index
del obj[index]
assert obj.expected is None
def set_large_index(obj, Py_ssize_t index):
"""
>>> obj = LargeIndexable()
>>> set_large_index(obj, 0)
>>> set_large_index(obj, 1)
>>> set_large_index(obj, -1)
>>> set_large_index(obj, py_maxsize)
>>> set_large_index(obj, -py_maxsize)
"""
obj.expected = index
obj[index] = index
assert obj.expected is None
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