001/* A queue that outputs the next token to an output channel that is ready to
002 receive it.
003
004 Copyright (c) 2008-2015 The Regents of the University of California.
005 All rights reserved.
006 Permission is hereby granted, without written agreement and without
007 license or royalty fees, to use, copy, modify, and distribute this
008 software and its documentation for any purpose, provided that the above
009 copyright notice and the following two paragraphs appear in all copies
010 of this software.
011
012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 ENHANCEMENTS, OR MODIFICATIONS.
024
025 PT_COPYRIGHT_VERSION_2
026 COPYRIGHTENDKEY
027
028 */
029package ptolemy.domains.de.lib;
030
031import java.util.Arrays;
032
033import ptolemy.actor.util.FIFOQueue;
034import ptolemy.data.IntToken;
035import ptolemy.data.Token;
036import ptolemy.kernel.CompositeEntity;
037import ptolemy.kernel.util.IllegalActionException;
038import ptolemy.kernel.util.NameDuplicationException;
039import ptolemy.kernel.util.Settable;
040
041//////////////////////////////////////////////////////////////////////////
042//// SharedQueue
043
044/**
045 A queue that outputs the next token to an output channel that is ready to
046 receive it. It can have multiple output channels, and the same number of
047 trigger channels. Initially all output channels are assumed to be ready. When a
048 token is available, it is sent to the first channel that is ready, and that
049 channel is marked not ready. When all channels are not ready, the token would
050 be queued. If the number of tokens already in the queue is equal to the queue
051 capacity (0 means infinity), then new tokens are lost.
052 <p>
053 To make an output channel ready after a token is sent to it, a triggering
054 signal needs to be received in the corresponding channel of the trigger port.
055
056 @author Thomas Huining Feng
057 @version $Id$
058 @since Ptolemy II 8.0
059 @Pt.ProposedRating Red (tfeng)
060 @Pt.AcceptedRating Red (tfeng)
061 */
062public class SharedQueue extends Queue {
063
064    /** Construct an actor with the given container and name.
065     *  @param container The container.
066     *  @param name The name of this actor.
067     *  @exception IllegalActionException If the actor cannot be contained
068     *   by the proposed container.
069     *  @exception NameDuplicationException If the container already has an
070     *   actor with this name.
071     */
072    public SharedQueue(CompositeEntity container, String name)
073            throws NameDuplicationException, IllegalActionException {
074        super(container, name);
075
076        output.setMultiport(true);
077        persistentTrigger.setVisibility(Settable.NONE);
078    }
079
080    /** If there is an input at the input port, consume it. If there are tokens
081     *  in the queue and there are ready output channels, the tokens are sent to
082     *  those output channels. If triggers are available at the trigger port,
083     *  consume them and make the corresponding output channels ready. Also send
084     *  tokens to those channels if there are tokens available.
085     *  @exception IllegalActionException If getting tokens from input and
086     *   trigger ports or sending token to output throws it.
087     */
088    @Override
089    public void fire() throws IllegalActionException {
090        if (_debugging) {
091            _debug("Called fire()");
092        }
093
094        int sizeOutput = _queue.size();
095        _removeTokens = 0;
096        for (int i = 0, j = 0; i < trigger.getWidth(); i++) {
097            if (trigger.hasToken(i)) {
098                trigger.get(i);
099                if (sizeOutput > 0) {
100                    _outputReady[i] = false;
101                    output.send(i, (Token) _queue.get(j++));
102                    sizeOutput--;
103                    _removeTokens++;
104                } else {
105                    _outputReady[i] = true;
106                }
107            }
108        }
109        if (input.hasToken(0)) {
110            _token = input.get(0);
111            for (int i = 0; i < _outputReady.length; i++) {
112                if (_outputReady[i]) {
113                    _outputReady[i] = false;
114                    output.send(i, _token);
115                    _token = null;
116                    break;
117                }
118            }
119            if (_token != null && (_queue
120                    .getCapacity() == FIFOQueue.INFINITE_CAPACITY
121                    || _queue.getCapacity() > _queue.size() - _removeTokens)) {
122                sizeOutput++;
123            } else {
124                _token = null;
125            }
126        }
127        size.send(0, new IntToken(sizeOutput));
128    }
129
130    /** Return true if either there is input at the input port, or there are
131     *  triggering signals at the trigger port. Return false otherwise.
132     *
133     *  @return True if this actor is ready to fire.
134     *  @exception IllegalActionException If the ports cannot be tested for
135     *   availability of tokens.
136     */
137    @Override
138    public boolean prefire() throws IllegalActionException {
139        if (input.isOutsideConnected() && input.hasToken(0)) {
140            return true;
141        }
142
143        for (int i = 0; i < trigger.getWidth(); i++) {
144            if (trigger.hasToken(i)) {
145                return true;
146            }
147        }
148
149        return false;
150    }
151
152    /** Make all output channels ready.
153     *
154     *  @exception IllegalActionException If thrown by the superclass.
155     */
156    @Override
157    public void initialize() throws IllegalActionException {
158        super.initialize();
159        _outputReady = new boolean[output.getWidth()];
160        Arrays.fill(_outputReady, true);
161    }
162
163    /** Clear the buffer.
164     *
165     *  @exception IllegalActionException If thrown by the superclass.
166     */
167    @Override
168    public void wrapup() throws IllegalActionException {
169        super.wrapup();
170        _outputReady = null;
171    }
172
173    // Each entry represents the readiness of an output channel.
174    private boolean[] _outputReady;
175}