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):
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,
......
......@@ -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
......
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