Commit 39feb676 authored by Stefan Behnel's avatar Stefan Behnel

use optimised dict iteration also for untyped objects when the known...

use optimised dict iteration also for untyped objects when the known iterkeys/values/items() methods are used

--HG--
extra : transplant_source : %FAOM%F4%BF%9E%B68%F0%E6%A2%C8P4sz%F4%B7%DBG
parent d7ece166
......@@ -166,12 +166,8 @@ class IterationTransform(Visitor.VisitorTransform):
function = iterator.function
# dict iteration?
if isinstance(function, ExprNodes.AttributeNode) and \
function.obj.type == Builtin.dict_type:
if reversed:
# CPython raises an error here: not a sequence
return node
dict_obj = iterator.self or function.obj
if function.is_attribute and not reversed:
base_obj = iterator.self or function.obj
method = function.attribute
is_py3 = self.module_scope.context.language_level >= 3
......@@ -182,10 +178,10 @@ class IterationTransform(Visitor.VisitorTransform):
values = True
elif method == 'iteritems' or (is_py3 and method == 'items'):
keys = values = True
else:
return node
return self._transform_dict_iteration(
node, dict_obj, method, keys, values)
if keys or values:
return self._transform_dict_iteration(
node, base_obj, method, keys, values)
# enumerate/reversed ?
if iterator.self is None and function.is_name and \
......
......@@ -36,9 +36,29 @@ def iteritems(dict d):
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode//DictIterationNextNode")
def iteritems_dict(dict d):
def optimistic_iteritems(d):
"""
>>> iteritems_dict(d)
>>> optimistic_iteritems(d)
[(10, 0), (11, 1), (12, 2), (13, 3)]
>>> optimistic_iteritems({})
[]
>>> class mydict(object):
... def iteritems(self): return d.items()
>>> optimistic_iteritems(mydict())
[(10, 0), (11, 1), (12, 2), (13, 3)]
"""
l = []
for k,v in d.iteritems():
l.append((k,v))
l.sort()
return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode//DictIterationNextNode")
def iteritems_dict():
"""
>>> iteritems_dict()
[(11, 1), (12, 2), (13, 3)]
"""
l = []
......@@ -73,6 +93,37 @@ def iteritems_int(dict d):
l.sort()
return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode//DictIterationNextNode")
def optimistic_iteritems_int(d):
"""
>>> optimistic_iteritems_int(d)
[(10, 0), (11, 1), (12, 2), (13, 3)]
>>> optimistic_iteritems_int({})
[]
>>> class mydict(object):
... def iteritems(self): return d.items()
>>> optimistic_iteritems_int(mydict())
[(10, 0), (11, 1), (12, 2), (13, 3)]
>>> optimistic_iteritems_int({'a': 1})
Traceback (most recent call last):
TypeError: an integer is required
>>> optimistic_iteritems_int({1: 'b'})
Traceback (most recent call last):
TypeError: an integer is required
>>> optimistic_iteritems_int({'a': 'b'})
Traceback (most recent call last):
TypeError: an integer is required
"""
cdef int k,v
l = []
for k,v in d.iteritems():
l.append((k,v))
l.sort()
return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode//DictIterationNextNode")
......@@ -113,6 +164,26 @@ def iterkeys(dict d):
l.sort()
return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode//DictIterationNextNode")
def optimistic_iterkeys(d):
"""
>>> optimistic_iterkeys(d)
[10, 11, 12, 13]
>>> optimistic_iterkeys({})
[]
>>> class mydict(object):
... def iterkeys(self): return d
>>> optimistic_iterkeys(mydict())
[10, 11, 12, 13]
"""
l = []
for k in d.iterkeys():
l.append(k)
l.sort()
return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode//DictIterationNextNode")
......@@ -217,6 +288,26 @@ def itervalues(dict d):
l.sort()
return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode//DictIterationNextNode")
def optimistic_itervalues(d):
"""
>>> optimistic_itervalues(d)
[0, 1, 2, 3]
>>> optimistic_itervalues({})
[]
>>> class mydict(object):
... def itervalues(self): return d.values()
>>> optimistic_itervalues(mydict())
[0, 1, 2, 3]
"""
l = []
for v in d.itervalues():
l.append(v)
l.sort()
return l
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode//DictIterationNextNode")
......@@ -294,3 +385,40 @@ def iterdict_change_size(dict d):
if count > 5:
break # safety
return "DONE"
@cython.test_assert_path_exists(
"//WhileStatNode",
"//WhileStatNode//DictIterationNextNode")
def optimistic_iterdict_change_size(d):
"""
>>> count, i = 0, -1
>>> d = {1:2, 10:20}
>>> for i in d:
... d[i+1] = 5
... count += 1
... if count > 5:
... break # safety
Traceback (most recent call last):
RuntimeError: dictionary changed size during iteration
>>> optimistic_iterdict_change_size({1:2, 10:20})
Traceback (most recent call last):
RuntimeError: dictionary changed size during iteration
>>> print( optimistic_iterdict_change_size({}) )
DONE
>>> class mydict(object):
... _d = {1:2, 10:20}
... def iterkeys(self): return self._d
... def __setitem__(self, key, value): self._d[key] = value
>>> optimistic_iterdict_change_size(mydict())
Traceback (most recent call last):
RuntimeError: dictionary changed size during iteration
"""
cdef int count = 0
i = -1
for i in d.iterkeys():
d[i+1] = 5
count += 1
if count > 5:
break # safety
return "DONE"
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