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.1 2002-09-05 00:37:09 richard Exp $'''
22 __version__='$Revision: 1.1 $'[11:-2]
24 import string
26 class Iterator:
27 '''Simple Iterator class'''
29 __allow_access_to_unprotected_subobjects__ = 1
31 nextIndex = 0
32 def __init__(self, seq):
33 self.seq = seq
34 for inner in seqInner, iterInner:
35 if inner._supports(seq):
36 self._inner = inner
37 self._prep_next = inner.prep_next
38 return
39 raise TypeError, "Iterator does not support %s" % `seq`
41 def __getattr__(self, name):
42 try:
43 inner = getattr(self._inner, 'it_' + name)
44 except AttributeError:
45 raise AttributeError, name
46 return inner(self)
48 def next(self):
49 if not (hasattr(self, '_next') or self._prep_next(self)):
50 return 0
51 self.index = i = self.nextIndex
52 self.nextIndex = i+1
53 self._advance(self)
54 return 1
56 def _advance(self, it):
57 self.item = self._next
58 del self._next
59 del self.end
60 self._advance = self._inner.advance
61 self.start = 1
63 def number(self): return self.nextIndex
65 def even(self): return not self.index % 2
67 def odd(self): return self.index % 2
69 def letter(self, base=ord('a'), radix=26):
70 index = self.index
71 s = ''
72 while 1:
73 index, off = divmod(index, radix)
74 s = chr(base + off) + s
75 if not index: return s
77 def Letter(self):
78 return self.letter(base=ord('A'))
80 def Roman(self, rnvalues=(
81 (1000,'M'),(900,'CM'),(500,'D'),(400,'CD'),
82 (100,'C'),(90,'XC'),(50,'L'),(40,'XL'),
83 (10,'X'),(9,'IX'),(5,'V'),(4,'IV'),(1,'I')) ):
84 n = self.index + 1
85 s = ''
86 for v, r in rnvalues:
87 rct, n = divmod(n, v)
88 s = s + r * rct
89 return s
91 def roman(self, lower=string.lower):
92 return lower(self.Roman())
94 def first(self, name=None):
95 if self.start: return 1
96 return not self.same_part(name, self._last, self.item)
98 def last(self, name=None):
99 if self.end: return 1
100 return not self.same_part(name, self.item, self._next)
102 def same_part(self, name, ob1, ob2):
103 if name is None:
104 return ob1 == ob2
105 no = []
106 return getattr(ob1, name, no) == getattr(ob2, name, no) is not no
108 def __iter__(self):
109 return IterIter(self)
111 class InnerBase:
112 '''Base Inner class for Iterators'''
113 # Prep sets up ._next and .end
114 def prep_next(self, it):
115 it.next = self.no_next
116 it.end = 1
117 return 0
119 # Advance knocks them down
120 def advance(self, it):
121 it._last = it.item
122 it.item = it._next
123 del it._next
124 del it.end
125 it.start = 0
127 def no_next(self, it):
128 return 0
130 def it_end(self, it):
131 if hasattr(it, '_next'):
132 return 0
133 return not self.prep_next(it)
135 class SeqInner(InnerBase):
136 '''Inner class for sequence Iterators'''
138 def _supports(self, ob):
139 try: ob[0]
140 except TypeError: return 0
141 except: pass
142 return 1
144 def prep_next(self, it):
145 i = it.nextIndex
146 try:
147 it._next = it.seq[i]
148 except IndexError:
149 it._prep_next = self.no_next
150 it.end = 1
151 return 0
152 it.end = 0
153 return 1
155 def it_length(self, it):
156 it.length = l = len(it.seq)
157 return l
159 try:
160 StopIteration=StopIteration
161 except NameError:
162 StopIteration="StopIteration"
164 class IterInner(InnerBase):
165 '''Iterator inner class for Python iterators'''
167 def _supports(self, ob):
168 try:
169 if hasattr(ob, 'next') and (ob is iter(ob)):
170 return 1
171 except:
172 return 0
174 def prep_next(self, it):
175 try:
176 it._next = it.seq.next()
177 except StopIteration:
178 it._prep_next = self.no_next
179 it.end = 1
180 return 0
181 it.end = 0
182 return 1
184 class IterIter:
185 def __init__(self, it):
186 self.it = it
187 self.skip = it.nextIndex > 0 and not it.end
188 def next(self):
189 it = self.it
190 if self.skip:
191 self.skip = 0
192 return it.item
193 if it.next():
194 return it.item
195 raise StopIteration
197 seqInner = SeqInner()
198 iterInner = IterInner()