001/* Append arrays together to form a larger array.
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.data.ArrayToken;
031import ptolemy.data.type.ArrayType;
032import ptolemy.data.type.Type;
033import ptolemy.kernel.CompositeEntity;
034import ptolemy.kernel.util.IllegalActionException;
035import ptolemy.kernel.util.NameDuplicationException;
036import ptolemy.kernel.util.Workspace;
037
038///////////////////////////////////////////////////////////////////
039//// ArrayAccumulate
040
041/**
042 An actor that accumulates input arrays into a growing array that
043 includes the contents of all input arrays.  Upon firing, this actor reads
044 an input array, appends it to the accumulating array, and outputs
045 the new array. The length of the output array grows by the size
046 of the input array on each firing.
047
048 @author Edward A. Lee
049 @version $Id$
050 @since Ptolemy II 10.0
051 @Pt.ProposedRating Yellow (cxh)
052 @Pt.AcceptedRating Red (eal)
053 */
054public class ArrayAccumulate extends Transformer {
055    /** Construct an actor with the given container and name.
056     *  @param container The container.
057     *  @param name The name of this actor.
058     *  @exception IllegalActionException If the actor cannot be contained
059     *   by the proposed container.
060     *  @exception NameDuplicationException If the container already has an
061     *   actor with this name.
062     */
063    public ArrayAccumulate(CompositeEntity container, String name)
064            throws NameDuplicationException, IllegalActionException {
065        super(container, name);
066        // Set type constraints.
067        input.setTypeAtLeast(ArrayType.ARRAY_BOTTOM);
068        output.setTypeAtLeast(input);
069        output.setTypeAtLeast(ArrayType.ARRAY_UNSIZED_BOTTOM);
070    }
071
072    ///////////////////////////////////////////////////////////////////
073    ////                         public methods                    ////
074
075    /** Clone the actor into the specified workspace. This calls the
076     *  base class and then creates new ports and parameters.
077     *  @param workspace The workspace for the new object.
078     *  @return A new actor.
079     *  @exception CloneNotSupportedException If a derived class contains
080     *   an attribute that cannot be cloned.
081     */
082    @Override
083    public Object clone(Workspace workspace) throws CloneNotSupportedException {
084        ArrayAccumulate newObject = (ArrayAccumulate) super.clone(workspace);
085
086        // Set the type constraints.
087        newObject.input.setTypeAtLeast(ArrayType.ARRAY_BOTTOM);
088        newObject.output.setTypeAtLeast(newObject.input);
089        newObject.output.setTypeAtLeast(ArrayType.ARRAY_UNSIZED_BOTTOM);
090        newObject._arrays = new ArrayToken[2];
091        return newObject;
092    }
093
094    /** Consume at most one ArrayToken from the input, append it
095     *  to the accumulating token, and produce the accumulated result
096     *  on the output.
097     *  @exception IllegalActionException If a runtime type conflict occurs,
098     *   or if there are no input channels.
099     */
100    @Override
101    public void fire() throws IllegalActionException {
102        super.fire();
103        // NOTE: Do not use System.arraycopy here because the
104        // arrays being appended may be subclasses of ArrayToken,
105        // so values have to be accessed via the getElement() method,
106        // which is overridden in the subclasses. Use the append()
107        // method of ArrayToken instead.
108        if (input.hasToken(0)) {
109            ArrayToken token = (ArrayToken) input.get(0);
110            if (_accumulating == null) {
111                _tentativeAccumulating = token;
112                output.send(0, token);
113            } else {
114                _arrays[0] = _accumulating;
115                _arrays[1] = token;
116                _tentativeAccumulating = ArrayToken.append(_arrays);
117                output.send(0, ArrayToken.append(_arrays));
118            }
119        } else {
120            Type elementType = ((ArrayType) output.getType()).getElementType();
121            output.send(0, new ArrayToken(elementType));
122        }
123    }
124
125    /** Initialize this actor to have an empty accumulating array.
126     *  @exception IllegalActionException If the superclass throws it.
127     */
128    @Override
129    public void initialize() throws IllegalActionException {
130        super.initialize();
131        _accumulating = null;
132        _tentativeAccumulating = null;
133    }
134
135    /** Record the accumulating array and return true.
136     *  @return True.
137     *  @exception IllegalActionException If the superclass throws it.
138     */
139    @Override
140    public boolean postfire() throws IllegalActionException {
141        boolean result = super.postfire();
142        _accumulating = _tentativeAccumulating;
143        return result;
144    }
145
146    ///////////////////////////////////////////////////////////////////
147    ////                         private variables                 ////
148
149    /** The accumulating array. */
150    private ArrayToken _accumulating;
151
152    /** An array to use (repeatedly) to append arrays. */
153    private ArrayToken[] _arrays = new ArrayToken[2];
154
155    /** The tentative accumulating array. */
156    private ArrayToken _tentativeAccumulating;
157}