001/* A polymorphic select, which routes specified input channels to the output.
002
003 Copyright (c) 1997-2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027 Code review issue: This actor reads data in prefire.
028 */
029package ptolemy.actor.lib;
030
031import ptolemy.actor.TypedIOPort;
032import ptolemy.data.IntToken;
033import ptolemy.data.type.BaseType;
034import ptolemy.kernel.CompositeEntity;
035import ptolemy.kernel.util.IllegalActionException;
036import ptolemy.kernel.util.NameDuplicationException;
037import ptolemy.kernel.util.StringAttribute;
038
039///////////////////////////////////////////////////////////////////
040//// Select
041
042/**
043 <p>A polymorphic select, which routes specified input channels to the
044 output.  This actor has two input ports, the <i>input</i> port for
045 data, and the <i>control</i> port to select which input channel to
046 read.  In an iteration, if an input token is available at the
047 <i>control</i> input, that token is read, and its value is noted.  Its
048 value specifies the input channel that should be read next. If an
049 input token is available on the specified channel of the <i>input</i>
050 port, then that token is read and sent to the output.
051
052 </p><p> The actor indicates a willingness to fire in its prefire() method
053 if there is an input available on the channel specified by the most
054 recently seen token on the <i>control</i> port.  If no token has ever
055 been received on the <i>control</i> port, then channel zero is assumed
056 to be the one to read.  If the value of the most recently received
057 token on the <i>control</i> port is out of range (less than zero, or
058 greater than or equal to the width of the input), then the actor will
059 not fire() (although it will continue to consume tokens on the
060 <i>control</i> port in its prefire() method).
061
062 </p><p> This actor is similar to the {@link ptolemy.actor.lib.Multiplexor}
063 actor, except that it never discards input tokens.  Tokens on
064 channels that are not selected are not consumed.
065
066 </p><p> Note that in the DE domain, where this actor is commonly used, if
067 a new value is given to the <i>control</i> port, then all previously
068 unread input tokens on the specified input channel will be read at the
069 same firing time, in the order in which they arrived.</p>
070
071 <p>Note further that this actor is subtly different from the
072 {@link BooleanSelect} actor. In addition to the obvious difference
073 that the latter accepts only two input streams, the latter also
074 requires two firings to produce an output. The BooleanSelect actor
075 is designed to work with DDF, but because of the multiple firings,
076 will not work with DE or SR. This actor will, because it consumes
077 the control input and the data input in the same firing.
078
079 @author Edward A. Lee
080 @version $Id$
081 @since Ptolemy II 1.0
082 @Pt.ProposedRating Green (neuendor)
083 @Pt.AcceptedRating Yellow (liuj)
084 */
085public class Select extends Transformer {
086    /** Construct an actor in the specified container with the specified
087     *  name.
088     *  @param container The container.
089     *  @param name The name of this actor within the container.
090     *  @exception IllegalActionException If the actor cannot be contained
091     *   by the proposed container.
092     *  @exception NameDuplicationException If the name coincides with
093     *   an actor already in the container.
094     */
095    public Select(CompositeEntity container, String name)
096            throws IllegalActionException, NameDuplicationException {
097        super(container, name);
098
099        input.setMultiport(true);
100
101        control = new TypedIOPort(this, "control", true, false);
102        control.setTypeEquals(BaseType.INT);
103
104        // Put the control input on the bottom of the actor.
105        StringAttribute controlCardinal = new StringAttribute(control,
106                "_cardinal");
107        controlCardinal.setExpression("SOUTH");
108    }
109
110    ///////////////////////////////////////////////////////////////////
111    ////                     ports and parameters                  ////
112
113    /** Input port for control tokens, which specify the output channel
114     *  to produce data on.  The type is int. */
115    public TypedIOPort control;
116
117    ///////////////////////////////////////////////////////////////////
118    ////                         public methods                    ////
119
120    /** Read an input token from the specified input channel and produce
121     *  it on the output.
122     *  @exception IllegalActionException If there is no director.
123     */
124    @Override
125    public void fire() throws IllegalActionException {
126        super.fire();
127        // Redo this check in case the control has changed since prefire().
128        if (input.hasToken(_control)) {
129            output.send(0, input.get(_control));
130        }
131    }
132
133    /** Initialize this actor so that channel zero of <i>input</i> is read
134     *  from until a token arrives on the <i>control</i> input.
135     *  @exception IllegalActionException If the parent class throws it.
136     */
137    @Override
138    public void initialize() throws IllegalActionException {
139        super.initialize();
140        _control = 0;
141    }
142
143    /** Read a control token, if there is one, and check to see
144     *  whether an input is available on the input channel specified by
145     *  the most recent control token, if it is in range.
146     *  Return false if there is no input token to read.
147     *  Otherwise, return whatever the superclass returns.
148     *  @return True if the actor is ready to fire.
149     *  @exception IllegalActionException If there is no director.
150     */
151    @Override
152    public boolean prefire() throws IllegalActionException {
153        if (control.hasToken(0)) {
154            _control = ((IntToken) control.get(0)).intValue();
155        }
156
157        if (_control < 0 || _control > input.getWidth()
158                || !input.hasToken(_control)) {
159            return false;
160        }
161
162        return super.prefire();
163    }
164
165    ///////////////////////////////////////////////////////////////////
166    ////                         private variables                 ////
167    // The most recently read control token.
168    private int _control = 0;
169}