001/* Determine whether an array contains an element.
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 */
028
029package ptolemy.actor.lib;
030
031import ptolemy.actor.TypedAtomicActor;
032import ptolemy.actor.TypedIOPort;
033import ptolemy.actor.parameters.PortParameter;
034import ptolemy.data.ArrayToken;
035import ptolemy.data.BooleanToken;
036import ptolemy.data.Token;
037import ptolemy.data.expr.Parameter;
038import ptolemy.data.type.ArrayType;
039import ptolemy.data.type.BaseType;
040import ptolemy.kernel.CompositeEntity;
041import ptolemy.kernel.util.IllegalActionException;
042import ptolemy.kernel.util.NameDuplicationException;
043import ptolemy.kernel.util.Workspace;
044
045///////////////////////////////////////////////////////////////////
046//// ArrayContains
047/**
048 Determine whether an element is contained in an array.
049 This actor reads an array from the <i>array</i>
050 input port and an element from the <i>element</i>
051 port parameter and outputs true if the element is contained by
052 the array.
053
054 @author Efrat Jaeger and Edward A. Lee
055 @version $Id$
056 */
057
058public class ArrayContains extends TypedAtomicActor {
059
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 ArrayContains(CompositeEntity container, String name)
069            throws NameDuplicationException, IllegalActionException {
070        super(container, name);
071
072        array = new TypedIOPort(this, "array", true, false);
073        output = new TypedIOPort(this, "output", false, true);
074
075        // Set parameters.
076        element = new PortParameter(this, "element");
077        new Parameter(element.getPort(), "_showName", BooleanToken.TRUE);
078
079        // set type constraints.
080        array.setTypeAtLeast(ArrayType.arrayOf(element));
081        output.setTypeEquals(BaseType.BOOLEAN);
082    }
083
084    ///////////////////////////////////////////////////////////////////
085    ////                         parameters                        ////
086
087    /** Input array. The type of this port is at least an array
088     *  of the type of the <i>element</i> port.
089     */
090    public TypedIOPort array;
091
092    /** Boolean output specifying whether the element is contained in
093     *         the array.
094     */
095    public TypedIOPort output;
096
097    /** The element to test for presence in the array.
098     */
099    public PortParameter element;
100
101    ///////////////////////////////////////////////////////////////////
102    ////                         public methods                    ////
103
104    /** Override the base class to set type constraints.
105     *  @param workspace The workspace for the cloned object.
106     *  @exception CloneNotSupportedException If cloned ports cannot have
107     *   as their container the cloned entity (this should not occur), or
108     *   if one of the attributes cannot be cloned.
109     *  @return A new ComponentEntity.
110     */
111    @Override
112    public Object clone(Workspace workspace) throws CloneNotSupportedException {
113        ArrayContains newObject = (ArrayContains) super.clone(workspace);
114        try {
115            newObject.array
116                    .setTypeAtLeast(ArrayType.arrayOf(newObject.element));
117        } catch (IllegalActionException e) {
118            throw new CloneNotSupportedException("Clone failed: " + e);
119        }
120        return newObject;
121    }
122
123    /** If there is an array input, then check to see whether it
124     *  contains the element given by the <i>element</i> port-parameter,
125     *  and output true or false accordingly.
126     */
127    @Override
128    public void fire() throws IllegalActionException {
129        super.fire();
130        // NOTE: This has be outside the if because we need to ensure
131        // that if an element token is provided that it is consumed even
132        // if there is no array token.
133        element.update();
134        Token elementToken = element.getToken();
135        if (array.hasToken(0)) {
136            ArrayToken token = (ArrayToken) array.get(0);
137            boolean contained = false;
138            for (int i = 0; i < token.length(); i++) {
139                BooleanToken bt = elementToken.isEqualTo(token.getElement(i));
140                if (bt.booleanValue()) {
141                    contained = true;
142                    break;
143                }
144            }
145            output.broadcast(new BooleanToken(contained));
146        }
147    }
148}