avoid code duplication by generating GetSlice/SetSlice utility code from a common...
authorStefan Behnel <stefan_ml@behnel.de>
Sat, 16 Mar 2013 17:19:15 +0000 (18:19 +0100)
committerStefan Behnel <stefan_ml@behnel.de>
Sat, 16 Mar 2013 17:19:15 +0000 (18:19 +0100)
Cython/Compiler/ExprNodes.py
Cython/Utility/ObjectHandling.c

index 894842c..a196160 100755 (executable)
@@ -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,
index 594624c..af7242f 100644 (file)
@@ -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