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): ...@@ -166,12 +166,8 @@ class IterationTransform(Visitor.VisitorTransform):
function = iterator.function function = iterator.function
# dict iteration? # dict iteration?
if isinstance(function, ExprNodes.AttributeNode) and \ if function.is_attribute and not reversed:
function.obj.type == Builtin.dict_type: base_obj = iterator.self or function.obj
if reversed:
# CPython raises an error here: not a sequence
return node
dict_obj = iterator.self or function.obj
method = function.attribute method = function.attribute
is_py3 = self.module_scope.context.language_level >= 3 is_py3 = self.module_scope.context.language_level >= 3
...@@ -182,10 +178,10 @@ class IterationTransform(Visitor.VisitorTransform): ...@@ -182,10 +178,10 @@ class IterationTransform(Visitor.VisitorTransform):
values = True values = True
elif method == 'iteritems' or (is_py3 and method == 'items'): elif method == 'iteritems' or (is_py3 and method == 'items'):
keys = values = True keys = values = True
else:
return node if keys or values:
return self._transform_dict_iteration( return self._transform_dict_iteration(
node, dict_obj, method, keys, values) node, base_obj, method, keys, values)
# enumerate/reversed ? # enumerate/reversed ?
if iterator.self is None and function.is_name and \ if iterator.self is None and function.is_name and \
......
...@@ -36,9 +36,29 @@ def iteritems(dict d): ...@@ -36,9 +36,29 @@ def iteritems(dict d):
@cython.test_assert_path_exists( @cython.test_assert_path_exists(
"//WhileStatNode", "//WhileStatNode",
"//WhileStatNode//DictIterationNextNode") "//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)] [(11, 1), (12, 2), (13, 3)]
""" """
l = [] l = []
...@@ -73,6 +93,37 @@ def iteritems_int(dict d): ...@@ -73,6 +93,37 @@ def iteritems_int(dict d):
l.sort() l.sort()
return l 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( @cython.test_assert_path_exists(
"//WhileStatNode", "//WhileStatNode",
"//WhileStatNode//DictIterationNextNode") "//WhileStatNode//DictIterationNextNode")
...@@ -113,6 +164,26 @@ def iterkeys(dict d): ...@@ -113,6 +164,26 @@ def iterkeys(dict d):
l.sort() l.sort()
return l 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( @cython.test_assert_path_exists(
"//WhileStatNode", "//WhileStatNode",
"//WhileStatNode//DictIterationNextNode") "//WhileStatNode//DictIterationNextNode")
...@@ -217,6 +288,26 @@ def itervalues(dict d): ...@@ -217,6 +288,26 @@ def itervalues(dict d):
l.sort() l.sort()
return l 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( @cython.test_assert_path_exists(
"//WhileStatNode", "//WhileStatNode",
"//WhileStatNode//DictIterationNextNode") "//WhileStatNode//DictIterationNextNode")
...@@ -294,3 +385,40 @@ def iterdict_change_size(dict d): ...@@ -294,3 +385,40 @@ def iterdict_change_size(dict d):
if count > 5: if count > 5:
break # safety break # safety
return "DONE" 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