From ce58dc06c9550d60164e71f28d676b799237bb56 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Sat, 16 Mar 2013 18:19:15 +0100 Subject: [PATCH] avoid code duplication by generating GetSlice/SetSlice utility code from a common template --- Cython/Compiler/ExprNodes.py | 21 +++--- Cython/Utility/ObjectHandling.c | 155 ++++++++++++---------------------------- 2 files changed, 57 insertions(+), 119 deletions(-) diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 894842c..a196160 100755 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -3594,6 +3594,12 @@ class SliceIndexNode(ExprNode): nogil_check = Node.gil_error gil_message = "Slicing Python object" + get_slice_utility_code = TempitaUtilityCode.load( + "SliceObject", "ObjectHandling.c", context={'access': 'Get'}) + + set_slice_utility_code = TempitaUtilityCode.load( + "SliceObject", "ObjectHandling.c", context={'access': 'Set'}) + def coerce_to(self, dst_type, env): if ((self.base.type.is_string or self.base.type.is_cpp_string) and dst_type in (bytes_type, str_type, unicode_type)): @@ -3668,12 +3674,11 @@ class SliceIndexNode(ExprNode): stop_code, code.error_goto_if_null(result, self.pos))) elif self.type is py_object_type: - code.globalstate.use_utility_code( - UtilityCode.load_cached("GetObjectSlice", "ObjectHandling.c")) + code.globalstate.use_utility_code(self.get_slice_utility_code) (has_c_start, has_c_stop, c_start, c_stop, py_start, py_stop, py_slice) = self.get_slice_config() code.putln( - "%s = __Pyx_PySequence_GetObjectSlice(%s, %s, %s, %s, %s, %s, %d, %d); %s" % ( + "%s = __Pyx_PyObject_GetSlice(%s, %s, %s, %s, %s, %s, %d, %d); %s" % ( result, self.base.py_result(), c_start, c_stop, @@ -3704,12 +3709,11 @@ class SliceIndexNode(ExprNode): def generate_assignment_code(self, rhs, code): self.generate_subexpr_evaluation_code(code) if self.type.is_pyobject: - code.globalstate.use_utility_code( - UtilityCode.load_cached("SetObjectSlice", "ObjectHandling.c")) + code.globalstate.use_utility_code(self.set_slice_utility_code) (has_c_start, has_c_stop, c_start, c_stop, py_start, py_stop, py_slice) = self.get_slice_config() code.put_error_if_neg(self.pos, - "__Pyx_PySequence_SetObjectSlice(%s, %s, %s, %s, %s, %s, %s, %d, %d)" % ( + "__Pyx_PyObject_SetSlice(%s, %s, %s, %s, %s, %s, %s, %d, %d)" % ( self.base.py_result(), rhs.py_result(), c_start, c_stop, @@ -3746,12 +3750,11 @@ class SliceIndexNode(ExprNode): "Deleting slices is only supported for Python types, not '%s'." % self.type) return self.generate_subexpr_evaluation_code(code) - code.globalstate.use_utility_code( - UtilityCode.load_cached("SetObjectSlice", "ObjectHandling.c")) + code.globalstate.use_utility_code(self.set_slice_utility_code) (has_c_start, has_c_stop, c_start, c_stop, py_start, py_stop, py_slice) = self.get_slice_config() code.put_error_if_neg(self.pos, - "__Pyx_PySequence_DelObjectSlice(%s, %s, %s, %s, %s, %s, %d, %d)" % ( + "__Pyx_PyObject_DelSlice(%s, %s, %s, %s, %s, %s, %d, %d)" % ( self.base.py_result(), c_start, c_stop, py_start, py_stop, py_slice, diff --git a/Cython/Utility/ObjectHandling.c b/Cython/Utility/ObjectHandling.c index 594624c..af7242f 100644 --- a/Cython/Utility/ObjectHandling.c +++ b/Cython/Utility/ObjectHandling.c @@ -444,137 +444,51 @@ static CYTHON_INLINE int __Pyx_DelItemInt_Fast(PyObject *o, Py_ssize_t i, } -/////////////// GetObjectSlice.proto /////////////// +/////////////// SliceObject.proto /////////////// // we pass pointer addresses to show the C compiler what is NULL and what isn't -static CYTHON_INLINE PyObject* __Pyx_PySequence_GetObjectSlice( +{{if access == 'Get'}} +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetSlice( PyObject* obj, Py_ssize_t cstart, Py_ssize_t cstop, PyObject** py_start, PyObject** py_stop, PyObject** py_slice, int has_cstart, int has_cstop); - -/////////////// GetObjectSlice /////////////// - -static CYTHON_INLINE PyObject* __Pyx_PySequence_GetObjectSlice( - PyObject* obj, Py_ssize_t cstart, Py_ssize_t cstop, - PyObject** _py_start, PyObject** _py_stop, PyObject** _py_slice, - int has_cstart, int has_cstop) { - PyMappingMethods* mp; -#if PY_MAJOR_VERSION < 3 - PySequenceMethods* ms = Py_TYPE(obj)->tp_as_sequence; - if (likely(ms && ms->sq_slice)) { - if (!has_cstart) { - if (_py_start && (*_py_start != Py_None)) { - cstart = __Pyx_PyIndex_AsSsize_t(*_py_start); - if ((cstart == (Py_ssize_t)-1) && PyErr_Occurred()) return NULL; - } else - cstart = 0; - } - if (!has_cstop) { - if (_py_stop && (*_py_stop != Py_None)) { - cstop = __Pyx_PyIndex_AsSsize_t(*_py_stop); - if ((cstop == (Py_ssize_t)-1) && PyErr_Occurred()) return NULL; - } else - cstop = PY_SSIZE_T_MAX; - } - if (unlikely((cstart < 0) | (cstop < 0)) && likely(ms->sq_length)) { - Py_ssize_t l = ms->sq_length(obj); - if (likely(l >= 0)) { - if (cstop < 0) { - cstop += l; - if (cstop < 0) cstop = 0; - } - if (cstart < 0) { - cstart += l; - if (cstart < 0) cstart = 0; - } - } else { - // if length > max(Py_ssize_t), maybe the object can wrap around itself? - if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_Clear(); - else - return NULL; - } - } - return ms->sq_slice(obj, cstart, cstop); - } -#endif - mp = Py_TYPE(obj)->tp_as_mapping; - if (likely(mp && mp->mp_subscript)) { - PyObject *result, *py_slice, *py_start, *py_stop; - if (_py_slice) { - py_slice = *_py_slice; - } else { - PyObject* owned_start = NULL; - PyObject* owned_stop = NULL; - if (_py_start) { - py_start = *_py_start; - } else { - if (has_cstart) { - owned_start = py_start = PyInt_FromSsize_t(cstart); - if (unlikely(!py_start)) return NULL; - } else - py_start = Py_None; - } - if (_py_stop) { - py_stop = *_py_stop; - } else { - if (has_cstop) { - owned_stop = py_stop = PyInt_FromSsize_t(cstop); - if (unlikely(!py_stop)) { - Py_XDECREF(owned_start); - return NULL; - } - } else - py_stop = Py_None; - } - py_slice = PySlice_New(py_start, py_stop, Py_None); - Py_XDECREF(owned_start); - Py_XDECREF(owned_stop); - if (unlikely(!py_slice)) return NULL; - } - result = mp->mp_subscript(obj, py_slice); - if (!_py_slice) { - Py_DECREF(py_slice); - } - return result; - } - PyErr_Format(PyExc_TypeError, - "'%.200s' object is unsliceable", Py_TYPE(obj)->tp_name); - return NULL; -} - -/////////////// SetObjectSlice.proto /////////////// - -#define __Pyx_PySequence_DelObjectSlice(obj, cstart, cstop, py_start, py_stop, py_slice, has_cstart, has_cstop) \ - __Pyx_PySequence_SetObjectSlice(obj, (PyObject*)NULL, cstart, cstop, py_start, py_stop, py_slice, has_cstart, has_cstop) +{{else}} +#define __Pyx_PyObject_DelSlice(obj, cstart, cstop, py_start, py_stop, py_slice, has_cstart, has_cstop) \ + __Pyx_PyObject_SetSlice(obj, (PyObject*)NULL, cstart, cstop, py_start, py_stop, py_slice, has_cstart, has_cstop) // we pass pointer addresses to show the C compiler what is NULL and what isn't -static CYTHON_INLINE int __Pyx_PySequence_SetObjectSlice( +static CYTHON_INLINE int __Pyx_PyObject_SetSlice( PyObject* obj, PyObject* value, Py_ssize_t cstart, Py_ssize_t cstop, PyObject** py_start, PyObject** py_stop, PyObject** py_slice, int has_cstart, int has_cstop); +{{endif}} -/////////////// SetObjectSlice /////////////// +/////////////// SliceObject /////////////// -static CYTHON_INLINE int __Pyx_PySequence_SetObjectSlice( +{{if access == 'Get'}} +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetSlice( + PyObject* obj, Py_ssize_t cstart, Py_ssize_t cstop, +{{else}} +static CYTHON_INLINE int __Pyx_PyObject_SetSlice( PyObject* obj, PyObject* value, Py_ssize_t cstart, Py_ssize_t cstop, +{{endif}} PyObject** _py_start, PyObject** _py_stop, PyObject** _py_slice, int has_cstart, int has_cstop) { PyMappingMethods* mp; #if PY_MAJOR_VERSION < 3 PySequenceMethods* ms = Py_TYPE(obj)->tp_as_sequence; - if (likely(ms && ms->sq_ass_slice)) { + if (likely(ms && ms->sq_{{if access == 'Set'}}ass_{{endif}}slice)) { if (!has_cstart) { if (_py_start && (*_py_start != Py_None)) { cstart = __Pyx_PyIndex_AsSsize_t(*_py_start); - if ((cstart == (Py_ssize_t)-1) && PyErr_Occurred()) return -1; + if ((cstart == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; } else cstart = 0; } if (!has_cstop) { if (_py_stop && (*_py_stop != Py_None)) { cstop = __Pyx_PyIndex_AsSsize_t(*_py_stop); - if ((cstop == (Py_ssize_t)-1) && PyErr_Occurred()) return -1; + if ((cstop == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; } else cstop = PY_SSIZE_T_MAX; } @@ -594,16 +508,26 @@ static CYTHON_INLINE int __Pyx_PySequence_SetObjectSlice( if (PyErr_ExceptionMatches(PyExc_OverflowError)) PyErr_Clear(); else - return -1; + goto bad; } } +{{if access == 'Get'}} + return ms->sq_slice(obj, cstart, cstop); +{{else}} return ms->sq_ass_slice(obj, cstart, cstop, value); +{{endif}} } #endif + mp = Py_TYPE(obj)->tp_as_mapping; +{{if access == 'Get'}} + if (likely(mp && mp->mp_subscript)) { + PyObject *result; +{{else}} if (likely(mp && mp->mp_ass_subscript)) { - PyObject *py_slice, *py_start, *py_stop; int result; +{{endif}} + PyObject *py_slice, *py_start, *py_stop; if (_py_slice) { py_slice = *_py_slice; } else { @@ -614,7 +538,7 @@ static CYTHON_INLINE int __Pyx_PySequence_SetObjectSlice( } else { if (has_cstart) { owned_start = py_start = PyInt_FromSsize_t(cstart); - if (unlikely(!py_start)) return -1; + if (unlikely(!py_start)) goto bad; } else py_start = Py_None; } @@ -625,7 +549,7 @@ static CYTHON_INLINE int __Pyx_PySequence_SetObjectSlice( owned_stop = py_stop = PyInt_FromSsize_t(cstop); if (unlikely(!py_stop)) { Py_XDECREF(owned_start); - return -1; + goto bad; } } else py_stop = Py_None; @@ -633,19 +557,30 @@ static CYTHON_INLINE int __Pyx_PySequence_SetObjectSlice( py_slice = PySlice_New(py_start, py_stop, Py_None); Py_XDECREF(owned_start); Py_XDECREF(owned_stop); - if (unlikely(!py_slice)) return -1; + if (unlikely(!py_slice)) goto bad; } +{{if access == 'Get'}} + result = mp->mp_subscript(obj, py_slice); +{{else}} result = mp->mp_ass_subscript(obj, py_slice, value); +{{endif}} if (!_py_slice) { Py_DECREF(py_slice); } return result; } PyErr_Format(PyExc_TypeError, +{{if access == 'Get'}} "'%.200s' object is unsliceable", Py_TYPE(obj)->tp_name); - return -1; +{{else}} + "'%.200s' object does not support slice assignment", Py_TYPE(obj)->tp_name); +{{endif}} + +bad: + return {{if access == 'Get'}}NULL{{else}}-1{{endif}}; } + /////////////// SliceTupleAndList.proto /////////////// #if CYTHON_COMPILING_IN_CPYTHON -- 2.7.4