Commit cc4f7dae authored by Stefan Behnel's avatar Stefan Behnel

use constant flags to move wraparound/boundscheck evaluation into inlined...

use constant flags to move wraparound/boundscheck evaluation into inlined Get/Set/DelItemInt() utility functions
parent 496c0fd9
......@@ -3132,13 +3132,24 @@ class IndexNode(ExprNode):
return "(%s[%s])" % (
self.base.result(), self.index.result())
def extra_index_params(self):
def extra_index_params(self, code):
if self.index.type.is_int:
if self.original_index_type.signed:
size_adjustment = ""
else:
size_adjustment = "+1"
return ", sizeof(%s)%s, %s" % (self.original_index_type.declaration_code(""), size_adjustment, self.original_index_type.to_py_function)
is_list = self.base.type is list_type
wraparound = (
bool(code.globalstate.directives['wraparound']) and
self.original_index_type.signed and
not (isinstance(self.index.constant_result, (int, long))
and self.index.constant_result >= 0))
boundscheck = bool(code.globalstate.directives['boundscheck'])
return ", sizeof(%s)%s, %s, %d, %d, %d" % (
self.original_index_type.declaration_code(""),
size_adjustment,
self.original_index_type.to_py_function,
is_list, wraparound, boundscheck)
else:
return ""
......@@ -3206,7 +3217,7 @@ class IndexNode(ExprNode):
function,
self.base.py_result(),
index_code,
self.extra_index_params(),
self.extra_index_params(code),
self.result(),
code.error_goto(self.pos)))
code.put_gotref(self.py_result())
......@@ -3222,19 +3233,13 @@ class IndexNode(ExprNode):
function,
self.base.py_result(),
index_code,
self.extra_index_params(),
self.extra_index_params(code),
self.result(),
code.error_goto(self.pos)))
def generate_setitem_code(self, value_code, code):
if self.index.type.is_int:
if (self.base.type.is_builtin_type
and self.base.type.name == "list"
and not code.globalstate.directives['wraparound']
and not code.globalstate.directives['boundscheck']):
function = "__Pyx_SetItemListInt_NoCheck"
else:
function = "__Pyx_SetItemInt"
function = "__Pyx_SetItemInt"
index_code = self.index.result()
code.globalstate.use_utility_code(
UtilityCode.load_cached("SetItemInt", "ObjectHandling.c"))
......@@ -3257,7 +3262,7 @@ class IndexNode(ExprNode):
self.base.py_result(),
index_code,
value_code,
self.extra_index_params(),
self.extra_index_params(code),
code.error_goto(self.pos)))
def generate_buffer_setitem_code(self, rhs, code, op=""):
......@@ -3330,7 +3335,7 @@ class IndexNode(ExprNode):
function,
self.base.py_result(),
index_code,
self.extra_index_params(),
self.extra_index_params(code),
code.error_goto(self.pos)))
self.generate_subexpr_disposal_code(code)
self.free_subexpr_temps(code)
......
......@@ -247,22 +247,20 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j
}
{{for type in ['List', 'Tuple']}}
#define __Pyx_GetItemInt_{{type}}(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \
__Pyx_GetItemInt_{{type}}_Fast(o, i) : \
__Pyx_GetItemInt_Generic(o, to_py_func(i)))
#define __Pyx_GetItemInt_{{type}}(o, i, size, to_py_func, is_list, wraparound, boundscheck) \
(((size) <= sizeof(Py_ssize_t)) ? \
__Pyx_GetItemInt_{{type}}_Fast(o, i, wraparound, boundscheck) : \
__Pyx_GetItemInt_Generic(o, to_py_func(i)))
static CYTHON_INLINE PyObject *__Pyx_GetItemInt_{{type}}_Fast(PyObject *o, Py_ssize_t i) {
static CYTHON_INLINE PyObject *__Pyx_GetItemInt_{{type}}_Fast(PyObject *o, Py_ssize_t i,
int wraparound, int boundscheck) {
#if CYTHON_COMPILING_IN_CPYTHON
if (likely((0 <= i) & (i < Py{{type}}_GET_SIZE(o)))) {
if (wraparound & unlikely(i < 0)) i += Py{{type}}_GET_SIZE(o);
if ((!boundscheck) || likely((0 <= i) & (i < Py{{type}}_GET_SIZE(o)))) {
PyObject *r = Py{{type}}_GET_ITEM(o, i);
Py_INCREF(r);
return r;
}
else if ((-Py{{type}}_GET_SIZE(o) <= i) & (i < 0)) {
PyObject *r = Py{{type}}_GET_ITEM(o, Py{{type}}_GET_SIZE(o) + i);
Py_INCREF(r);
return r;
}
return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i));
#else
return PySequence_GetItem(o, i);
......@@ -270,23 +268,25 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_{{type}}_Fast(PyObject *o, Py_ss
}
{{endfor}}
#define __Pyx_GetItemInt(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \
__Pyx_GetItemInt_Fast(o, i) : \
__Pyx_GetItemInt_Generic(o, to_py_func(i)))
#define __Pyx_GetItemInt(o, i, size, to_py_func, is_list, wraparound, boundscheck) \
(((size) <= sizeof(Py_ssize_t)) ? \
__Pyx_GetItemInt_Fast(o, i, is_list, wraparound, boundscheck) : \
__Pyx_GetItemInt_Generic(o, to_py_func(i)))
static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i) {
static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
int is_list, int wraparound, int boundscheck) {
#if CYTHON_COMPILING_IN_CPYTHON
if (PyList_CheckExact(o)) {
Py_ssize_t n = (likely(i >= 0)) ? i : i + PyList_GET_SIZE(o);
if (likely((n >= 0) & (n < PyList_GET_SIZE(o)))) {
if (is_list || PyList_CheckExact(o)) {
Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o);
if ((!boundscheck) || (likely((n >= 0) & (n < PyList_GET_SIZE(o))))) {
PyObject *r = PyList_GET_ITEM(o, n);
Py_INCREF(r);
return r;
}
}
else if (PyTuple_CheckExact(o)) {
Py_ssize_t n = (likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o);
if (likely((n >= 0) & (n < PyTuple_GET_SIZE(o)))) {
Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o);
if ((!boundscheck) || likely((n >= 0) & (n < PyTuple_GET_SIZE(o)))) {
PyObject *r = PyTuple_GET_ITEM(o, n);
Py_INCREF(r);
return r;
......@@ -294,7 +294,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i)
} else { /* inlined PySequence_GetItem() */
PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence;
if (likely(m && m->sq_item)) {
if (unlikely(i < 0) && likely(m->sq_length)) {
if (wraparound && unlikely(i < 0) && likely(m->sq_length)) {
Py_ssize_t l = m->sq_length(o);
if (unlikely(l < 0)) return NULL;
i += l;
......@@ -303,7 +303,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i)
}
}
#else
if (PySequence_Check(o)) {
if (is_list || PySequence_Check(o)) {
return PySequence_GetItem(o, i);
}
#endif
......@@ -312,9 +312,10 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i)
/////////////// SetItemInt.proto ///////////////
#define __Pyx_SetItemInt(o, i, v, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \
__Pyx_SetItemInt_Fast(o, i, v) : \
__Pyx_SetItemInt_Generic(o, to_py_func(i), v))
#define __Pyx_SetItemInt(o, i, v, size, to_py_func, is_list, wraparound, boundscheck) \
(((size) <= sizeof(Py_ssize_t)) ? \
__Pyx_SetItemInt_Fast(o, i, v, is_list, wraparound, boundscheck) : \
__Pyx_SetItemInt_Generic(o, to_py_func(i), v))
static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) {
int r;
......@@ -324,11 +325,12 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyOb
return r;
}
static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v) {
static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v,
int is_list, int wraparound, int boundscheck) {
#if CYTHON_COMPILING_IN_CPYTHON
if (PyList_CheckExact(o)) {
Py_ssize_t n = (likely(i >= 0)) ? i : i + PyList_GET_SIZE(o);
if (likely((n >= 0) & (n < PyList_GET_SIZE(o)))) {
if (is_list || PyList_CheckExact(o)) {
Py_ssize_t n = (!wraparound) ? i : ((likely(i >= 0)) ? i : i + PyList_GET_SIZE(o));
if ((!boundscheck) || likely((n >= 0) & (n < PyList_GET_SIZE(o)))) {
PyObject* old = PyList_GET_ITEM(o, n);
Py_INCREF(v);
PyList_SET_ITEM(o, n, v);
......@@ -338,7 +340,7 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje
} else { /* inlined PySequence_SetItem() */
PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence;
if (likely(m && m->sq_ass_item)) {
if (unlikely(i < 0) && likely(m->sq_length)) {
if (wraparound && unlikely(i < 0) && likely(m->sq_length)) {
Py_ssize_t l = m->sq_length(o);
if (unlikely(l < 0)) return -1;
i += l;
......@@ -348,9 +350,9 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje
}
#else
#if CYTHON_COMPILING_IN_PYPY
if (PySequence_Check(o) && !PyDict_Check(o)) {
if (is_list || (PySequence_Check(o) && !PyDict_Check(o))) {
#else
if (PySequence_Check(o)) {
if (is_list || PySequence_Check(o)) {
#endif
return PySequence_SetItem(o, i, v);
}
......@@ -359,23 +361,12 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje
}
#define __Pyx_SetItemListInt_NoCheck(o, i, v, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \
__Pyx_SetItemIntList_NoCheck(o, i, v) : \
__Pyx_SetItemInt_Generic(o, to_py_func(i), v))
static CYTHON_INLINE int __Pyx_SetItemIntList_NoCheck(PyObject *o, Py_ssize_t n, PyObject *v) {
PyObject* old = PyList_GET_ITEM(o, n);
Py_INCREF(v);
PyList_SET_ITEM(o, n, v);
Py_DECREF(old);
return 1;
}
/////////////// DelItemInt.proto ///////////////
#define __Pyx_DelItemInt(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \
__Pyx_DelItemInt_Fast(o, i) : \
__Pyx_DelItem_Generic(o, to_py_func(i)))
#define __Pyx_DelItemInt(o, i, size, to_py_func, is_list, wraparound, boundscheck) \
(((size) <= sizeof(Py_ssize_t)) ? \
__Pyx_DelItemInt_Fast(o, i, is_list, wraparound, boundscheck) : \
__Pyx_DelItem_Generic(o, to_py_func(i)))
static CYTHON_INLINE int __Pyx_DelItem_Generic(PyObject *o, PyObject *j) {
int r;
......@@ -385,16 +376,17 @@ static CYTHON_INLINE int __Pyx_DelItem_Generic(PyObject *o, PyObject *j) {
return r;
}
static CYTHON_INLINE int __Pyx_DelItemInt_Fast(PyObject *o, Py_ssize_t i) {
static CYTHON_INLINE int __Pyx_DelItemInt_Fast(PyObject *o, Py_ssize_t i,
int is_list, int wraparound, int boundscheck) {
#if CYTHON_COMPILING_IN_PYPY
if (PySequence_Check(o)) {
if (is_list || PySequence_Check(o)) {
return PySequence_DelItem(o, i);
}
#else
/* inlined PySequence_DelItem() */
PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence;
if (likely(m && m->sq_ass_item)) {
if (unlikely(i < 0) && likely(m->sq_length)) {
if (wraparound && unlikely(i < 0) && likely(m->sq_length)) {
Py_ssize_t l = m->sq_length(o);
if (unlikely(l < 0)) return -1;
i += l;
......
......@@ -229,28 +229,34 @@ static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int eq
//////////////////// GetItemIntUnicode.proto ////////////////////
#define __Pyx_GetItemInt_Unicode(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \
__Pyx_GetItemInt_Unicode_Fast(o, i) : \
__Pyx_GetItemInt_Unicode_Generic(o, to_py_func(i)))
#define __Pyx_GetItemInt_Unicode(o, i, size, to_py_func, is_list, wraparound, boundscheck) \
(((size) <= sizeof(Py_ssize_t)) ? \
__Pyx_GetItemInt_Unicode_Fast(o, i, wraparound, boundscheck) : \
__Pyx_GetItemInt_Unicode_Generic(o, to_py_func(i)))
static CYTHON_INLINE Py_UCS4 __Pyx_GetItemInt_Unicode_Fast(PyObject* ustring, Py_ssize_t i);
static CYTHON_INLINE Py_UCS4 __Pyx_GetItemInt_Unicode_Fast(PyObject* ustring, Py_ssize_t i,
int wraparound, int boundscheck);
static CYTHON_INLINE Py_UCS4 __Pyx_GetItemInt_Unicode_Generic(PyObject* ustring, PyObject* j);
//////////////////// GetItemIntUnicode ////////////////////
static CYTHON_INLINE Py_UCS4 __Pyx_GetItemInt_Unicode_Fast(PyObject* ustring, Py_ssize_t i) {
static CYTHON_INLINE Py_UCS4 __Pyx_GetItemInt_Unicode_Fast(PyObject* ustring, Py_ssize_t i,
int wraparound, int boundscheck) {
Py_ssize_t length;
#if CYTHON_PEP393_ENABLED
if (unlikely(__Pyx_PyUnicode_READY(ustring) < 0)) return (Py_UCS4)-1;
#endif
length = __Pyx_PyUnicode_GET_LENGTH(ustring);
if (likely((0 <= i) & (i < length))) {
return __Pyx_PyUnicode_READ_CHAR(ustring, i);
} else if ((-length <= i) & (i < 0)) {
return __Pyx_PyUnicode_READ_CHAR(ustring, i + length);
if (wraparound | boundscheck) {
length = __Pyx_PyUnicode_GET_LENGTH(ustring);
if (wraparound & unlikely(i < 0)) i += length;
if ((!boundscheck) || likely((0 <= i) & (i < length))) {
return __Pyx_PyUnicode_READ_CHAR(ustring, i);
} else {
PyErr_SetString(PyExc_IndexError, "string index out of range");
return (Py_UCS4)-1;
}
} else {
PyErr_SetString(PyExc_IndexError, "string index out of range");
return (Py_UCS4)-1;
return __Pyx_PyUnicode_READ_CHAR(ustring, i);
}
}
......
......@@ -119,11 +119,35 @@ def test_long_long():
assert len(D) == 0
@cython.boundscheck(False)
def test_boundscheck(list L, tuple t, object o, unsigned long ix):
def test_boundscheck_unsigned(list L, tuple t, object o, unsigned long ix):
"""
>>> test_boundscheck([1, 2, 4], (1, 2, 4), [1, 2, 4], 2)
>>> test_boundscheck_unsigned([1, 2, 4], (1, 2, 4), [1, 2, 4], 2)
(4, 4, 4)
>>> test_boundscheck([1, 2, 4], (1, 2, 4), "", 2)
>>> test_boundscheck_unsigned([1, 2, 4], (1, 2, 4), "", 2)
Traceback (most recent call last):
...
IndexError: string index out of range
"""
return L[ix], t[ix], o[ix]
@cython.boundscheck(False)
def test_boundscheck_signed(list L, tuple t, object o, long ix):
"""
>>> test_boundscheck_signed([1, 2, 4], (1, 2, 4), [1, 2, 4], 2)
(4, 4, 4)
>>> test_boundscheck_signed([1, 2, 4], (1, 2, 4), "", 2)
Traceback (most recent call last):
...
IndexError: string index out of range
"""
return L[ix], t[ix], o[ix]
@cython.wraparound(False)
def test_wraparound_signed(list L, tuple t, object o, long ix):
"""
>>> test_wraparound_signed([1, 2, 4], (1, 2, 4), [1, 2, 4], 2)
(4, 4, 4)
>>> test_wraparound_signed([1, 2, 4], (1, 2, 4), "", 2)
Traceback (most recent call last):
...
IndexError: string index out of range
......
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