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}