Commit 6c86783d authored by Stefan Behnel's avatar Stefan Behnel Committed by Vitja Makarov

rewrite of the tuple unpacking code

according to unladen swallows' bm_unpack_sequence benchmark:
- ~25% faster for tuples (60% faster than CPython 2.7)
- ~3x faster for lists (40% faster than CPython 2.7)
also, apparently using less memory during gcc compilation

--HG--
extra : rebase_source : 1069d7a0c9c338c16e96cc289114e0d0052a7588
parent c7a2101b
This diff is collapsed.
...@@ -7,9 +7,21 @@ def _it(N): ...@@ -7,9 +7,21 @@ def _it(N):
for i in range(N): for i in range(N):
yield i yield i
def f(obj1, obj2, obj3, obj4, obj5): cdef class ItCount(object):
cdef object values
cdef readonly count
def __init__(self, values):
self.values = iter(values)
self.count = 0
def __iter__(self):
return self
def __next__(self):
self.count += 1
return next(self.values)
def kunterbunt(obj1, obj2, obj3, obj4, obj5):
""" """
>>> f(1, (2,), (3,4,5), (6,(7,(8,9))), 0) >>> kunterbunt(1, (2,), (3,4,5), (6,(7,(8,9))), 0)
(8, 9, (8, 9), (6, (7, (8, 9))), 0) (8, 9, (8, 9), (6, (7, (8, 9))), 0)
""" """
obj1, = obj2 obj1, = obj2
...@@ -19,16 +31,177 @@ def f(obj1, obj2, obj3, obj4, obj5): ...@@ -19,16 +31,177 @@ def f(obj1, obj2, obj3, obj4, obj5):
[obj1, obj2] = obj3 [obj1, obj2] = obj3
return obj1, obj2, obj3, obj4, obj5 return obj1, obj2, obj3, obj4, obj5
def unpack_tuple(tuple it):
"""
>>> unpack_tuple((1,2,3))
(1, 2, 3)
>>> a,b,c = None
Traceback (most recent call last):
TypeError: 'NoneType' object is not iterable
>>> unpack_tuple(None)
Traceback (most recent call last):
TypeError: 'NoneType' object is not iterable
"""
a,b,c = it
return a,b,c
def unpack_list(list it):
"""
>>> unpack_list([1,2,3])
(1, 2, 3)
>>> a,b,c = None
Traceback (most recent call last):
TypeError: 'NoneType' object is not iterable
>>> unpack_list(None)
Traceback (most recent call last):
TypeError: 'NoneType' object is not iterable
"""
a,b,c = it
return a,b,c
def unpack_to_itself(it):
"""
>>> it = _it(2)
>>> it, it = it
>>> it
1
>>> unpack_to_itself([1,2])
2
>>> unpack_to_itself((1,2))
2
>>> unpack_to_itself(_it(2))
1
>>> unpack_to_itself((1,2,3))
Traceback (most recent call last):
ValueError: too many values to unpack (expected 2)
>>> unpack_to_itself(_it(3))
Traceback (most recent call last):
ValueError: too many values to unpack (expected 2)
"""
it, it = it
return it
def unpack_partial(it):
"""
>>> it = _it(2)
>>> a = b = c = 0
>>> a,b,c = it
Traceback (most recent call last):
ValueError: need more than 2 values to unpack
>>> a, b, c
(0, 0, 0)
>>> unpack_partial([1,2])
(0, 0, 0)
>>> unpack_partial((1,2))
(0, 0, 0)
>>> unpack_partial(_it(2))
(0, 0, 0)
>>> it = ItCount([1,2])
>>> a = b = c = 0
>>> a,b,c = it
Traceback (most recent call last):
ValueError: need more than 2 values to unpack
>>> a, b, c
(0, 0, 0)
>>> it.count
3
>>> it = ItCount([1,2])
>>> unpack_partial(it)
(0, 0, 0)
>>> it.count
3
"""
a = b = c = 0
try:
a, b, c = it
except ValueError:
pass
return a, b, c
def unpack_fail_assignment(it):
"""
>>> it = ItCount([1, 2, 3])
>>> a = b = c = 0
>>> try: a, b[0], c = it
... except TypeError: pass
>>> a,b,c
(1, 0, 0)
>>> it.count
4
>>> it = ItCount([1, 2, 3])
>>> unpack_fail_assignment(it)
(1, 0, 0)
>>> it.count
4
"""
cdef object a,b,c
a = b = c = 0
try:
a, b[0], c = it
except TypeError:
pass
return a, b, c
def unpack_partial_typed(it):
"""
>>> unpack_partial_typed([1, 2, 'abc'])
(0, 0, 0)
>>> unpack_partial_typed((1, 'abc', 3))
(0, 0, 0)
>>> unpack_partial_typed(_set([1, 'abc', 3]))
(0, 0, 0)
>>> it = ItCount([1, 'abc', 3])
>>> unpack_partial_typed(it)
(0, 0, 0)
>>> it.count
4
"""
cdef int a,b,c
a = b = c = 0
try:
a, b, c = it
except TypeError:
pass
return a, b, c
def unpack_typed(it): def unpack_typed(it):
""" """
>>> unpack_typed((1, 2.0, [1])) >>> unpack_typed((1, 2.0, [1]))
(1, 2.0, [1]) (1, 2.0, [1])
>>> unpack_typed([1, 2.0, [1]])
(1, 2.0, [1])
>>> it = ItCount([1, 2.0, [1]])
>>> unpack_typed(it)
(1, 2.0, [1])
>>> it.count
4
>>> unpack_typed((1, None, [1])) >>> unpack_typed((1, None, [1]))
Traceback (most recent call last): Traceback (most recent call last):
TypeError: a float is required TypeError: a float is required
>>> unpack_typed([1, None, [1]])
Traceback (most recent call last):
TypeError: a float is required
>>> it = ItCount([1, None, [1]])
>>> unpack_typed(it)
Traceback (most recent call last):
TypeError: a float is required
>>> it.count
4
>>> unpack_typed((1, 2.0, (1,))) >>> unpack_typed((1, 2.0, (1,)))
Traceback (most recent call last): Traceback (most recent call last):
TypeError: Expected list, got tuple TypeError: Expected list, got tuple
>>> it = ItCount([1, 2.0, (1,)])
>>> unpack_typed(it)
Traceback (most recent call last):
TypeError: Expected list, got tuple
>>> it.count
4
""" """
cdef int a cdef int a
cdef float b cdef float b
...@@ -67,6 +240,7 @@ def failure_too_many(it): ...@@ -67,6 +240,7 @@ def failure_too_many(it):
ValueError: too many values to unpack (expected 3) ValueError: too many values to unpack (expected 3)
""" """
a,b,c = it a,b,c = it
return a,b,c
def failure_too_few(it): def failure_too_few(it):
""" """
...@@ -99,6 +273,7 @@ def failure_too_few(it): ...@@ -99,6 +273,7 @@ def failure_too_few(it):
ValueError: need more than 2 values to unpack ValueError: need more than 2 values to unpack
""" """
a,b,c = it a,b,c = it
return a,b,c
def _it_failure(N): def _it_failure(N):
for i in range(N): for i in range(N):
...@@ -143,3 +318,4 @@ def failure_while_unpacking(it): ...@@ -143,3 +318,4 @@ def failure_while_unpacking(it):
ValueError: too many values to unpack (expected 3) ValueError: too many values to unpack (expected 3)
""" """
a,b,c = it a,b,c = it
return a,b,c
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