Commit ce58dc06 authored by Stefan Behnel's avatar Stefan Behnel

avoid code duplication by generating GetSlice/SetSlice utility code from a common template

parent 53de3248
...@@ -3594,6 +3594,12 @@ class SliceIndexNode(ExprNode): ...@@ -3594,6 +3594,12 @@ class SliceIndexNode(ExprNode):
nogil_check = Node.gil_error nogil_check = Node.gil_error
gil_message = "Slicing Python object" 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): def coerce_to(self, dst_type, env):
if ((self.base.type.is_string or self.base.type.is_cpp_string) if ((self.base.type.is_string or self.base.type.is_cpp_string)
and dst_type in (bytes_type, str_type, unicode_type)): and dst_type in (bytes_type, str_type, unicode_type)):
...@@ -3668,12 +3674,11 @@ class SliceIndexNode(ExprNode): ...@@ -3668,12 +3674,11 @@ class SliceIndexNode(ExprNode):
stop_code, stop_code,
code.error_goto_if_null(result, self.pos))) code.error_goto_if_null(result, self.pos)))
elif self.type is py_object_type: elif self.type is py_object_type:
code.globalstate.use_utility_code( code.globalstate.use_utility_code(self.get_slice_utility_code)
UtilityCode.load_cached("GetObjectSlice", "ObjectHandling.c"))
(has_c_start, has_c_stop, c_start, c_stop, (has_c_start, has_c_stop, c_start, c_stop,
py_start, py_stop, py_slice) = self.get_slice_config() py_start, py_stop, py_slice) = self.get_slice_config()
code.putln( 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, result,
self.base.py_result(), self.base.py_result(),
c_start, c_stop, c_start, c_stop,
...@@ -3704,12 +3709,11 @@ class SliceIndexNode(ExprNode): ...@@ -3704,12 +3709,11 @@ class SliceIndexNode(ExprNode):
def generate_assignment_code(self, rhs, code): def generate_assignment_code(self, rhs, code):
self.generate_subexpr_evaluation_code(code) self.generate_subexpr_evaluation_code(code)
if self.type.is_pyobject: if self.type.is_pyobject:
code.globalstate.use_utility_code( code.globalstate.use_utility_code(self.set_slice_utility_code)
UtilityCode.load_cached("SetObjectSlice", "ObjectHandling.c"))
(has_c_start, has_c_stop, c_start, c_stop, (has_c_start, has_c_stop, c_start, c_stop,
py_start, py_stop, py_slice) = self.get_slice_config() py_start, py_stop, py_slice) = self.get_slice_config()
code.put_error_if_neg(self.pos, 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(), self.base.py_result(),
rhs.py_result(), rhs.py_result(),
c_start, c_stop, c_start, c_stop,
...@@ -3746,12 +3750,11 @@ class SliceIndexNode(ExprNode): ...@@ -3746,12 +3750,11 @@ class SliceIndexNode(ExprNode):
"Deleting slices is only supported for Python types, not '%s'." % self.type) "Deleting slices is only supported for Python types, not '%s'." % self.type)
return return
self.generate_subexpr_evaluation_code(code) self.generate_subexpr_evaluation_code(code)
code.globalstate.use_utility_code( code.globalstate.use_utility_code(self.set_slice_utility_code)
UtilityCode.load_cached("SetObjectSlice", "ObjectHandling.c"))
(has_c_start, has_c_stop, c_start, c_stop, (has_c_start, has_c_stop, c_start, c_stop,
py_start, py_stop, py_slice) = self.get_slice_config() py_start, py_stop, py_slice) = self.get_slice_config()
code.put_error_if_neg(self.pos, 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(), self.base.py_result(),
c_start, c_stop, c_start, c_stop,
py_start, py_stop, py_slice, py_start, py_stop, py_slice,
......
...@@ -444,137 +444,51 @@ static CYTHON_INLINE int __Pyx_DelItemInt_Fast(PyObject *o, Py_ssize_t i, ...@@ -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 // 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* obj, Py_ssize_t cstart, Py_ssize_t cstop,
PyObject** py_start, PyObject** py_stop, PyObject** py_slice, PyObject** py_start, PyObject** py_stop, PyObject** py_slice,
int has_cstart, int has_cstop); int has_cstart, int has_cstop);
{{else}}
/////////////// GetObjectSlice /////////////// #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)
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)
// we pass pointer addresses to show the C compiler what is NULL and what isn't // 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* obj, PyObject* value, Py_ssize_t cstart, Py_ssize_t cstop,
PyObject** py_start, PyObject** py_stop, PyObject** py_slice, PyObject** py_start, PyObject** py_stop, PyObject** py_slice,
int has_cstart, int has_cstop); 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, PyObject* obj, PyObject* value, Py_ssize_t cstart, Py_ssize_t cstop,
{{endif}}
PyObject** _py_start, PyObject** _py_stop, PyObject** _py_slice, PyObject** _py_start, PyObject** _py_stop, PyObject** _py_slice,
int has_cstart, int has_cstop) { int has_cstart, int has_cstop) {
PyMappingMethods* mp; PyMappingMethods* mp;
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
PySequenceMethods* ms = Py_TYPE(obj)->tp_as_sequence; 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 (!has_cstart) {
if (_py_start && (*_py_start != Py_None)) { if (_py_start && (*_py_start != Py_None)) {
cstart = __Pyx_PyIndex_AsSsize_t(*_py_start); 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 } else
cstart = 0; cstart = 0;
} }
if (!has_cstop) { if (!has_cstop) {
if (_py_stop && (*_py_stop != Py_None)) { if (_py_stop && (*_py_stop != Py_None)) {
cstop = __Pyx_PyIndex_AsSsize_t(*_py_stop); 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 } else
cstop = PY_SSIZE_T_MAX; cstop = PY_SSIZE_T_MAX;
} }
...@@ -594,16 +508,26 @@ static CYTHON_INLINE int __Pyx_PySequence_SetObjectSlice( ...@@ -594,16 +508,26 @@ static CYTHON_INLINE int __Pyx_PySequence_SetObjectSlice(
if (PyErr_ExceptionMatches(PyExc_OverflowError)) if (PyErr_ExceptionMatches(PyExc_OverflowError))
PyErr_Clear(); PyErr_Clear();
else 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); return ms->sq_ass_slice(obj, cstart, cstop, value);
{{endif}}
} }
#endif #endif
mp = Py_TYPE(obj)->tp_as_mapping; 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)) { if (likely(mp && mp->mp_ass_subscript)) {
PyObject *py_slice, *py_start, *py_stop;
int result; int result;
{{endif}}
PyObject *py_slice, *py_start, *py_stop;
if (_py_slice) { if (_py_slice) {
py_slice = *_py_slice; py_slice = *_py_slice;
} else { } else {
...@@ -614,7 +538,7 @@ static CYTHON_INLINE int __Pyx_PySequence_SetObjectSlice( ...@@ -614,7 +538,7 @@ static CYTHON_INLINE int __Pyx_PySequence_SetObjectSlice(
} else { } else {
if (has_cstart) { if (has_cstart) {
owned_start = py_start = PyInt_FromSsize_t(cstart); owned_start = py_start = PyInt_FromSsize_t(cstart);
if (unlikely(!py_start)) return -1; if (unlikely(!py_start)) goto bad;
} else } else
py_start = Py_None; py_start = Py_None;
} }
...@@ -625,7 +549,7 @@ static CYTHON_INLINE int __Pyx_PySequence_SetObjectSlice( ...@@ -625,7 +549,7 @@ static CYTHON_INLINE int __Pyx_PySequence_SetObjectSlice(
owned_stop = py_stop = PyInt_FromSsize_t(cstop); owned_stop = py_stop = PyInt_FromSsize_t(cstop);
if (unlikely(!py_stop)) { if (unlikely(!py_stop)) {
Py_XDECREF(owned_start); Py_XDECREF(owned_start);
return -1; goto bad;
} }
} else } else
py_stop = Py_None; py_stop = Py_None;
...@@ -633,19 +557,30 @@ static CYTHON_INLINE int __Pyx_PySequence_SetObjectSlice( ...@@ -633,19 +557,30 @@ static CYTHON_INLINE int __Pyx_PySequence_SetObjectSlice(
py_slice = PySlice_New(py_start, py_stop, Py_None); py_slice = PySlice_New(py_start, py_stop, Py_None);
Py_XDECREF(owned_start); Py_XDECREF(owned_start);
Py_XDECREF(owned_stop); 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); result = mp->mp_ass_subscript(obj, py_slice, value);
{{endif}}
if (!_py_slice) { if (!_py_slice) {
Py_DECREF(py_slice); Py_DECREF(py_slice);
} }
return result; return result;
} }
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
{{if access == 'Get'}}
"'%.200s' object is unsliceable", Py_TYPE(obj)->tp_name); "'%.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 /////////////// /////////////// SliceTupleAndList.proto ///////////////
#if CYTHON_COMPILING_IN_CPYTHON #if CYTHON_COMPILING_IN_CPYTHON
......
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