Commit 51e11ec5 authored by Stefan Behnel's avatar Stefan Behnel

include fast list/tuple iteration in dict iteration optimisation to prevent...

include fast list/tuple iteration in dict iteration optimisation to prevent performance regressions for the too-optimistic optimisation case
parent 73eb7a82
...@@ -310,36 +310,41 @@ static CYTHON_INLINE int __Pyx_dict_iter_next(PyObject* dict_or_iter, Py_ssize_t ...@@ -310,36 +310,41 @@ static CYTHON_INLINE int __Pyx_dict_iter_next(PyObject* dict_or_iter, Py_ssize_t
//@requires: ObjectHandling.c::UnpackTuple2 //@requires: ObjectHandling.c::UnpackTuple2
//@requires: ObjectHandling.c::IterFinish //@requires: ObjectHandling.c::IterFinish
static CYTHON_INLINE PyObject* __Pyx_dict_iterator(PyObject* dict, int is_dict, PyObject* method_name, static CYTHON_INLINE PyObject* __Pyx_dict_iterator(PyObject* iterable, int is_dict, PyObject* method_name,
Py_ssize_t* p_orig_length, int* p_is_dict) { Py_ssize_t* p_orig_length, int* p_is_dict) {
#if !CYTHON_COMPILING_IN_PYPY #if !CYTHON_COMPILING_IN_PYPY
if (is_dict || likely(PyDict_CheckExact(dict))) { if (is_dict || likely(PyDict_CheckExact(iterable))) {
*p_is_dict = 1; *p_is_dict = 1;
*p_orig_length = PyDict_Size(dict); *p_orig_length = PyDict_Size(iterable);
Py_INCREF(dict); Py_INCREF(iterable);
return dict; return iterable;
} }
#endif #endif
*p_is_dict = 0; *p_is_dict = 0;
*p_orig_length = 0; *p_orig_length = 0;
if (method_name) { if (method_name) {
dict = PyObject_CallMethodObjArgs(dict, method_name, NULL); iterable = PyObject_CallMethodObjArgs(iterable, method_name, NULL);
if (!dict) if (!iterable)
return NULL; return NULL;
#if !CYTHON_COMPILING_IN_PYPY
if (PyTuple_CheckExact(iterable) || PyList_CheckExact(iterable))
return iterable;
#endif
} }
return PyObject_GetIter(dict); return PyObject_GetIter(iterable);
} }
static CYTHON_INLINE int __Pyx_dict_iter_next(PyObject* dict_or_iter, Py_ssize_t orig_length, Py_ssize_t* ppos, static CYTHON_INLINE int __Pyx_dict_iter_next(PyObject* iter_obj, Py_ssize_t orig_length, Py_ssize_t* ppos,
PyObject** pkey, PyObject** pvalue, PyObject** pitem, int is_dict) { PyObject** pkey, PyObject** pvalue, PyObject** pitem, int is_dict) {
PyObject* next_item;
#if !CYTHON_COMPILING_IN_PYPY #if !CYTHON_COMPILING_IN_PYPY
if (is_dict) { if (is_dict) {
PyObject *key, *value; PyObject *key, *value;
if (unlikely(orig_length != PyDict_Size(dict_or_iter))) { if (unlikely(orig_length != PyDict_Size(iter_obj))) {
PyErr_SetString(PyExc_RuntimeError, "dictionary changed size during iteration"); PyErr_SetString(PyExc_RuntimeError, "dictionary changed size during iteration");
return -1; return -1;
} }
if (unlikely(!PyDict_Next(dict_or_iter, ppos, &key, &value))) { if (unlikely(!PyDict_Next(iter_obj, ppos, &key, &value))) {
return 0; return 0;
} }
if (pitem) { if (pitem) {
...@@ -363,25 +368,37 @@ static CYTHON_INLINE int __Pyx_dict_iter_next(PyObject* dict_or_iter, Py_ssize_t ...@@ -363,25 +368,37 @@ static CYTHON_INLINE int __Pyx_dict_iter_next(PyObject* dict_or_iter, Py_ssize_t
} }
} }
return 1; return 1;
} } else if (PyTuple_CheckExact(iter_obj)) {
Py_ssize_t pos = *ppos;
if (unlikely(pos >= PyTuple_GET_SIZE(iter_obj))) return 0;
*ppos = pos + 1;
next_item = PyTuple_GET_ITEM(iter_obj, pos);
Py_INCREF(next_item);
} else if (PyList_CheckExact(iter_obj)) {
Py_ssize_t pos = *ppos;
if (unlikely(pos >= PyList_GET_SIZE(iter_obj))) return 0;
*ppos = pos + 1;
next_item = PyList_GET_ITEM(iter_obj, pos);
Py_INCREF(next_item);
} else
#endif #endif
{ {
PyObject* next_item = PyIter_Next(dict_or_iter); next_item = PyIter_Next(iter_obj);
if (unlikely(!next_item)) { if (unlikely(!next_item)) {
return __Pyx_IterFinish(); return __Pyx_IterFinish();
} }
if (pitem) {
*pitem = next_item;
} else if (pkey && pvalue) {
if (__Pyx_unpack_tuple2(next_item, pkey, pvalue, is_dict, is_dict, 1))
return -1;
} else if (pkey) {
*pkey = next_item;
} else {
*pvalue = next_item;
}
return 1;
} }
if (pitem) {
*pitem = next_item;
} else if (pkey && pvalue) {
if (__Pyx_unpack_tuple2(next_item, pkey, pvalue, is_dict, is_dict, 1))
return -1;
} else if (pkey) {
*pkey = next_item;
} else {
*pvalue = next_item;
}
return 1;
} }
/////////////// pyobject_as_double.proto /////////////// /////////////// pyobject_as_double.proto ///////////////
......
...@@ -43,8 +43,13 @@ def optimistic_iteritems(d): ...@@ -43,8 +43,13 @@ def optimistic_iteritems(d):
>>> optimistic_iteritems({}) >>> optimistic_iteritems({})
[] []
>>> class mydict(object): >>> class mydict(object):
... def iteritems(self): return d.items() ... def __init__(self, t): self.t = t
>>> optimistic_iteritems(mydict()) ... def iteritems(self): return self.t(d.items())
>>> optimistic_iteritems(mydict(list))
[(10, 0), (11, 1), (12, 2), (13, 3)]
>>> optimistic_iteritems(mydict(tuple))
[(10, 0), (11, 1), (12, 2), (13, 3)]
>>> optimistic_iteritems(mydict(iter))
[(10, 0), (11, 1), (12, 2), (13, 3)] [(10, 0), (11, 1), (12, 2), (13, 3)]
""" """
l = [] l = []
...@@ -103,8 +108,13 @@ def optimistic_iteritems_int(d): ...@@ -103,8 +108,13 @@ def optimistic_iteritems_int(d):
>>> optimistic_iteritems_int({}) >>> optimistic_iteritems_int({})
[] []
>>> class mydict(object): >>> class mydict(object):
... def iteritems(self): return d.items() ... def __init__(self, t): self.t = t
>>> optimistic_iteritems_int(mydict()) ... def iteritems(self): return self.t(d.items())
>>> optimistic_iteritems_int(mydict(list))
[(10, 0), (11, 1), (12, 2), (13, 3)]
>>> optimistic_iteritems_int(mydict(tuple))
[(10, 0), (11, 1), (12, 2), (13, 3)]
>>> optimistic_iteritems_int(mydict(iter))
[(10, 0), (11, 1), (12, 2), (13, 3)] [(10, 0), (11, 1), (12, 2), (13, 3)]
>>> optimistic_iteritems_int({'a': 1}) >>> optimistic_iteritems_int({'a': 1})
...@@ -174,8 +184,17 @@ def optimistic_iterkeys(d): ...@@ -174,8 +184,17 @@ def optimistic_iterkeys(d):
>>> optimistic_iterkeys({}) >>> optimistic_iterkeys({})
[] []
>>> class mydict(object): >>> class mydict(object):
... def iterkeys(self): return d ... def __init__(self, t): self.t = t
>>> optimistic_iterkeys(mydict()) ... def iterkeys(self): return self.t(d)
>>> optimistic_iterkeys(mydict(lambda x:x))
[10, 11, 12, 13]
>>> optimistic_iterkeys(mydict(lambda x:x.keys()))
[10, 11, 12, 13]
>>> optimistic_iterkeys(mydict(list))
[10, 11, 12, 13]
>>> optimistic_iterkeys(mydict(tuple))
[10, 11, 12, 13]
>>> optimistic_iterkeys(mydict(iter))
[10, 11, 12, 13] [10, 11, 12, 13]
""" """
l = [] l = []
...@@ -298,8 +317,15 @@ def optimistic_itervalues(d): ...@@ -298,8 +317,15 @@ def optimistic_itervalues(d):
>>> optimistic_itervalues({}) >>> optimistic_itervalues({})
[] []
>>> class mydict(object): >>> class mydict(object):
... def itervalues(self): return d.values() ... def __init__(self, t): self.t = t
>>> optimistic_itervalues(mydict()) ... def itervalues(self): return self.t(d.values())
>>> optimistic_itervalues(mydict(lambda x:x))
[0, 1, 2, 3]
>>> optimistic_itervalues(mydict(list))
[0, 1, 2, 3]
>>> optimistic_itervalues(mydict(tuple))
[0, 1, 2, 3]
>>> optimistic_itervalues(mydict(iter))
[0, 1, 2, 3] [0, 1, 2, 3]
""" """
l = [] l = []
......
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