Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / devtools / v9 / lib / python2.4 / test / test_iterlen.py
CommitLineData
920dae64
AT
1""" Test Iterator Length Transparency
2
3Some functions or methods which accept general iterable arguments have
4optional, more efficient code paths if they know how many items to expect.
5For instance, map(func, iterable), will pre-allocate the exact amount of
6space required whenever the iterable can report its length.
7
8The desired invariant is: len(it)==len(list(it)).
9
10A complication is that an iterable and iterator can be the same object. To
11maintain the invariant, an iterator needs to dynamically update its length.
12For instance, an iterable such as xrange(10) always reports its length as ten,
13but it=iter(xrange(10)) starts at ten, and then goes to nine after it.next().
14Having this capability means that map() can ignore the distinction between
15map(func, iterable) and map(func, iter(iterable)).
16
17When the iterable is immutable, the implementation can straight-forwardly
18report the original length minus the cumulative number of calls to next().
19This is the case for tuples, xrange objects, and itertools.repeat().
20
21Some containers become temporarily immutable during iteration. This includes
22dicts, sets, and collections.deque. Their implementation is equally simple
23though they need to permantently set their length to zero whenever there is
24an attempt to iterate after a length mutation.
25
26The situation slightly more involved whenever an object allows length mutation
27during iteration. Lists and sequence iterators are dynanamically updatable.
28So, if a list is extended during iteration, the iterator will continue through
29the new items. If it shrinks to a point before the most recent iteration,
30then no further items are available and the length is reported at zero.
31
32Reversed objects can also be wrapped around mutable objects; however, any
33appends after the current position are ignored. Any other approach leads
34to confusion and possibly returning the same item more than once.
35
36The iterators not listed above, such as enumerate and the other itertools,
37are not length transparent because they have no way to distinguish between
38iterables that report static length and iterators whose length changes with
39each call (i.e. the difference between enumerate('abc') and
40enumerate(iter('abc')).
41
42"""
43
44import unittest
45from test import test_support
46from itertools import repeat, count
47from collections import deque
48from UserList import UserList
49
50n = 10
51
52class TestInvariantWithoutMutations(unittest.TestCase):
53
54 def test_invariant(self):
55 it = self.it
56 for i in reversed(xrange(1, n+1)):
57 self.assertEqual(len(it), i)
58 it.next()
59 self.assertEqual(len(it), 0)
60 self.assertRaises(StopIteration, it.next)
61 self.assertEqual(len(it), 0)
62
63class TestTemporarilyImmutable(TestInvariantWithoutMutations):
64
65 def test_immutable_during_iteration(self):
66 # objects such as deques, sets, and dictionaries enforce
67 # length immutability during iteration
68
69 it = self.it
70 self.assertEqual(len(it), n)
71 it.next()
72 self.assertEqual(len(it), n-1)
73 self.mutate()
74 self.assertRaises(RuntimeError, it.next)
75 self.assertEqual(len(it), 0)
76
77## ------- Concrete Type Tests -------
78
79class TestRepeat(TestInvariantWithoutMutations):
80
81 def setUp(self):
82 self.it = repeat(None, n)
83
84 def test_no_len_for_infinite_repeat(self):
85 # The repeat() object can also be infinite
86 self.assertRaises(TypeError, len, repeat(None))
87
88class TestXrange(TestInvariantWithoutMutations):
89
90 def setUp(self):
91 self.it = iter(xrange(n))
92
93class TestXrangeCustomReversed(TestInvariantWithoutMutations):
94
95 def setUp(self):
96 self.it = reversed(xrange(n))
97
98class TestTuple(TestInvariantWithoutMutations):
99
100 def setUp(self):
101 self.it = iter(tuple(xrange(n)))
102
103## ------- Types that should not be mutated during iteration -------
104
105class TestDeque(TestTemporarilyImmutable):
106
107 def setUp(self):
108 d = deque(xrange(n))
109 self.it = iter(d)
110 self.mutate = d.pop
111
112class TestDequeReversed(TestTemporarilyImmutable):
113
114 def setUp(self):
115 d = deque(xrange(n))
116 self.it = reversed(d)
117 self.mutate = d.pop
118
119class TestDictKeys(TestTemporarilyImmutable):
120
121 def setUp(self):
122 d = dict.fromkeys(xrange(n))
123 self.it = iter(d)
124 self.mutate = d.popitem
125
126class TestDictItems(TestTemporarilyImmutable):
127
128 def setUp(self):
129 d = dict.fromkeys(xrange(n))
130 self.it = d.iteritems()
131 self.mutate = d.popitem
132
133class TestDictValues(TestTemporarilyImmutable):
134
135 def setUp(self):
136 d = dict.fromkeys(xrange(n))
137 self.it = d.itervalues()
138 self.mutate = d.popitem
139
140class TestSet(TestTemporarilyImmutable):
141
142 def setUp(self):
143 d = set(xrange(n))
144 self.it = iter(d)
145 self.mutate = d.pop
146
147## ------- Types that can mutate during iteration -------
148
149class TestList(TestInvariantWithoutMutations):
150
151 def setUp(self):
152 self.it = iter(range(n))
153
154 def test_mutation(self):
155 d = range(n)
156 it = iter(d)
157 it.next()
158 it.next()
159 self.assertEqual(len(it), n-2)
160 d.append(n)
161 self.assertEqual(len(it), n-1) # grow with append
162 d[1:] = []
163 self.assertEqual(len(it), 0)
164 self.assertEqual(list(it), [])
165 d.extend(xrange(20))
166 self.assertEqual(len(it), 0)
167
168class TestListReversed(TestInvariantWithoutMutations):
169
170 def setUp(self):
171 self.it = reversed(range(n))
172
173 def test_mutation(self):
174 d = range(n)
175 it = reversed(d)
176 it.next()
177 it.next()
178 self.assertEqual(len(it), n-2)
179 d.append(n)
180 self.assertEqual(len(it), n-2) # ignore append
181 d[1:] = []
182 self.assertEqual(len(it), 0)
183 self.assertEqual(list(it), []) # confirm invariant
184 d.extend(xrange(20))
185 self.assertEqual(len(it), 0)
186
187class TestSeqIter(TestInvariantWithoutMutations):
188
189 def setUp(self):
190 self.it = iter(UserList(range(n)))
191
192 def test_mutation(self):
193 d = UserList(range(n))
194 it = iter(d)
195 it.next()
196 it.next()
197 self.assertEqual(len(it), n-2)
198 d.append(n)
199 self.assertEqual(len(it), n-1) # grow with append
200 d[1:] = []
201 self.assertEqual(len(it), 0)
202 self.assertEqual(list(it), [])
203 d.extend(xrange(20))
204 self.assertEqual(len(it), 0)
205
206class TestSeqIterReversed(TestInvariantWithoutMutations):
207
208 def setUp(self):
209 self.it = reversed(UserList(range(n)))
210
211 def test_mutation(self):
212 d = UserList(range(n))
213 it = reversed(d)
214 it.next()
215 it.next()
216 self.assertEqual(len(it), n-2)
217 d.append(n)
218 self.assertEqual(len(it), n-2) # ignore append
219 d[1:] = []
220 self.assertEqual(len(it), 0)
221 self.assertEqual(list(it), []) # confirm invariant
222 d.extend(xrange(20))
223 self.assertEqual(len(it), 0)
224
225
226
227if __name__ == "__main__":
228
229 unittests = [
230 TestRepeat,
231 TestXrange,
232 TestXrangeCustomReversed,
233 TestTuple,
234 TestDeque,
235 TestDequeReversed,
236 TestDictKeys,
237 TestDictItems,
238 TestDictValues,
239 TestSet,
240 TestList,
241 TestListReversed,
242 TestSeqIter,
243 TestSeqIterReversed,
244 ]
245 test_support.run_unittest(*unittests)