001/* Extract an element from an 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 java.util.HashSet; 031import java.util.Set; 032 033import ptolemy.actor.parameters.PortParameter; 034import ptolemy.data.ArrayToken; 035import ptolemy.data.BooleanToken; 036import ptolemy.data.IntToken; 037import ptolemy.data.expr.Parameter; 038import ptolemy.data.type.ArrayType; 039import ptolemy.data.type.BaseType; 040import ptolemy.data.type.MonotonicFunction; 041import ptolemy.data.type.Typeable; 042import ptolemy.graph.Inequality; 043import ptolemy.graph.InequalityTerm; 044import ptolemy.kernel.CompositeEntity; 045import ptolemy.kernel.util.IllegalActionException; 046import ptolemy.kernel.util.InternalErrorException; 047import ptolemy.kernel.util.NameDuplicationException; 048import ptolemy.kernel.util.Workspace; 049 050/////////////////////////////////////////////////////////////////// 051//// ArrayElement 052 053/** 054 Extract an element from an array. This actor reads an array from the 055 <i>input</i> port and sends one of its elements to the <i>output</i> 056 port. The element that is extracted is determined by the 057 <i>index</i> parameter (or port). It is required that 058 0 <= <i>index</i> < <i>N</i>, where <i>N</i> is the 059 length of the input array, or 060 an exception will be thrown by the fire() method. 061 062 @see LookupTable 063 @see RecordDisassembler 064 @author Edward A. Lee, Elaine Cheong 065 @version $Id$ 066 @since Ptolemy II 1.0 067 @Pt.ProposedRating Green (celaine) 068 @Pt.AcceptedRating Green (cxh) 069 */ 070public class ArrayElement extends Transformer { 071 /** Construct an actor with the given container and name. 072 * @param container The container. 073 * @param name The name of this actor. 074 * @exception IllegalActionException If the actor cannot be contained 075 * by the proposed container. 076 * @exception NameDuplicationException If the container already has an 077 * actor with this name. 078 */ 079 public ArrayElement(CompositeEntity container, String name) 080 throws NameDuplicationException, IllegalActionException { 081 super(container, name); 082 083 // set type constraints. 084 output.setTypeAtLeast(ArrayType.elementType(input)); 085 086 // Set parameters. 087 index = new PortParameter(this, "index"); 088 index.setTypeEquals(BaseType.INT); 089 index.setExpression("0"); 090 new Parameter(index.getPort(), "_showName", BooleanToken.TRUE); 091 } 092 093 /////////////////////////////////////////////////////////////////// 094 //// parameters //// 095 096 /** The index into the input array. This is an integer that 097 * defaults to 0, and is required to be less than or equal to the 098 * length of the input array. If the port is left unconnected, 099 * then the parameter value will be used. 100 */ 101 public PortParameter index; 102 103 /////////////////////////////////////////////////////////////////// 104 //// public methods //// 105 106 /** Override the base class to set type constraints. 107 * @param workspace The workspace for the new object. 108 * @return A new instance of ArrayElement. 109 * @exception CloneNotSupportedException If a derived class contains 110 * an attribute that cannot be cloned. 111 */ 112 @Override 113 public Object clone(Workspace workspace) throws CloneNotSupportedException { 114 ArrayElement newObject = (ArrayElement) super.clone(workspace); 115 try { 116 newObject.output 117 .setTypeAtLeast(ArrayType.elementType(newObject.input)); 118 } catch (IllegalActionException e) { 119 // Should have been caught before. 120 throw new InternalErrorException(e); 121 } 122 return newObject; 123 } 124 125 /** Force the type of the input to be an array with fields of a type 126 * greater than or equal to the type of the output port. 127 */ 128 @Override 129 protected Set<Inequality> _customTypeConstraints() { 130 Set<Inequality> result = new HashSet<Inequality>(); 131 if (isBackwardTypeInferenceEnabled()) { 132 result.add(new Inequality(new ArrayTypeFunction(output), 133 input.getTypeTerm())); 134 } 135 return result; 136 } 137 138 /** Consume at most one array from the input port and produce 139 * one of its elements on the output port. If there is no token 140 * on the input, then no output is produced. 141 * @exception IllegalActionException If the <i>index</i> parameter 142 * (or port value) is out of range. 143 */ 144 @Override 145 public void fire() throws IllegalActionException { 146 super.fire(); 147 // NOTE: This has be outside the if because we need to ensure 148 // that if an index token is provided that it is consumed even 149 // if there is no input token. 150 index.update(); 151 152 int indexValue = ((IntToken) index.getToken()).intValue(); 153 154 if (input.hasToken(0)) { 155 ArrayToken token = (ArrayToken) input.get(0); 156 157 if (indexValue < 0 || indexValue >= token.length()) { 158 throw new IllegalActionException(this, 159 "index " + indexValue 160 + " is out of range for the input " 161 + "array, which has length " + token.length()); 162 } 163 164 output.send(0, token.getElement(indexValue)); 165 } 166 } 167 168 /** A monotonic function that returns an array type of which the 169 * fields have the same type as the provided argument. 170 * @author Marten Lohstroh 171 */ 172 private static class ArrayTypeFunction extends MonotonicFunction { 173 174 /** Construct a ArrayElementTypeFunction whose argument is the 175 * type of the specified object. 176 * @param typeable A Typeable object. 177 */ 178 public ArrayTypeFunction(Typeable typeable) { 179 _typeable = typeable; 180 } 181 182 /////////////////////////////////////////////////////////////////// 183 //// public methods //// 184 185 /** Return the current value of this monotonic function. 186 * @return A Type. 187 * @exception IllegalActionException If the type of the argument 188 * cannot be determined. 189 */ 190 @Override 191 public Object getValue() throws IllegalActionException { 192 return new ArrayType(_typeable.getType()); 193 } 194 195 /** Return the type variables for this function, which is 196 * the type term of the specified typeable, unless it has a constant type, 197 * in which case return an empty array. 198 * @return An array of InequalityTerms. 199 */ 200 @Override 201 public InequalityTerm[] getVariables() { 202 InequalityTerm term = _typeable.getTypeTerm(); 203 if (term.isSettable()) { 204 InequalityTerm[] result = new InequalityTerm[1]; 205 result[0] = term; 206 return result; 207 } else { 208 return new InequalityTerm[0]; 209 } 210 } 211 212 /////////////////////////////////////////////////////////////////// 213 //// private variables //// 214 215 /** The argument. */ 216 private Typeable _typeable; 217 218 } 219 220}