# base ExprNode
# start ExprNode or None
# stop ExprNode or None
+ # slice ExprNode or None constant slice object
- subexprs = ['base', 'start', 'stop']
+ subexprs = ['base', 'start', 'stop', 'slice']
+
+ slice = None
def infer_type(self, env):
base_type = self.base.infer_type(env)
self.type = base_type
self.base = self.base.as_none_safe_node("'NoneType' object is not subscriptable")
- c_int = PyrexTypes.c_py_ssize_t_type
- if self.start:
- self.start = self.start.coerce_to(c_int, env)
- if self.stop:
- self.stop = self.stop.coerce_to(c_int, env)
+ if self.type is py_object_type:
+ if (not self.start or self.start.is_literal) and \
+ (not self.stop or self.stop.is_literal):
+ # cache the constant slice object, in case we need it
+ none_node = NoneNode(self.pos)
+ self.slice = SliceNode(
+ self.pos,
+ start=copy.deepcopy(self.start or none_node),
+ stop=copy.deepcopy(self.stop or none_node),
+ step=none_node
+ ).analyse_types(env)
+ else:
+ c_int = PyrexTypes.c_py_ssize_t_type
+ if self.start:
+ self.start = self.start.coerce_to(c_int, env)
+ if self.stop:
+ self.stop = self.stop.coerce_to(c_int, env)
self.is_temp = 1
return self
start_code,
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"))
+ has_c_start, c_start, py_start = False, '0', 'NULL'
+ if self.start:
+ has_c_start = not self.start.type.is_pyobject
+ if has_c_start:
+ c_start = self.start.result()
+ else:
+ py_start = '&%s' % self.start.py_result()
+ has_c_stop, c_stop, py_stop = False, '0', 'NULL'
+ if self.stop:
+ has_c_stop = not self.stop.type.is_pyobject
+ if has_c_stop:
+ c_stop = self.stop.result()
+ else:
+ py_stop = '&%s' % self.stop.py_result()
+ py_slice = self.slice and '&%s' % self.slice.py_result() or 'NULL'
+ code.putln(
+ "%s = __Pyx_PySequence_GetObjectSlice(%s, %s, %s, %s, %s, %s, %d, %d); %s" % (
+ result,
+ self.base.py_result(),
+ c_start, c_stop,
+ py_start, py_stop, py_slice,
+ has_c_start, has_c_stop,
+ code.error_goto_if_null(result, self.pos)))
else:
if self.base.type is list_type:
code.globalstate.use_utility_code(
}
+/////////////// GetObjectSlice.proto ///////////////
+
+// we pass pointer addresses to show the C compiler what is NULL and what isn't
+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);
+
+/////////////// 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) {
+ 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) {
+ cstop = __Pyx_PyIndex_AsSsize_t(*_py_stop);
+ if ((cstop == (Py_ssize_t)-1) && PyErr_Occurred()) return NULL;
+ } else
+ cstop = PY_SSIZE_T_MAX;
+ }
+ 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;
+}
+
/////////////// SliceTupleAndList.proto ///////////////
#if CYTHON_COMPILING_IN_CPYTHON