module: dfmc-flow-graph Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND /// /// Queueable items have a next link that points to the rest of the queue. /// They can only belong to one queue. The status field says whether an item /// should be ignored when processing the queue (#"dead"), whether its /// in a queue (#"absent" or #f). Items will only be added to a queue if /// they are #"absent". /// /// Maybe we should just add the slots to directly? /// /// A thought: if we use the queue itself to indicate that the item was in a /// queue rather than #f then we wouldn't have to pass the queue around as an /// argument everywhere. define abstract class () slot item-properties :: = 0; end class ; define constant $queueable-item-absent = 0; define constant $queueable-item-present = 1; define constant $queueable-item-dead = 2; define packed-slots item-properties (, ) field slot item-status = $queueable-item-absent, field-size: 2; end packed-slots; define method mark-as-dead (x :: ) => () x.item-status := $queueable-item-dead; end method mark-as-dead; /// /// Basically holds the queue. Queue operations such as adding and popping /// etc are defined on this class and . The operations /// maintain as far as possible the integrity of the queue. define constant = ; /// Protocol for s and s // adds an (#"absent") item to a queue. define generic add-to-queue! (queue :: , item :: ) => (); // returns the first non-dead item from a queue. Will pop dead items if found. define generic queue-head (queue :: ) => ( item :: false-or()); // pop items from the queue until it pops a non dead item, which it returns define generic queue-pop (queue :: ) => ( item :: false-or()); define generic reverse-queue! (queue :: ) => (); /// Default implementation of protocol for s and s define method print-queue-out (queue) do-queue(method (i) format-out(" ELT %= STATUS %=\n", i, i.item-status) end, queue); end method; define method queue-pop! (queue :: ) => (item :: false-or()) let new-size = size(queue) - 1; unless (new-size = -1) let elt = queue[new-size]; elt.item-status := $queueable-item-absent; size(queue) := new-size; elt end unless end method; define inline method queue-push! (queue :: , item :: ) => () add!(queue, item) end method; define method add-to-queue! (queue :: , item :: ) => () if (item.item-status == $queueable-item-absent) item.item-status := $queueable-item-present; queue-push!(queue, item); end if; end method add-to-queue!; define method pop-dead! (queue :: ) => (item :: false-or()) iterate loop (i :: = size(queue) - 1) unless (i < 0) let item = queue[i]; if (item.item-status == $queueable-item-dead) size(queue) := i; loop(i - 1); else item // return first non-dead item end if; end unless; end iterate; end method; define inline method queue-head (queue :: ) => (item :: false-or()) pop-dead!(queue); end method; define method queue-pop (queue :: ) => (item :: false-or()) let item = pop-dead!(queue); if (item) item.item-status := $queueable-item-absent; queue-pop!(queue) end if; end method; define method reverse-queue! (queue :: ) => () pop-dead!(queue); reverse!(queue); pop-dead!(queue); end method reverse-queue!; define method do-queue (function :: , queue :: ) => () pop-dead!(queue); for (item in queue) unless (item.item-status == $queueable-item-dead) function(item); end unless; end for; end method; // eof