# -*- Mode: Python; tab-width: 4 -*- # fifo, implemented with lisp-style pairs. # [quick translation of scheme48/big/queue.scm] class fifo: def __init__ (self): self.head, self.tail = None, None self.length = 0 self.node_cache = None def __len__ (self): return self.length def push (self, v): self.node_cache = None self.length = self.length + 1 p = [v, None] if self.head is None: self.head = p else: self.tail[1] = p self.tail = p def pop (self): self.node_cache = None pair = self.head if pair is None: raise ValueError, "pop() from an empty queue" else: self.length = self.length - 1 [value, next] = pair self.head = next if next is None: self.tail = None return value def first (self): if self.head is None: raise ValueError, "first() of an empty queue" else: return self.head[0] def push_front (self, thing): self.node_cache = None self.length = self.length + 1 old_head = self.head new_head = [thing, old_head] self.head = new_head if old_head is None: self.tail = new_head def _nth (self, n): i = n h = self.head while i: h = h[1] i = i - 1 self.node_cache = n, h[1] return h[0] def __getitem__ (self, index): if (index < 0) or (index >= self.length): raise IndexError, "index out of range" else: if self.node_cache: j, h = self.node_cache if j == index - 1: result = h[0] self.node_cache = index, h[1] return result else: return self._nth (index) else: return self._nth (index) class protected_fifo: def __init__ (self, lock=None): if lock is None: import thread self.lock = thread.allocate_lock() else: self.lock = lock self.fifo = fifo.fifo() def push (self, item): try: self.lock.acquire() self.fifo.push (item) finally: self.lock.release() enqueue = push def pop (self): try: self.lock.acquire() return self.fifo.pop() finally: self.lock.release() dequeue = pop def __len__ (self): try: self.lock.acquire() return len(self.queue) finally: self.lock.release() class output_fifo: EMBEDDED = 'embedded' EOF = 'eof' TRIGGER = 'trigger' def __init__ (self): # containment, not inheritance self.fifo = fifo() self._embedded = None def push_embedded (self, fifo): # push embedded fifo fifo.parent = self # CYCLE self.fifo.push ((self.EMBEDDED, fifo)) def push_eof (self): # push end-of-fifo self.fifo.push ((self.EOF, None)) def push_trigger (self, thunk): self.fifo.push ((self.TRIGGER, thunk)) def push (self, item): # item should be a producer or string self.fifo.push (item) # 'length' is an inaccurate term. we should # probably use an 'empty' method instead. def __len__ (self): if self._embedded is None: return len(self.fifo) else: return len(self._embedded) def empty (self): return len(self) == 0 def first (self): if self._embedded is None: return self.fifo.first() else: return self._embedded.first() def pop (self): if self._embedded is not None: return self._embedded.pop() else: result = self.fifo.pop() # unset self._embedded self._embedded = None # check for special items in the front if len(self.fifo): front = self.fifo.first() if type(front) is type(()): # special kind, value = front if kind is self.EMBEDDED: self._embedded = value elif kind is self.EOF: # break the cycle parent = self.parent self.parent = None # pop from parent parent._embedded = None elif kind is self.TRIGGER: # call the trigger thunk value() # remove the special self.fifo.pop() # return the originally popped result return result def test_embedded(): of = output_fifo() f2 = output_fifo() f3 = output_fifo() of.push ('one') of.push_embedded (f2) f2.push ('two') f3.push ('three') f3.push ('four') f2.push_embedded (f3) f3.push_eof() f2.push ('five') f2.push_eof() of.push ('six') of.push ('seven') while 1: print of.pop()