001/* A token that contains an array of tokens.
002
003 Copyright (c) 1997-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.data;
029
030import ptolemy.data.type.TupleType;
031import ptolemy.data.type.Type;
032import ptolemy.kernel.util.IllegalActionException;
033
034///////////////////////////////////////////////////////////////////
035//// TupleToken
036
037/**
038 A token that contains an ordered set of tokens.
039
040 @author Yang Zhao
041 @version $Id$
042 @since Ptolemy II 10.0
043 @Pt.ProposedRating Yellow (neuendor)
044 @Pt.AcceptedRating Red (cxh)
045 */
046public class TupleToken extends Token {
047    /** Construct a TupleToken with the specified token array as its value.
048     *  @param value The value.
049     */
050    public TupleToken(Token[] value) {
051        _initialize(value);
052    }
053
054    ///////////////////////////////////////////////////////////////////
055    ////                         public methods                    ////
056
057    /** Return an array of tokens populated with the contents of this
058     *  array token.  The returned array is a copy so the caller is
059     *  free to modify it.
060     *  @return An array of tokens.
061     */
062    public Token[] tupleValue() {
063        Token[] result = new Token[_value.length];
064
065        // This code will create a token array of a more specific type
066        // than token.  Eventually, we would like to use this code
067        // since it will simplify writing some actors, but for the
068        // moment the code generator cannot deal with it.
069        // (Token[])
070        //             java.lang.reflect.Array.newInstance(
071        //                     getElementType().getTokenClass(),
072        //                     _value.length);
073        System.arraycopy(_value, 0, result, 0, _value.length);
074        return result;
075    }
076
077    /** Return true if the class of the argument is TupleToken and it
078     *  has the same length and the elements are equal to that of this
079     *  token.  Equality of the contained elements is tested by their
080     *  equals() method.
081     *  @param object The object to compare with.
082     *  @return True if the argument is a tuple token of the same length
083     *   and the elements are equal to that of this token.
084     */
085    @Override
086    public boolean equals(Object object) {
087        if (object == null) {
088            return false;
089        }
090        // This test rules out instances of a subclass.
091        if (object.getClass() != getClass()) {
092            return false;
093        }
094
095        TupleToken tupleArgument = (TupleToken) object;
096        int length = tupleArgument.length();
097
098        if (_value.length != length) {
099            return false;
100        }
101
102        Token[] array = tupleArgument._value;
103
104        for (int i = 0; i < length; i++) {
105            if (!_value[i].equals(array[i])) {
106                return false;
107            }
108        }
109
110        return true;
111    }
112
113    /** Return the element at the specified index.
114     *  @param index The index of the desired element.
115     *  @return The token contained in this array token at the
116     *   specified index.
117     *  @exception ArrayIndexOutOfBoundsException If the specified index is
118     *   outside the range of the token array.
119     */
120    public Token getElement(int index) {
121        return _value[index];
122    }
123
124    /** Return the element type at the specified index.
125     *  @param index The index of the desired element.
126     *  @return The type of the token contained in this array token at the
127     *   specified index.
128     *  @exception ArrayIndexOutOfBoundsException If the specified index is
129     *   outside the range of the token array.
130     */
131    public Type getElementType(int index) {
132        return _value[index].getType();
133    }
134
135    /** Return the type of this token, which is a TupleType populated
136     *  with the types of the value of this token.
137     *  @return A TupleType.
138     */
139    @Override
140    public Type getType() {
141        Type[] types = new Type[_value.length];
142
143        for (int i = 0; i < _value.length; i++) {
144            types[i] = getElementType(i);
145        }
146
147        return new TupleType(types);
148    }
149
150    /** Return a hash code value for this token. This method returns the
151     *  hash code length xored with the values of the tuples.
152     *  @return A hash code value for this token.
153     */
154    @Override
155    public int hashCode() {
156        int results = 0;
157        for (Token element : _value) {
158            results ^= element.hashCode();
159        }
160        return results;
161    }
162
163    /** Return a true-valued token if the argument is equal to this one.
164     *  The isEqualTo() method of the element tokens is used to make the
165     *         comparison.  It is assumed that the argument is a TupleToken.
166     *  @param token The token to compare to this token.
167     *  @exception IllegalActionException If the element types do not
168     *   support this comparison.
169     *  @return A true-valued token if the argument is equal.
170     */
171    @Override
172    public BooleanToken isEqualTo(Token token) throws IllegalActionException {
173        if (getClass() != token.getClass()) {
174            throw new IllegalActionException("isEqualTo not supported"
175                    + " between " + this.getType().toString() + " and "
176                    + token.getType().toString());
177        }
178
179        if (isNil() || token.isNil()) {
180            return BooleanToken.FALSE;
181        }
182
183        TupleToken rightTuple = (TupleToken) token;
184        if (length() != rightTuple.length()) {
185            return BooleanToken.FALSE;
186        }
187
188        for (int i = 0; i < _value.length; i++) {
189            BooleanToken result = _value[i].isEqualTo(rightTuple.getElement(i));
190
191            if (result.booleanValue() == false) {
192                return BooleanToken.FALSE;
193            }
194        }
195
196        return BooleanToken.TRUE;
197    }
198
199    /** Return the length of the contained token array.
200     *  @return The length of the contained token array.
201     */
202    public int length() {
203        return _value.length;
204    }
205
206    /** Merge two tuple tokens into one by concatenating their tokens.
207     *  @param first The first tuple token.
208     *  @param second The second tuple token.
209     *  @return The merged tuple token.
210     */
211    public static TupleToken merge(TupleToken first, TupleToken second) {
212        if (first == VOID) {
213            return second;
214        }
215
216        if (second == VOID) {
217            return first;
218        }
219
220        Token[] firstTokens = first._value;
221        Token[] secondTokens = second._value;
222        Token[] result = new Token[firstTokens.length + secondTokens.length];
223        System.arraycopy(firstTokens, 0, result, 0, firstTokens.length);
224        System.arraycopy(secondTokens, 0, result, firstTokens.length,
225                secondTokens.length);
226        return new TupleToken(result);
227    }
228
229    /** Return a new TupleToken representing the multiplicative
230     *  identity.  The returned token contains a tuple of the same
231     *  size as the tuple contained by this token, where each element of
232     *  the tuple in the returned token is the multiplicative identity
233     *  of the corresponding element of this token.
234     *  @return A TupleToken of multiplicative identities.
235     *  @exception IllegalActionException If multiplicative identity is not
236     *   supported by an element token.
237     */
238    @Override
239    public Token one() throws IllegalActionException {
240        Token[] oneValueTuple = new Token[_value.length];
241
242        for (int i = 0; i < _value.length; i++) {
243            oneValueTuple[i] = _value[i].one();
244        }
245
246        return new TupleToken(oneValueTuple);
247    }
248
249    /** Return the value of this token as a string that can be parsed
250     *  by the expression language to recover a token with the same value.
251     *  FIXME: This is not currently supported by the expression language.
252     *  @return A string beginning with "&lt;" that contains expressions
253     *   for every element in the tuple separated by commas, ending with "&gt;".
254     */
255    @Override
256    public String toString() {
257        StringBuffer buffer = new StringBuffer("<");
258
259        for (int i = 0; i < _value.length; i++) {
260            buffer.append(_value[i].toString());
261
262            if (i < _value.length - 1) {
263                buffer.append(", ");
264            }
265        }
266
267        buffer.append(">");
268        return buffer.toString();
269    }
270
271    /** Returns a new TupleToken representing the additive identity.
272     *  The returned token contains a tuple of the same size as the
273     *  tuple contained by this token, and each element of the tuple
274     *  in the returned token is the additive identity of the
275     *  corresponding element of this token.
276     *  @return A TupleToken with additive identities.
277     *  @exception IllegalActionException If the additive identity is not
278     *   supported by an element token.
279     */
280    @Override
281    public Token zero() throws IllegalActionException {
282        Token[] zeroValueTuple = new Token[_value.length];
283
284        for (int i = 0; i < _value.length; i++) {
285            zeroValueTuple[i] = _value[i].zero();
286        }
287
288        return new TupleToken(zeroValueTuple);
289    }
290
291    ///////////////////////////////////////////////////////////////////
292    ////                         public variables                  ////
293
294    /** An empty tuple token. */
295    public static final TupleToken VOID = new TupleToken(new Token[0]);
296
297    ///////////////////////////////////////////////////////////////////
298    ////                         private methods                   ////
299    // Initialize this token using the specified array.
300    private void _initialize(Token[] value) {
301        int length = value.length;
302        _value = new Token[length];
303
304        for (int i = 0; i < length; i++) {
305            _value[i] = value[i];
306        }
307    }
308
309    ///////////////////////////////////////////////////////////////////
310    ////                         private variables                 ////
311    private Token[] _value;
312}