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.Token; 032import ptolemy.data.type.ArrayType; 033import ptolemy.data.type.Type; 034import ptolemy.kernel.CompositeEntity; 035import ptolemy.kernel.util.IllegalActionException; 036import ptolemy.kernel.util.NameDuplicationException; 037import ptolemy.kernel.util.Workspace; 038 039/////////////////////////////////////////////////////////////////// 040//// ArrayAppend 041 042/** 043 An actor that appends ArrayTokens together. This actor has a single input 044 multiport, and a single output port. The types on the input and the output 045 port must both be the same array type. During each firing, this actor reads 046 up to one ArrayToken from each channel of the input port and creates an 047 ArrayToken of the same type on the output port. If no token is available on 048 a particular channel, then there will be no contribution to the output. 049 The output is an array of length equal to the sum of the lengths of 050 the input arrays (which may be zero if either there are no input 051 arrays or the lengths of the input arrays are all zero). 052 053 @author Steve Neuendorffer 054 @version $Id$ 055 @since Ptolemy II 1.0 056 @Pt.ProposedRating Green (celaine) 057 @Pt.AcceptedRating Green (cxh) 058 */ 059public class ArrayAppend extends Transformer { 060 /** Construct an actor with the given container and name. 061 * @param container The container. 062 * @param name The name of this actor. 063 * @exception IllegalActionException If the actor cannot be contained 064 * by the proposed container. 065 * @exception NameDuplicationException If the container already has an 066 * actor with this name. 067 */ 068 public ArrayAppend(CompositeEntity container, String name) 069 throws NameDuplicationException, IllegalActionException { 070 super(container, name); 071 072 // The input is a multiport. 073 input.setMultiport(true); 074 075 // Set type constraints. 076 input.setTypeAtLeast(ArrayType.ARRAY_BOTTOM); 077 output.setTypeAtLeast(input); 078 output.setTypeAtLeast(ArrayType.ARRAY_UNSIZED_BOTTOM); 079 } 080 081 /////////////////////////////////////////////////////////////////// 082 //// public methods //// 083 084 /** Clone the actor into the specified workspace. This calls the 085 * base class and then creates new ports and parameters. 086 * @param workspace The workspace for the new object. 087 * @return A new actor. 088 * @exception CloneNotSupportedException If a derived class contains 089 * an attribute that cannot be cloned. 090 */ 091 @Override 092 public Object clone(Workspace workspace) throws CloneNotSupportedException { 093 ArrayAppend newObject = (ArrayAppend) super.clone(workspace); 094 095 // Set the type constraints. 096 newObject.input.setTypeAtLeast(ArrayType.ARRAY_BOTTOM); 097 newObject.output.setTypeAtLeast(newObject.input); 098 newObject.output.setTypeAtLeast(ArrayType.ARRAY_UNSIZED_BOTTOM); 099 return newObject; 100 } 101 102 /** Consume at most one ArrayToken from each channel of the input port 103 * and produce a single ArrayToken on the output 104 * port that contains all of the tokens contained in all of the 105 * arrays read from the input. If all input arrays are empty, 106 * or if there are no input arrays, then output an empty array 107 * of the appropriate type. 108 * @exception IllegalActionException If a runtime type conflict occurs, 109 * or if there are no input channels. 110 */ 111 @Override 112 public void fire() throws IllegalActionException { 113 super.fire(); 114 int width = input.getWidth(); 115 if (width == 0) { 116 throw new IllegalActionException(this, "No input channels."); 117 } 118 // NOTE: Do not use System.arraycopy here because the 119 // arrays being appended may be subclasses of ArrayToken, 120 // so values have to be accessed via the getElement() method, 121 // which is overridden in the subclasses. Use the append() 122 // method of ArrayToken instead. 123 ArrayToken[] arraysToAppend = new ArrayToken[width]; 124 int resultWidth = 0; 125 for (int i = 0; i < width; i++) { 126 if (input.hasToken(i)) { 127 Token token = input.get(i); 128 try { 129 ArrayToken arrayToken = (ArrayToken) token; 130 arraysToAppend[i] = arrayToken; 131 resultWidth += arrayToken.length(); 132 } catch (ClassCastException ex) { 133 throw new IllegalActionException(this, ex, 134 "Cannot cast \"" + token + "\" to an ArrayToken"); 135 } 136 } 137 } 138 if (resultWidth > 0) { 139 output.send(0, ArrayToken.append(arraysToAppend)); 140 } else { 141 Type elementType = ((ArrayType) input.getType()).getElementType(); 142 output.send(0, new ArrayToken(elementType)); 143 } 144 } 145}