96a64ba31caab501ac6b39f53f09c759dd100064
1 ##############################################################################
2 #
3 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
4 #
5 # This software is subject to the provisions of the Zope Public License,
6 # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
10 # FOR A PARTICULAR PURPOSE
11 #
12 ##############################################################################
13 __doc__='''Iterator class
15 Unlike the builtin iterators of Python 2.2+, these classes are
16 designed to maintain information about the state of an iteration.
17 The Iterator() function accepts either a sequence or a Python
18 iterator. The next() method fetches the next item, and returns
19 true if it succeeds.
21 $Id: Iterator.py,v 1.3 2004-02-11 23:55:09 richard Exp $'''
22 __docformat__ = 'restructuredtext'
23 __version__='$Revision: 1.3 $'[11:-2]
25 import string
27 class Iterator:
28 '''Simple Iterator class'''
30 __allow_access_to_unprotected_subobjects__ = 1
32 nextIndex = 0
33 def __init__(self, seq):
34 self.seq = seq
35 for inner in seqInner, iterInner:
36 if inner._supports(seq):
37 self._inner = inner
38 self._prep_next = inner.prep_next
39 return
40 raise TypeError, "Iterator does not support %s" % `seq`
42 def __getattr__(self, name):
43 try:
44 inner = getattr(self._inner, 'it_' + name)
45 except AttributeError:
46 raise AttributeError, name
47 return inner(self)
49 def next(self):
50 if not (hasattr(self, '_next') or self._prep_next(self)):
51 return 0
52 self.index = i = self.nextIndex
53 self.nextIndex = i+1
54 self._advance(self)
55 return 1
57 def _advance(self, it):
58 self.item = self._next
59 del self._next
60 del self.end
61 self._advance = self._inner.advance
62 self.start = 1
64 def number(self): return self.nextIndex
66 def even(self): return not self.index % 2
68 def odd(self): return self.index % 2
70 def letter(self, base=ord('a'), radix=26):
71 index = self.index
72 s = ''
73 while 1:
74 index, off = divmod(index, radix)
75 s = chr(base + off) + s
76 if not index: return s
78 def Letter(self):
79 return self.letter(base=ord('A'))
81 def Roman(self, rnvalues=(
82 (1000,'M'),(900,'CM'),(500,'D'),(400,'CD'),
83 (100,'C'),(90,'XC'),(50,'L'),(40,'XL'),
84 (10,'X'),(9,'IX'),(5,'V'),(4,'IV'),(1,'I')) ):
85 n = self.index + 1
86 s = ''
87 for v, r in rnvalues:
88 rct, n = divmod(n, v)
89 s = s + r * rct
90 return s
92 def roman(self, lower=string.lower):
93 return lower(self.Roman())
95 def first(self, name=None):
96 if self.start: return 1
97 return not self.same_part(name, self._last, self.item)
99 def last(self, name=None):
100 if self.end: return 1
101 return not self.same_part(name, self.item, self._next)
103 def same_part(self, name, ob1, ob2):
104 if name is None:
105 return ob1 == ob2
106 no = []
107 return getattr(ob1, name, no) == getattr(ob2, name, no) is not no
109 def __iter__(self):
110 return IterIter(self)
112 class InnerBase:
113 '''Base Inner class for Iterators'''
114 # Prep sets up ._next and .end
115 def prep_next(self, it):
116 it.next = self.no_next
117 it.end = 1
118 return 0
120 # Advance knocks them down
121 def advance(self, it):
122 it._last = it.item
123 it.item = it._next
124 del it._next
125 del it.end
126 it.start = 0
128 def no_next(self, it):
129 return 0
131 def it_end(self, it):
132 if hasattr(it, '_next'):
133 return 0
134 return not self.prep_next(it)
136 class SeqInner(InnerBase):
137 '''Inner class for sequence Iterators'''
139 def _supports(self, ob):
140 try: ob[0]
141 except (TypeError, AttributeError): return 0
142 except: pass
143 return 1
145 def prep_next(self, it):
146 i = it.nextIndex
147 try:
148 it._next = it.seq[i]
149 except IndexError:
150 it._prep_next = self.no_next
151 it.end = 1
152 return 0
153 it.end = 0
154 return 1
156 def it_length(self, it):
157 it.length = l = len(it.seq)
158 return l
160 try:
161 StopIteration=StopIteration
162 except NameError:
163 StopIteration="StopIteration"
165 class IterInner(InnerBase):
166 '''Iterator inner class for Python iterators'''
168 def _supports(self, ob):
169 try:
170 if hasattr(ob, 'next') and (ob is iter(ob)):
171 return 1
172 except:
173 return 0
175 def prep_next(self, it):
176 try:
177 it._next = it.seq.next()
178 except StopIteration:
179 it._prep_next = self.no_next
180 it.end = 1
181 return 0
182 it.end = 0
183 return 1
185 class IterIter:
186 def __init__(self, it):
187 self.it = it
188 self.skip = it.nextIndex > 0 and not it.end
189 def next(self):
190 it = self.it
191 if self.skip:
192 self.skip = 0
193 return it.item
194 if it.next():
195 return it.item
196 raise StopIteration
198 seqInner = SeqInner()
199 iterInner = IterInner()