001/* Replace an element in an array with a new value.
002
003 Copyright (c) 1998-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 ptolemy.actor.parameters.PortParameter;
031import ptolemy.data.ArrayToken;
032import ptolemy.data.IntToken;
033import ptolemy.data.expr.Parameter;
034import ptolemy.data.type.ArrayType;
035import ptolemy.kernel.CompositeEntity;
036import ptolemy.kernel.util.IllegalActionException;
037import ptolemy.kernel.util.NameDuplicationException;
038import ptolemy.kernel.util.StringAttribute;
039import ptolemy.kernel.util.Workspace;
040
041///////////////////////////////////////////////////////////////////
042//// ArrayUpdate
043
044/**
045 Replace an element in an array with a new value.  This actor reads an array from the
046 <i>input</i> port and sends a new array to the <i>output</i>
047 port with the specified element replaced by the specified value.
048 The type of the output array elements is the greater than or equal to
049 the type of the elements of the input array and the replacement value.
050
051 @author Edward A. Lee
052 @version $Id$
053 @since Ptolemy II 10.0
054 @Pt.ProposedRating Yellow (cxh)
055 @Pt.AcceptedRating Red (eal)
056 */
057public class ArrayUpdate extends Transformer {
058    /** Construct an actor with the given container and name.
059     *  @param container The container.
060     *  @param name The name of this actor.
061     *  @exception IllegalActionException If the actor cannot be contained
062     *   by the proposed container.
063     *  @exception NameDuplicationException If the container already has an
064     *   actor with this name.
065     */
066    public ArrayUpdate(CompositeEntity container, String name)
067            throws NameDuplicationException, IllegalActionException {
068        super(container, name);
069
070        // Set parameters.
071        index = new PortParameter(this, "index");
072        index.setExpression("0");
073        new StringAttribute(index.getPort(), "_cardinal")
074                .setExpression("SOUTH");
075        new Parameter(index.getPort(), "_showName").setExpression("true");
076
077        value = new PortParameter(this, "value");
078        value.setExpression("1");
079        new StringAttribute(value.getPort(), "_cardinal")
080                .setExpression("SOUTH");
081        new Parameter(value.getPort(), "_showName").setExpression("true");
082
083        // Set type constraints.
084        input.setTypeAtLeast(ArrayType.ARRAY_BOTTOM);
085        output.setTypeAtLeast(input);
086        output.setTypeAtLeast(ArrayType.arrayOf(value));
087    }
088
089    ///////////////////////////////////////////////////////////////////
090    ////                         parameters                        ////
091
092    /** The index into the input array at which to set the new value.
093     *  This is a non-negative integer that defaults to 0, and is
094     *  required to be less than the length of the input array.
095     */
096    public PortParameter index;
097
098    /** The value to insert into the array at the position given by
099     *  <i>index</i>.
100     */
101    public PortParameter value;
102
103    ///////////////////////////////////////////////////////////////////
104    ////                         public methods                    ////
105
106    /** Clone the actor into the specified workspace. This calls the
107     *  base class and then sets up the type constraints.
108     *  @param workspace The workspace for the new object.
109     *  @return A new actor.
110     *  @exception CloneNotSupportedException If a derived class contains
111     *   an attribute that cannot be cloned.
112     */
113    @Override
114    public Object clone(Workspace workspace) throws CloneNotSupportedException {
115        ArrayUpdate newObject = (ArrayUpdate) super.clone(workspace);
116
117        // Set the type constraints.
118        newObject.input.setTypeAtLeast(ArrayType.ARRAY_BOTTOM);
119        newObject.output.setTypeAtLeast(newObject.input);
120        try {
121            newObject.output.setTypeAtLeast(ArrayType.arrayOf(newObject.value));
122        } catch (IllegalActionException e) {
123            throw new CloneNotSupportedException(
124                    "Failed to set type constraints on cloned actor.");
125        }
126
127        return newObject;
128    }
129
130    /** Consume one array from the input port and send a subarray to
131     *  the output port, padding the subarray with zeros if necessary.
132     *  @exception IllegalActionException If any parameter value
133     *   is out of range.
134     */
135    @Override
136    public void fire() throws IllegalActionException {
137        super.fire();
138        index.update();
139        value.update();
140
141        if (input.hasToken(0)) {
142            ArrayToken inputValue = (ArrayToken) input.get(0);
143            int indexValue = ((IntToken) index.getToken()).intValue();
144            output.send(0, inputValue.update(indexValue, value.getToken()));
145        }
146    }
147}