diff roundup/cgi/ZTUtils/Iterator.py @ 1049:b9988e118055

moved
author Richard Jones <richard@users.sourceforge.net>
date Thu, 05 Sep 2002 00:37:09 +0000
parents
children 69bf0d381fd7
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/roundup/cgi/ZTUtils/Iterator.py	Thu Sep 05 00:37:09 2002 +0000
@@ -0,0 +1,198 @@
+##############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+# 
+##############################################################################
+__doc__='''Iterator class
+
+Unlike the builtin iterators of Python 2.2+, these classes are
+designed to maintain information about the state of an iteration.
+The Iterator() function accepts either a sequence or a Python
+iterator.  The next() method fetches the next item, and returns
+true if it succeeds.
+
+$Id: Iterator.py,v 1.1 2002-09-05 00:37:09 richard Exp $'''
+__version__='$Revision: 1.1 $'[11:-2]
+
+import string
+
+class Iterator:
+    '''Simple Iterator class'''
+
+    __allow_access_to_unprotected_subobjects__ = 1
+
+    nextIndex = 0
+    def __init__(self, seq):
+        self.seq = seq
+        for inner in seqInner, iterInner:
+            if inner._supports(seq):
+                self._inner = inner
+                self._prep_next = inner.prep_next
+                return
+        raise TypeError, "Iterator does not support %s" % `seq`
+
+    def __getattr__(self, name):
+        try:
+            inner = getattr(self._inner, 'it_' + name)
+        except AttributeError:
+            raise AttributeError, name
+        return inner(self)
+
+    def next(self):
+        if not (hasattr(self, '_next') or self._prep_next(self)):
+            return 0
+        self.index = i = self.nextIndex
+        self.nextIndex = i+1
+        self._advance(self)
+        return 1
+
+    def _advance(self, it):
+        self.item = self._next
+        del self._next
+        del self.end
+        self._advance = self._inner.advance
+        self.start = 1
+            
+    def number(self): return self.nextIndex
+
+    def even(self): return not self.index % 2
+
+    def odd(self): return self.index % 2
+
+    def letter(self, base=ord('a'), radix=26):
+        index = self.index
+        s = ''
+        while 1:
+            index, off = divmod(index, radix)
+            s = chr(base + off) + s
+            if not index: return s
+
+    def Letter(self):
+        return self.letter(base=ord('A'))
+
+    def Roman(self, rnvalues=(
+                    (1000,'M'),(900,'CM'),(500,'D'),(400,'CD'),
+                    (100,'C'),(90,'XC'),(50,'L'),(40,'XL'),
+                    (10,'X'),(9,'IX'),(5,'V'),(4,'IV'),(1,'I')) ):
+        n = self.index + 1
+        s = ''
+        for v, r in rnvalues:
+            rct, n = divmod(n, v)
+            s = s + r * rct
+        return s
+
+    def roman(self, lower=string.lower):
+        return lower(self.Roman())
+
+    def first(self, name=None):
+        if self.start: return 1
+        return not self.same_part(name, self._last, self.item)
+
+    def last(self, name=None):
+        if self.end: return 1
+        return not self.same_part(name, self.item, self._next)
+
+    def same_part(self, name, ob1, ob2):
+        if name is None:
+            return ob1 == ob2
+        no = []
+        return getattr(ob1, name, no) == getattr(ob2, name, no) is not no
+
+    def __iter__(self):
+        return IterIter(self)
+
+class InnerBase:
+    '''Base Inner class for Iterators'''
+    # Prep sets up ._next and .end
+    def prep_next(self, it):
+        it.next = self.no_next
+        it.end = 1
+        return 0
+
+    # Advance knocks them down
+    def advance(self, it):
+        it._last = it.item
+        it.item = it._next
+        del it._next
+        del it.end
+        it.start = 0
+            
+    def no_next(self, it):
+        return 0
+
+    def it_end(self, it):
+        if hasattr(it, '_next'):
+            return 0
+        return not self.prep_next(it)
+
+class SeqInner(InnerBase):
+    '''Inner class for sequence Iterators'''
+
+    def _supports(self, ob):
+        try: ob[0]
+        except TypeError: return 0
+        except: pass
+        return 1
+
+    def prep_next(self, it):
+        i = it.nextIndex
+        try:
+            it._next = it.seq[i]
+        except IndexError:
+            it._prep_next = self.no_next
+            it.end = 1
+            return 0
+        it.end = 0
+        return 1
+
+    def it_length(self, it):
+        it.length = l = len(it.seq)
+        return l
+
+try:
+    StopIteration=StopIteration
+except NameError:
+    StopIteration="StopIteration"
+
+class IterInner(InnerBase):
+    '''Iterator inner class for Python iterators'''
+
+    def _supports(self, ob):
+        try:
+            if hasattr(ob, 'next') and (ob is iter(ob)):
+                return 1
+        except:
+            return 0
+
+    def prep_next(self, it):
+        try:
+            it._next = it.seq.next()
+        except StopIteration:
+            it._prep_next = self.no_next
+            it.end = 1
+            return 0
+        it.end = 0
+        return 1
+
+class IterIter:
+    def __init__(self, it):
+        self.it = it
+        self.skip = it.nextIndex > 0 and not it.end
+    def next(self):
+        it = self.it
+        if self.skip:
+            self.skip = 0
+            return it.item
+        if it.next():
+            return it.item
+        raise StopIteration
+
+seqInner = SeqInner()
+iterInner = IterInner()

Roundup Issue Tracker: http://roundup-tracker.org/