Friday, October 14, 2005

Two way iterator

#twowayiterator.py
#
#Helpers for implementing iterators
#that can be talked to
#
#See:
#http://blogs.applibase.net/sidharth/?p=30
#

def izip(*args):
    """
    A special version of izip
    that continues processing the
    remaining iterators one more
    time even after the one of them
    has thrown StopIteration.
    """

    iters = [arg for arg in args]
    canloop = True
    while canloop:
        l = []
        for it in iters:
            if canloop:
                try:
                    l.append(it.next())
                except StopIteration:
                    canloop = False
            else:
                try:
                    it.next()
                except StopIteration:
                    pass
        if canloop:
            yield l

class _Ref:
    def put(self, val):
        self.val = val
    def get(self):
        return val

class _Ret:
    def set(self, val):
        self.val = val
        raise StopIteration
    
    def get(self):
        return self.val

def twowayiterator(generator):
    """
    A decorator for generators for iterators
    that can get messages from the caller.

    Building a generator:
    @twowayiterator
    def <generator_name>((ret, get), <params>):
        ...
        yield <value>
        <var>=get()
        ...
        ret(<value>)
        
    ret and get are required parameters for the decorator
    get is used to return the value injectd into the
    iterator by its caller.
    yield <value>
    <var>=get()
    could be considered to represent
    <var>=yield<value>

    ret is used to signal that the iterator is done and
    return a value to its caller.
    ret(<value>)
    could be represented as
    return <value>

    Using a two way iterator
    (ret, put), iter = <generator_name>(<params>)
    try:
        ...
        put(<value>)
        <var>=iter.next()
        ...
    except StopIteration:
        ...
    <var>=ret()

    put is used to inject a value into the iterator
    it is the other side of the get function
    put(<value>)
    <var>=iter.next()
    can be represented as
    <var>=iter.next(<value>)

    ret in this case case is different from ret in the
    iterator it is used to recieve a value returned
    using ret.

    The two way iterator could be used in a for loop
    
    (ret, put), iter = <generator_name>(<params>)
    for val in iter:
        ...
        put(<value>)
    <var>=ret()
    """

    def _twowayiterator(*args, **aargs):
        _in = _Ref()
        ret = _Ret()
        return ((ret.get, _in.put),
                generator((ret.set, _in.get),
                          *args, **aargs))
    return _twowayiterator

0 Comments:

Post a Comment

<< Home