001/* An actor that disassemble an ArrayToken to a multiport output.
002
003 Copyright (c) 2003-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 */
028package ptolemy.actor.lib;
029
030import java.util.HashSet;
031import java.util.Set;
032
033import ptolemy.actor.util.ArrayOfTypesFunction;
034import ptolemy.data.ArrayToken;
035import ptolemy.data.Token;
036import ptolemy.data.type.ArrayType;
037import ptolemy.graph.Inequality;
038import ptolemy.kernel.CompositeEntity;
039import ptolemy.kernel.util.IllegalActionException;
040import ptolemy.kernel.util.InternalErrorException;
041import ptolemy.kernel.util.NameDuplicationException;
042import ptolemy.kernel.util.Workspace;
043
044///////////////////////////////////////////////////////////////////
045//// ArrayToElements
046
047/**
048 <p>An actor that disassembles an ArrayToken to a multiport output.</p>
049 <p>On each firing, this actor reads an ArrayToken from the input
050 port and send out each element token to each channel of the output
051 port. If the width of the output port (say, <i>n</i>) is less than
052 the number of elements in the array (say <i>m</i>), then the first
053 <i>n</i> elements in the array will be sent, and the remaining
054 tokens are discarded. If <i>n</i> is greater than <i>m</i>, then
055 the last <i>n-m</i> channels of the output port will never send
056 tokens out.</p>
057 <p>
058 This actor is polymorphic. It can accept ArrayTokens with any element
059 type and send out tokens corresponding to that type.
060 </p>
061
062 @author Ye Zhou
063 @version $Id$
064 @since Ptolemy II 4.0
065 @Pt.ProposedRating Red (zhouye)
066 @Pt.AcceptedRating Red (cxh)
067 */
068public class ArrayToElements extends Transformer {
069    /** Construct an actor with the given container and name.
070     *  @param container The container.
071     *  @param name The name of this actor.
072     *  @exception IllegalActionException If the actor cannot be
073     *   contained by the proposed container.
074     *  @exception NameDuplicationException If the container
075     *   already has an actor with this name.
076     */
077    public ArrayToElements(CompositeEntity container, String name)
078            throws NameDuplicationException, IllegalActionException {
079        super(container, name);
080
081        // Set type constraints.
082        output.setTypeAtLeast(ArrayType.elementType(input));
083
084        output.setMultiport(true);
085
086        // Set the icon.
087        _attachText("_iconDescription",
088                "<svg>\n" + "<polygon points=\"-15,-15 15,15 15,-15 -15,15\" "
089                        + "style=\"fill:white\"/>\n" + "</svg>\n");
090    }
091
092    ///////////////////////////////////////////////////////////////////
093    ////                         public methods                    ////
094
095    /** Clone the actor into the specified workspace. This calls the
096     *  base class and then creates new ports and parameters.
097     *  @param workspace The workspace for the new object.
098     *  @return A new actor.
099     *  @exception CloneNotSupportedException If a derived class
100     *   contains an attribute that cannot be cloned.
101     */
102    @Override
103    public Object clone(Workspace workspace) throws CloneNotSupportedException {
104        ArrayToElements newObject = (ArrayToElements) super.clone(workspace);
105        try {
106            newObject.output
107                    .setTypeAtLeast(ArrayType.elementType(newObject.input));
108        } catch (IllegalActionException e) {
109            // Should have been caught before.
110            throw new InternalErrorException(e);
111        }
112        return newObject;
113    }
114
115    /** If there is a token at the input, read the ArrayToken
116     *  from the input port, and for each channel <i>i</i> of
117     *  the output port, send the <i>i</i>-th element of this
118     *  array to this channel. Otherwise, do nothing.
119     *  @exception IllegalActionException If a runtime
120     *   type conflict occurs.
121     */
122    @Override
123    public void fire() throws IllegalActionException {
124        super.fire();
125        if (input.hasToken(0)) {
126            ArrayToken token = (ArrayToken) input.get(0);
127            int size = token.length();
128
129            int min = Math.min(size, output.getWidth());
130
131            Token[] elements = token.arrayValue();
132
133            for (int i = 0; i < min; i++) {
134                output.send(i, elements[i]);
135            }
136        }
137    }
138
139    ///////////////////////////////////////////////////////////////////
140    ////                         protected methods                 ////
141
142    /** Do not establish the usual default type constraints. Instead, the type
143     *  of the output port is constrained to be no less than the type of the
144     *  elements of the input array (set in the constructor of this class).
145     */
146    @Override
147    protected Set<Inequality> _defaultTypeConstraints() {
148        return null;
149    }
150
151    /** Add a type constraint for backward type inference that forces
152     *  the input to be an array of which the elements have a type
153     *  greater than or equal to the output port.
154     *  If backward type inference is disabled, this method returns
155     *  an empty set.
156     *  @see ArrayOfTypesFunction
157     *  @return A set of inequalities.
158     */
159    @Override
160    protected Set<Inequality> _customTypeConstraints() {
161        Set<Inequality> result = new HashSet<Inequality>();
162        if (isBackwardTypeInferenceEnabled()) {
163            result.add(new Inequality(new ArrayOfTypesFunction(output),
164                    input.getTypeTerm()));
165        }
166        return result;
167    }
168}