001/* A token that contains an array of tokens. 002 003 Copyright (c) 1997-2015 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 java.util.LinkedList; 031import java.util.List; 032 033import ptolemy.data.expr.ASTPtRootNode; 034import ptolemy.data.expr.ParseTreeEvaluator; 035import ptolemy.data.expr.PtParser; 036import ptolemy.data.type.ArrayType; 037import ptolemy.data.type.BaseType; 038import ptolemy.data.type.Type; 039import ptolemy.data.type.TypeLattice; 040import ptolemy.graph.CPO; 041import ptolemy.kernel.util.IllegalActionException; 042import ptolemy.kernel.util.InternalErrorException; 043 044/////////////////////////////////////////////////////////////////// 045//// ArrayToken 046 047/** 048 A token that contains an array of tokens. The operations between 049 arrays are defined pointwise, and require that the lengths of the 050 arrays are the same. The elements of the ArrayToken will be 051 converted to the least upper bound of their input types. Zero length 052 array tokens are supported, given a prototype element to determine 053 the type of the array. 054 055 @author Yuhong Xiong, Steve Neuendorffer, Contributor: Christopher Brooks 056 @version $Id$ 057 @since Ptolemy II 0.4 058 @Pt.ProposedRating Yellow (cxh) 059 @Pt.AcceptedRating Red (cxh) nil token code 060 */ 061public class ArrayToken extends AbstractNotConvertibleToken { 062 /** Construct an ArrayToken with the specified token array. 063 * The type of the resulting array is the least upper bound 064 * of the types of the elements. 065 * This class makes a copy of the given array, so 066 * the passed array may be reused. Note that this method cannot 067 * be used to create an empty array token, since the array token 068 * must have a type. Instead, use the constructor that takes a 069 * type argument or use the "emptyArray" function from the expression 070 * language. 071 * @param value An (not empty) array of tokens. 072 * @exception IllegalActionException If the length of the given array is 073 * zero. 074 */ 075 public ArrayToken(Token[] value) throws IllegalActionException { 076 int length = value.length; 077 078 if (length < 1) { 079 throw new IllegalActionException("ArrayToken(Token[]) called with " 080 + "a an array of length less than 1. To create an array " 081 + "of length 0, use the ArrayToken(Token) constructor " 082 + "or the \"emptyArray(type)\" function in the expression " 083 + "language. The reason is that elements in ArrayToken " 084 + "must have a type."); 085 } 086 087 _elementType = value[0].getType(); 088 089 for (int i = 0; i < length; i++) { 090 Type valueType = value[i].getType(); 091 _elementType = TypeLattice.leastUpperBound(_elementType, valueType); 092 } 093 094 _value = new Token[length]; 095 096 for (int i = 0; i < length; i++) { 097 _value[i] = _elementType.convert(value[i]); 098 } 099 } 100 101 /** Construct an ArrayToken with the first <i>length</i> 102 * elements of the specified token array. If <i>length</i> 103 * is greater than the length of the specified array, then the 104 * resulting array token will have exactly the number of elements 105 * in the specified array. 106 * The type of the resulting array is the least upper bound 107 * of the types of the elements. 108 * This class makes a copy of the given array, so 109 * the passed array may be reused. Note that this method cannot 110 * be used to create an empty array token, since the array token 111 * must have a type. Instead, use the constructor that takes a 112 * type argument or use the "emptyArray" function from the expression 113 * language. 114 * @param value An (not empty) array of tokens. 115 * @param length The number of elements to be used from the 116 * specified array. 117 * @exception IllegalActionException If the length of the given array is 118 * zero. 119 */ 120 public ArrayToken(Token[] value, int length) throws IllegalActionException { 121 if (length > value.length) { 122 length = value.length; 123 } 124 125 if (length < 1) { 126 throw new IllegalActionException("ArrayToken(Token[]) called with " 127 + "a an empty array. To create an array " 128 + "of length 0, use the ArrayToken(Token) constructor " 129 + "or the \"emptyArray(type)\" function in the expression " 130 + "language. The reason is that elements in ArrayToken " 131 + "must have a type."); 132 } 133 134 _elementType = value[0].getType(); 135 136 for (int i = 0; i < length; i++) { 137 Type valueType = value[i].getType(); 138 _elementType = TypeLattice.leastUpperBound(_elementType, valueType); 139 } 140 141 _value = new Token[length]; 142 143 for (int i = 0; i < length; i++) { 144 _value[i] = _elementType.convert(value[i]); 145 } 146 } 147 148 /** Construct an ArrayToken from the specified string. 149 * The format of the string is a list of comma separated 150 * token values that begins with "{" and ends with "}". 151 * For example 152 * <code> 153 * "{1, 2, 3}" 154 * </code> 155 * @param init A string expression of an array. 156 * @exception IllegalActionException If the string does 157 * not contain a parsable array. 158 */ 159 public ArrayToken(String init) throws IllegalActionException { 160 PtParser parser = new PtParser(); 161 ASTPtRootNode tree = parser.generateParseTree(init); 162 ParseTreeEvaluator evaluator = new ParseTreeEvaluator(); 163 Token token = evaluator.evaluateParseTree(tree); 164 165 if (token instanceof ArrayToken) { 166 _value = ((ArrayToken) token)._value; 167 _elementType = ((ArrayToken) token)._elementType; 168 } else { 169 throw new IllegalActionException("An array token cannot be" 170 + " created from the expression '" + init + "'"); 171 } 172 } 173 174 /** Construct an empty ArrayToken with the given element type. 175 * @param elementType A token type. 176 */ 177 public ArrayToken(Type elementType) { 178 _value = new Token[0]; 179 _elementType = elementType; 180 } 181 182 /** Construct an ArrayToken with the specified element type and 183 * token array. All the tokens in the array must have the type 184 * of element type (or a subclass), otherwise an exception will 185 * be thrown. This class makes a copy of the given array, so 186 * the passed array may be reused. 187 * @param elementType The type of the array. 188 * @param value An array of tokens. 189 * @exception IllegalActionException If the tokens in the array 190 * do not have the specified type. 191 */ 192 public ArrayToken(Type elementType, Token[] value) 193 throws IllegalActionException { 194 _elementType = elementType; 195 int length = value.length; 196 197 _value = new Token[length]; 198 199 for (int i = 0; i < length; i++) { 200 _value[i] = _elementType.convert(value[i]); 201 } 202 } 203 204 /////////////////////////////////////////////////////////////////// 205 //// public methods //// 206 207 /** Addition can occur between arrays, or between an array and a token 208 * of some base type (i.e., anything less than or equal to String). 209 * 210 * Addition is undefined between arrays and tokens of other incomparable 211 * data types such as Record and Union. 212 * @param rightArgument The array to be added to this array. 213 * @return The result of the addition. 214 * @exception IllegalActionException If addition between this array 215 * and the provided argument is not supported. 216 */ 217 @Override 218 public Token add(Token rightArgument) throws IllegalActionException { 219 220 int typeInfo = TypeLattice.compare(rightArgument, BaseType.STRING); 221 222 // Disallow addition between arrays and anything greater than or 223 // incomparable with String (e.g., Record, Union, etc). 224 if ((typeInfo == CPO.INCOMPARABLE || typeInfo == CPO.HIGHER) 225 && getClass() != rightArgument.getClass()) { 226 throw new IllegalActionException( 227 notSupportedDifferentClassesMessage("add", this, 228 rightArgument)); 229 } 230 try { 231 return _add(rightArgument); 232 } catch (IllegalActionException ex) { 233 // If the type-specific operation fails, then create a 234 // better error message that has the types of the 235 // arguments that were passed in. 236 throw new IllegalActionException(null, ex, 237 notSupportedMessage("add", this, rightArgument)); 238 } 239 } 240 241 /** If the left-hand argument is a base type token, then convert it 242 * to an array of size one. Then do an element-wise addition with 243 * each element of the right-hand argument. 244 * 245 * This method is only invoked when addition is attempted using a 246 * base type left-hand argument (e.g., 1 + {1, 2, 3} which will 247 * yield {2, 3, 4}. 248 * @param leftArgument The array to add this array to. 249 * @return The result of the addition. 250 * @exception IllegalActionException If addition between this array 251 * and the provided argument is not supported. 252 */ 253 @Override 254 public Token addReverse(Token leftArgument) throws IllegalActionException { 255 try { 256 int typeInfo = TypeLattice.compare(leftArgument, BaseType.STRING); 257 258 // Wrap base type argument in array in order to do expansion. 259 if ((typeInfo == CPO.LOWER || typeInfo == CPO.SAME)) { 260 Token[] arr = { leftArgument }; 261 return new ArrayToken(arr).add(this); 262 } else if (getClass() == leftArgument.getClass()) { 263 return ((ArrayToken) leftArgument).add(this); 264 } else { 265 throw new IllegalActionException(null, 266 notSupportedMessage("addReverse", this, leftArgument)); 267 } 268 } catch (IllegalActionException ex) { 269 // If the type-specific operation fails, then create a 270 // better error message that has the types of the 271 // arguments that were passed in. 272 throw new IllegalActionException(null, ex, 273 notSupportedMessage("addReverse", this, leftArgument)); 274 } 275 } 276 277 /** Append the given array to the end of this array, and return the 278 * resulting array. For example, if this array is {1, 2, 3} and the 279 * given array is {4, 5, 6}, then the result would be {1, 2, 3, 4, 5, 6}. 280 * If both arrays are empty, then an empty array is returned. 281 * 282 * @param token The array to be appended to the end of this array. 283 * @return The result array. 284 * @exception IllegalActionException If an array token cannot be created. 285 * @since Ptolemy II 7.1 286 */ 287 public ArrayToken append(ArrayToken token) throws IllegalActionException { 288 // FIXME: This should probably create an instance of a subclass the 289 // preserves and refers to the two subarrays. 290 int newLength = length() + token.length(); 291 if (newLength > 0) { 292 // NOTE: Do not use System.arraycopy if either of the two 293 // arrays being appended are a subclasses of this class, 294 // in which case values have to be accessed via the getElement() method, 295 // which is overridden in the subclasses. 296 Token[] result = new Token[newLength]; 297 if (_depth == 0 && token._depth == 0) { 298 // Safe to use ArrayCopy, which is much more efficient than 299 // the method below (performance measurements appending 50 300 // arrays of length 10,000 yielded a huge performance improvement). 301 System.arraycopy(_value, 0, result, 0, _value.length); 302 System.arraycopy(token._value, 0, result, _value.length, 303 token._value.length); 304 } else { 305 int headLength = length(); 306 int tailLength = token.length(); 307 for (int i = 0; i < headLength; i++) { 308 result[i] = getElement(i); 309 } 310 for (int i = headLength; i < headLength + tailLength; i++) { 311 result[i] = token.getElement(i - headLength); 312 } 313 } 314 return new ArrayToken(result); 315 } else { 316 return new ArrayToken(getElementType()); 317 } 318 } 319 320 /** Append the given arrays. 321 * @param tokens The list of arrays to be appended together. 322 * @return The result array. 323 * @exception IllegalActionException If an array token cannot be created, 324 * or if all specified arrays are empty. 325 * @since Ptolemy II 9.0 326 */ 327 public static ArrayToken append(ArrayToken[] tokens) 328 throws IllegalActionException { 329 // FIXME: This should probably create an instance of a subclass the 330 // preserves and refers to the subarrays. 331 332 // First, figure out the length of the result array. 333 boolean okToUseArrayCopy = true; 334 int newLength = 0; 335 for (ArrayToken token : tokens) { 336 if (token != null) { 337 newLength += token.length(); 338 if (token._depth > 0) { 339 okToUseArrayCopy = false; 340 } 341 } 342 } 343 if (newLength == 0) { 344 throw new IllegalActionException("Cannot append empty arrays."); 345 } 346 // NOTE: Do not use System.arraycopy if any of the 347 // arrays being appended are a subclasses of this class, 348 // in which case values have to be accessed via the getElement() method, 349 // which is overridden in the subclasses. 350 Token[] result = new Token[newLength]; 351 if (okToUseArrayCopy) { 352 // Safe to use ArrayCopy, which is much more efficient than 353 // the method below (performance measurements appending 50 354 // arrays of length 10,000 yielded a huge performance improvement). 355 int i = 0; 356 for (ArrayToken token : tokens) { 357 if (token != null) { 358 System.arraycopy(token._value, 0, result, i, 359 token._value.length); 360 i += token._value.length; 361 } 362 } 363 } else { 364 int i = 0; 365 for (ArrayToken token : tokens) { 366 if (token != null) { 367 for (int j = 0; j < token.length(); j++) { 368 result[i++] = token.getElement(j); 369 } 370 } 371 } 372 } 373 return new ArrayToken(result); 374 } 375 376 /** Convert an ArrayToken to an array of unsigned bytes. 377 * 378 * @param dataArrayToken to be converted to a unsigned byte array. 379 * @return dataBytes the resulting unsigned byte array. 380 * @see #unsignedByteArrayToArrayToken(byte[]) 381 */ 382 public static byte[] arrayTokenToUnsignedByteArray( 383 ArrayToken dataArrayToken) { 384 byte[] dataBytes = new byte[dataArrayToken.length()]; 385 386 for (int j = 0; j < dataArrayToken.length(); j++) { 387 UnsignedByteToken dataToken = (UnsignedByteToken) dataArrayToken 388 .getElement(j); 389 dataBytes[j] = dataToken.byteValue(); 390 } 391 392 return dataBytes; 393 } 394 395 /** Return an array of tokens populated with the contents of this 396 * array token. The returned array is a copy so the caller is 397 * free to modify it. 398 * @return An array of tokens. 399 */ 400 public Token[] arrayValue() { 401 // NOTE: Do not System.arraycopy here if the 402 // array is a subclasses of this class, 403 // so values have to be accessed via the getElement() method, 404 // which is overridden in the subclasses. 405 Token[] result = new Token[length()]; 406 if (_depth == 0) { 407 System.arraycopy(_value, 0, result, 0, _value.length); 408 } else { 409 for (int i = 0; i < length(); i++) { 410 result[i] = getElement(i); 411 } 412 } 413 return result; 414 } 415 416 /** Return a Boolean token that identifies whether the given token is an 417 * element of this array. 418 * 419 * @param element A token to test whether it is an element of this array. 420 * @return A true Boolean token if the element is found, or false 421 * otherwise. 422 */ 423 public BooleanToken contains(Token element) { 424 for (int i = 0; i < length(); i++) { 425 if (getElement(i).equals(element)) { 426 return BooleanToken.TRUE; 427 } 428 } 429 return BooleanToken.FALSE; 430 } 431 432 /** Divide this array token by the specified argument. 433 * If the argument is an array token and it has 434 * the same length as this array token, and the division is elementwise. 435 * Otherwise, each element is divided by the argument. 436 * This overrides the base class to allow division by scalars. 437 * @param rightArgument The token to divide into this token. 438 * @return A new token containing the result. 439 * @exception IllegalActionException If the argument token is 440 * an array token but does not have the same length as this 441 * token, or if division is not supported between the elements 442 * of this array and the argument. 443 */ 444 @Override 445 public Token divide(Token rightArgument) throws IllegalActionException { 446 try { 447 return _divide(rightArgument); 448 } catch (IllegalActionException ex) { 449 // If the type-specific operation fails, then create a 450 // better error message that has the types of the 451 // arguments that were passed in. 452 throw new IllegalActionException(null, ex, 453 notSupportedMessage("divide", this, rightArgument)); 454 } 455 } 456 457 /** Divide this array token into the specified argument. 458 * If the argument is an array token and it has 459 * the same length as this array token, and the division is elementwise. 460 * Otherwise, each element is divided into the argument. 461 * This overrides the base class to allow division into scalars. 462 * @param rightArgument The token into which to divide this token. 463 * @return A new token containing the result. 464 * @exception IllegalActionException If the argument token is 465 * an array token but does not have the same length as this 466 * token, or if division is not supported between the elements 467 * of this array and the argument. 468 */ 469 @Override 470 public Token divideReverse(Token rightArgument) 471 throws IllegalActionException { 472 try { 473 return _divideReverse(rightArgument); 474 } catch (IllegalActionException ex) { 475 // If the type-specific operation fails, then create a 476 // better error message that has the types of the 477 // arguments that were passed in. 478 throw new IllegalActionException(null, ex, 479 notSupportedMessage("divide", this, rightArgument)); 480 } 481 } 482 483 /** Add the given token to each element of this array. 484 * @param token The token to be added to this token. 485 * @return A new array token. 486 * @exception IllegalActionException If the argument token is not 487 * of a type that can be added to an element of this token. 488 */ 489 public ArrayToken elementAdd(Token token) throws IllegalActionException { 490 Token[] result = new Token[length()]; 491 492 try { 493 for (int i = 0; i < length(); i++) { 494 result[i] = getElement(i).add(token); 495 } 496 } catch (IllegalActionException ex) { 497 // If the type-specific operation fails, then create a 498 // better error message that has the types of the 499 // arguments that were passed in. 500 throw new IllegalActionException(null, ex, 501 notSupportedMessage("elementAdd", this, token)); 502 } 503 504 return new ArrayToken(result); 505 } 506 507 /** Divide each element of this array by the given token. 508 * @param token The token which which to divide this token 509 * @return An array token. 510 * @exception IllegalActionException If the argument token is not 511 * of a type that can be divided into an element of this token. 512 */ 513 public ArrayToken elementDivide(Token token) throws IllegalActionException { 514 Token[] result = new Token[length()]; 515 516 try { 517 for (int i = 0; i < length(); i++) { 518 result[i] = getElement(i).divide(token); 519 } 520 } catch (IllegalActionException ex) { 521 // If the type-specific operation fails, then create a 522 // better error message that has the types of the 523 // arguments that were passed in. 524 throw new IllegalActionException(null, ex, 525 notSupportedMessage("elementDivide", this, token)); 526 } 527 528 return new ArrayToken(result); 529 } 530 531 /** Modulo each element of this array by the given token. 532 * @param token The token with which to modulo this token. 533 * @return An array token. 534 * @exception IllegalActionException If the argument token is not 535 * of a type that can be used with modulo. 536 */ 537 public ArrayToken elementModulo(Token token) throws IllegalActionException { 538 Token[] result = new Token[length()]; 539 540 try { 541 for (int i = 0; i < length(); i++) { 542 result[i] = getElement(i).modulo(token); 543 } 544 } catch (IllegalActionException ex) { 545 // If the type-specific operation fails, then create a 546 // better error message that has the types of the 547 // arguments that were passed in. 548 throw new IllegalActionException(null, ex, 549 notSupportedMessage("elementModulo", this, token)); 550 } 551 552 return new ArrayToken(result); 553 } 554 555 /** Multiply each element of this array by the given token. 556 * @param token The token with which to multiply this token. 557 * @return An array token. 558 * @exception IllegalActionException If the argument token is 559 * not of a type that can be multiplied to an element of this token. 560 */ 561 public ArrayToken elementMultiply(Token token) 562 throws IllegalActionException { 563 Token[] result = new Token[length()]; 564 565 try { 566 for (int i = 0; i < length(); i++) { 567 result[i] = getElement(i).multiply(token); 568 } 569 } catch (IllegalActionException ex) { 570 // If the type-specific operation fails, then create a 571 // better error message that has the types of the 572 // arguments that were passed in. 573 throw new IllegalActionException(null, ex, 574 notSupportedMessage("elementMultiply", this, token)); 575 } 576 577 return new ArrayToken(result); 578 } 579 580 /** Return the (exact) return type of the elementMultiply function 581 * above. This returns a new array type whose element type is 582 * the least upper bound of the element type of this token and 583 * the given type. 584 * @param type1 The type of the base of the corresponding function. 585 * @param type2 The type of the argument of the corresponding function. 586 * @return The type of the value returned from the corresponding 587 * function. 588 * @exception IllegalActionException Not thrown in this base class. 589 */ 590 public static Type elementMultiplyReturnType(Type type1, Type type2) 591 throws IllegalActionException { 592 if (type1 instanceof ArrayType) { 593 return new ArrayType(TypeLattice.leastUpperBound( 594 ((ArrayType) type1).getElementType(), type2)); 595 } else { 596 return new ArrayType(BaseType.UNKNOWN); 597 } 598 } 599 600 /** Subtract the given token from each element of this array. 601 * @param token The token to subtract from this token. 602 * @return An array token. 603 * @exception IllegalActionException If the argument token is not 604 * of a type that can be subtracted from an element of this token. 605 */ 606 public ArrayToken elementSubtract(Token token) 607 throws IllegalActionException { 608 Token[] result = new Token[length()]; 609 610 try { 611 for (int i = 0; i < length(); i++) { 612 result[i] = getElement(i).subtract(token); 613 } 614 } catch (IllegalActionException ex) { 615 // If the type-specific operation fails, then create a 616 // better error message that has the types of the 617 // arguments that were passed in. 618 throw new IllegalActionException(null, ex, 619 notSupportedMessage("elementSubtract", this, token)); 620 } 621 622 return new ArrayToken(result); 623 } 624 625 /** Return true if the class of the argument is ArrayToken and of 626 * the same length and the elements are equal to that of this 627 * token. Equality of the contained elements is tested by their 628 * equals() method. 629 * @param object the object to compare with. 630 * @return True if the argument is an array token of the same length 631 * and the elements are equal to that of this token. 632 */ 633 @Override 634 public boolean equals(Object object) { 635 if (object == null) { 636 return false; 637 } 638 // This test allows instances of a subclass. 639 if (!(object instanceof ArrayToken)) { 640 return false; 641 } 642 643 if (this.isNil() || ((ArrayToken) object).isNil()) { 644 return false; 645 } 646 647 ArrayToken arrayArgument = (ArrayToken) object; 648 int length = arrayArgument.length(); 649 650 if (length() != length) { 651 return false; 652 } 653 654 for (int i = 0; i < length(); i++) { 655 if (!getElement(i).equals(arrayArgument.getElement(i)) 656 || getElement(i).isNil()) { 657 return false; 658 } 659 } 660 661 return true; 662 } 663 664 /** Extract a non-contiguous subarray either by giving a boolean array 665 * of the same length of this array describing which elements to 666 * include and which to include, or by giving an an array of an 667 * arbitrary length giving the indices of elements from this array 668 * to include in the subarray. An example of the first form is 669 * {"red","green","blue"}.extract({true,false,true}), which evaluates 670 * to {"red", "blue"}. An example of the second form is 671 * {"red","green","blue"}.extract({2,0,1,1}), which evaluates to 672 * {"blue", "red", "green", "green"}. 673 * @param selection An ArrayToken describing the selection of elements 674 * with which to form the subarray: either an array of integer 675 * indices, or an array of boolean inclusion/exclusion choices. 676 * @return An ArrayToken containing the extracted subarray. 677 * @exception IllegalActionException If the argument type is invalid 678 * or the result cannot be constructed. 679 * @exception ArrayIndexOutOfBoundsException If the argument is an array 680 * of integers, and one or more of those integers is not a valid 681 * index into this array. 682 * @since Ptolemy II 4.1 683 */ 684 public ArrayToken extract(ArrayToken selection) 685 throws IllegalActionException { 686 List result = new LinkedList(); 687 688 if (selection.getElementType().equals(BaseType.BOOLEAN)) { 689 if (selection.length() != length()) { 690 throw new IllegalActionException( 691 "When the argument is an array of booleans, it must have " 692 + "the same length as this array."); 693 } 694 695 for (int i = 0; i < selection.length(); i++) { 696 if (selection.getElement(i).equals(BooleanToken.TRUE)) { 697 result.add(getElement(i)); 698 } 699 } 700 } else if (selection.getElementType().equals(BaseType.INT)) { 701 for (int i = 0; i < selection.length(); i++) { 702 // We could check for out-of-bounds indicies and ignore them, 703 // if we wanted to. 704 int index = ((IntToken) selection.getElement(i)).intValue(); 705 result.add(getElement(index)); 706 } 707 } else { 708 throw new IllegalActionException( 709 "The argument must be {boolean} or {int}."); 710 } 711 712 if (result.size() > 0) { 713 Token[] resultArray = new Token[result.size()]; 714 resultArray = (Token[]) result.toArray(resultArray); 715 return new ArrayToken(resultArray); 716 } else { 717 return new ArrayToken(getElementType()); 718 } 719 } 720 721 /** Return the element at the specified index. 722 * @param index The index of the desired element. 723 * @return The token contained in this array token at the 724 * specified index. 725 * @exception ArrayIndexOutOfBoundsException If the specified index is 726 * outside the range of the token array. 727 */ 728 public Token getElement(int index) { 729 return _value[index]; 730 } 731 732 /** Return the type contained in this ArrayToken. 733 * @return A Type. 734 */ 735 public Type getElementType() { 736 return _elementType; 737 } 738 739 /** Return the type of this ArrayToken. 740 * @return An ArrayType. 741 */ 742 @Override 743 public Type getType() { 744 return new ArrayType(getElementType(), length()); 745 } 746 747 /** Return a hash code value for this token. This method returns 748 * the hash code of the first element, unless the array is empty, 749 * in which case it returns the hashCode of the element type, unless 750 * there is no element type, in which case it returns the superclass hash code. 751 * @return A hash code value for this token. 752 */ 753 @Override 754 public int hashCode() { 755 if (length() > 0) { 756 return getElement(0).hashCode(); 757 } else if (getElementType() != null) { 758 return getElementType().hashCode(); 759 } else { 760 return super.hashCode(); 761 } 762 } 763 764 /** Test that the value of this token is close to the first argument, 765 * where "close" means that the distance between them is less than 766 * or equal to the second argument. This method only makes sense 767 * for arrays where where the distance between elements is reasonably 768 * represented as a double. This class overrides the superclass to not 769 * insist that the two array tokens be instances of the same class, 770 * but rather that they just both be array tokens, and then defers to the 771 * _isCloseTo() method. 772 * @param token The token to test closeness of this token with. 773 * @param epsilon The value that we use to determine whether two 774 * tokens are close. 775 * @return A boolean token that contains the value true if the 776 * value of this token is close to that of the argument token. 777 * @exception IllegalActionException If the argument token and 778 * this token are implemented in different classes. 779 */ 780 @Override 781 public BooleanToken isCloseTo(Token token, double epsilon) 782 throws IllegalActionException { 783 if (!(token instanceof ArrayToken)) { 784 throw new IllegalActionException( 785 notSupportedDifferentClassesMessage("isCloseTo", this, 786 token)); 787 } 788 789 try { 790 return _isCloseTo(token, epsilon); 791 } catch (IllegalActionException ex) { 792 // If the type-specific operation fails, then create a 793 // better error message that has the types of the 794 // arguments that were passed in. 795 throw new IllegalActionException(null, ex, 796 notSupportedMessage("isCloseTo", this, token)); 797 } 798 } 799 800 /** Return true if the token is nil, (aka null or missing). 801 * Nil or missing tokens occur when a data source is sparsely populated. 802 * @return True if the token is the {@link #NIL} token. 803 */ 804 @Override 805 public boolean isNil() { 806 // We use a method here so that we can easily change how 807 // we determine if a token is nil without modify lots of classes. 808 // Can't use equals() here, or we'll go into an infinite loop. 809 return this == ArrayToken.NIL; 810 } 811 812 /** Return the length of the contained token array. 813 * @return The length of the contained token array. 814 */ 815 public int length() { 816 return _value.length; 817 } 818 819 /** Return a new token whose value is the value of this token 820 * modulo the value of the argument token. 821 * This overrides the base class to allow modulo by scalars. 822 * @param rightArgument The token to divide into this token. 823 * @return A new token containing the result. 824 * @exception IllegalActionException If the argument token and 825 * this token are implemented in different classes, or the 826 * operation does not make sense for the given types. 827 */ 828 @Override 829 public Token modulo(Token rightArgument) throws IllegalActionException { 830 try { 831 return _modulo(rightArgument); 832 } catch (IllegalActionException ex) { 833 // If the type-specific operation fails, then create a 834 // better error message that has the types of the 835 // arguments that were passed in. 836 throw new IllegalActionException(null, ex, 837 notSupportedMessage("modulo", this, rightArgument)); 838 } 839 } 840 841 /** Return a new token whose value is the value of the argument 842 * modulo the value of this token. 843 * This overrides the base class to allow modulo by scalars. 844 * @param rightArgument The token to divide into this token. 845 * @return A new token containing the result. 846 * @exception IllegalActionException If the argument token and 847 * this token are implemented in different classes, or the 848 * operation does not make sense for the given types. 849 */ 850 @Override 851 public Token moduloReverse(Token rightArgument) 852 throws IllegalActionException { 853 try { 854 return _moduloReverse(rightArgument); 855 } catch (IllegalActionException ex) { 856 // If the type-specific operation fails, then create a 857 // better error message that has the types of the 858 // arguments that were passed in. 859 throw new IllegalActionException(null, ex, 860 notSupportedMessage("modulo", this, rightArgument)); 861 } 862 } 863 864 /** Multiply this array token by the specified argument. 865 * If the argument is an array token and it has 866 * the same length as this array token, and the multiplication is elementwise. 867 * Otherwise, each element is multiplied by the argument. 868 * This overrides the base class to allow multiplication by scalars. 869 * @param rightArgument The token to multiply by this token. 870 * @return A new token containing the result. 871 * @exception IllegalActionException If the argument token is 872 * an array token but does not have the same length as this 873 * token, or if multiplication is not supported between the elements 874 * of this array and the argument. 875 */ 876 @Override 877 public Token multiply(Token rightArgument) throws IllegalActionException { 878 try { 879 return _multiply(rightArgument); 880 } catch (IllegalActionException ex) { 881 // If the type-specific operation fails, then create a 882 // better error message that has the types of the 883 // arguments that were passed in. 884 throw new IllegalActionException(null, ex, 885 notSupportedMessage("multiply", this, rightArgument)); 886 } 887 } 888 889 /** Multiply this array token by the specified argument. 890 * If the argument is an array token and it has 891 * the same length as this array token, and the multiplication is elementwise. 892 * Otherwise, each element is multiplied by the argument. 893 * This overrides the base class to allow multiplication by scalars. 894 * @param leftArgument The token to multiply by this token. 895 * @return A new token containing the result. 896 * @exception IllegalActionException If the argument token is 897 * an array token but does not have the same length as this 898 * token, or if multiplication is not supported between the elements 899 * of this array and the argument. 900 */ 901 @Override 902 public Token multiplyReverse(Token leftArgument) 903 throws IllegalActionException { 904 try { 905 return _multiply(leftArgument); 906 } catch (IllegalActionException ex) { 907 // If the type-specific operation fails, then create a 908 // better error message that has the types of the 909 // arguments that were passed in. 910 throw new IllegalActionException(null, ex, 911 notSupportedMessage("multiplyReverse", this, leftArgument)); 912 } 913 } 914 915 /** Return a new ArrayToken representing the multiplicative 916 * identity. The returned token contains an array of the same 917 * size as the array contained by this token, and each element of 918 * the array in the returned token is the multiplicative identity 919 * of the corresponding element of this token. 920 * @return An ArrayToken. 921 * @exception IllegalActionException If multiplicative identity is not 922 * supported by the element token. 923 */ 924 @Override 925 public Token one() throws IllegalActionException { 926 Token[] oneValueArray = new Token[length()]; 927 928 for (int i = 0; i < length(); i++) { 929 oneValueArray[i] = getElement(i).one(); 930 } 931 932 return new ArrayToken(oneValueArray); 933 } 934 935 /** Return a new ArrayToken whose elements are in reverse order of this 936 * ArrayToken. 937 * @return An ArrayToken 938 * @exception IllegalActionException If thrown while creating the new 939 * ArrayToken. 940 */ 941 public ArrayToken reverse() throws IllegalActionException { 942 Token[] result = new Token[length()]; 943 for (int i = 0; i < length(); i++) { 944 result[i] = getElement(length() - i - 1); 945 } 946 return new ArrayToken(result); 947 } 948 949 /** Return the contiguous subarray starting at the specified index to the 950 * end of this array. If the specified index is out of range, 951 * then return an empty array with the same type as this array. 952 * @param index The index of the beginning of the subarray. 953 * @return The extracted subarray. 954 * @exception IllegalActionException If the index argument is 955 * less than zero. 956 * @since Ptolemy II 7.1 957 */ 958 public ArrayToken subarray(int index) throws IllegalActionException { 959 return subarray(index, length() - index); 960 } 961 962 /** Return the contiguous subarray starting at the specified index and 963 * of the specified length. If the specified index is out of range, 964 * or if the specified length extends beyond the end of the array, 965 * then return an empty array with the same type as this array. 966 * @param index The index of the beginning of the subarray. 967 * @param count The length of the subarray. 968 * @return The extracted subarray. 969 * @exception IllegalActionException If the index argument is 970 * less than zero. 971 * @since Ptolemy II 4.1 972 */ 973 public ArrayToken subarray(int index, int count) 974 throws IllegalActionException { 975 if (index < 0) { 976 throw new IllegalActionException( 977 "index argument of subarray() must be non-negative."); 978 } 979 980 // NOTE: Do not use System.arraycopy here if the 981 // array is a subclass of this class, 982 // so values have to be accessed via the getElement() method, 983 // which is overridden in the subclasses. 984 985 if (count > 0 && index < length() && index >= 0) { 986 if (count + index > length()) { 987 count = length() - index; 988 } 989 990 Token[] result = new Token[count]; 991 if (_depth == 0) { 992 System.arraycopy(_value, index, result, 0, count); 993 } else { 994 for (int i = 0; i < count; i++) { 995 result[i] = getElement(index + i); 996 } 997 } 998 return new ArrayToken(result); 999 } else { 1000 return new ArrayToken(getElementType()); 1001 } 1002 } 1003 1004 /** Subtract from this array token the specified argument. 1005 * If the argument is an array token and it has 1006 * the same length as this array token, and the subtraction is elementwise. 1007 * Otherwise, subtract the argument from each element. 1008 * This overrides the base class to allow subtraction by scalars. 1009 * @param rightArgument The token to subtract from this token. 1010 * @return A new token containing the result. 1011 * @exception IllegalActionException If the argument token is 1012 * an array token but does not have the same length as this 1013 * token or length 1, or if division is not supported between the elements 1014 * of this array and the argument. 1015 */ 1016 @Override 1017 public Token subtract(Token rightArgument) throws IllegalActionException { 1018 try { 1019 return _subtract(rightArgument); 1020 } catch (IllegalActionException ex) { 1021 // If the type-specific operation fails, then create a 1022 // better error message that has the types of the 1023 // arguments that were passed in. 1024 throw new IllegalActionException(null, ex, 1025 notSupportedMessage("subtract", this, rightArgument)); 1026 } 1027 } 1028 1029 /** Subtract this array token from the specified argument. 1030 * If the argument is an array token and it has 1031 * the same length as this array token, and the subtraction is elementwise. 1032 * Otherwise, each element is subtracted from the argument. 1033 * This overrides the base class to allow subtraction from scalars. 1034 * @param rightArgument The token from which to subtract this token. 1035 * @return A new token containing the result. 1036 * @exception IllegalActionException If the argument token is 1037 * an array token but does not have the same length as this 1038 * token or length 1, or if division is not supported between the elements 1039 * of this array and the argument. 1040 */ 1041 @Override 1042 public Token subtractReverse(Token rightArgument) 1043 throws IllegalActionException { 1044 try { 1045 return _subtractReverse(rightArgument); 1046 } catch (IllegalActionException ex) { 1047 // If the type-specific operation fails, then create a 1048 // better error message that has the types of the 1049 // arguments that were passed in. 1050 throw new IllegalActionException(null, ex, 1051 notSupportedMessage("divide", this, rightArgument)); 1052 } 1053 } 1054 1055 /** Return the value of this token as a string that can be parsed 1056 * by the expression language to recover a token with the same value. 1057 * @return A string beginning with "{" that contains expressions 1058 * for every element in the array separated by commas, ending with "}". 1059 */ 1060 @Override 1061 public String toString() { 1062 StringBuffer buffer = new StringBuffer("{"); 1063 1064 for (int i = 0; i < length(); i++) { 1065 buffer.append(getElement(i).toString()); 1066 1067 if (i < length() - 1) { 1068 buffer.append(", "); 1069 } 1070 } 1071 1072 buffer.append("}"); 1073 return buffer.toString(); 1074 } 1075 1076 /** Take an array of unsigned bytes and convert it to an ArrayToken. 1077 * 1078 * @param dataBytes data to be converted to an ArrayToken. 1079 * @return dataArrayToken the resulting ArrayToken. 1080 * @exception IllegalActionException If ArrayToken can not be created. 1081 * @see #arrayTokenToUnsignedByteArray(ArrayToken) 1082 */ 1083 public static ArrayToken unsignedByteArrayToArrayToken(byte[] dataBytes) 1084 throws IllegalActionException { 1085 int bytesAvailable = dataBytes.length; 1086 Token[] dataArrayToken = new Token[bytesAvailable]; 1087 1088 for (int j = 0; j < bytesAvailable; j++) { 1089 dataArrayToken[j] = new UnsignedByteToken(dataBytes[j]); 1090 } 1091 1092 return new ArrayToken(dataArrayToken); 1093 } 1094 1095 /** Return a new array with all elements equal to those of this 1096 * array except the one at position <i>index</i>, which has value 1097 * given by <i>value</i>. If the index is out of range, then return 1098 * this array token unchanged. The element type of the new array is the 1099 * least upper bound of the element type of this array and the specified 1100 * value. 1101 * @param index The index of the element to be updated. 1102 * @param value The value of the element to be updated. 1103 * @return A new array. 1104 * @exception IllegalActionException Should not be thrown in this base class. 1105 */ 1106 public ArrayToken update(int index, Token value) 1107 throws IllegalActionException { 1108 if (index < 0 || index >= length()) { 1109 return this; 1110 } 1111 return new UpdatedArrayToken(this, index, value); 1112 } 1113 1114 /** Returns a new ArrayToken representing the additive identity. 1115 * The returned token contains an array of the same size as the 1116 * array contained by this token, and each element of the array 1117 * in the returned token is the additive identity of the 1118 * corresponding element of this token. 1119 * @return An ArrayToken. 1120 * @exception IllegalActionException If additive identity is not 1121 * supported by an element token. 1122 */ 1123 @Override 1124 public Token zero() throws IllegalActionException { 1125 if (length() == 0) { 1126 return this; 1127 } 1128 1129 Token[] zeroValueArray = new Token[length()]; 1130 1131 for (int i = 0; i < length(); i++) { 1132 zeroValueArray[i] = getElement(i).zero(); 1133 } 1134 1135 return new ArrayToken(zeroValueArray); 1136 } 1137 1138 /////////////////////////////////////////////////////////////////// 1139 //// public variables //// 1140 1141 /** A token that represents a missing value. 1142 * Null or missing tokens are common in analytical systems 1143 * like R and SAS where they are used to handle sparsely populated data 1144 * sources. In database parlance, missing tokens are sometimes called 1145 * null tokens. Since null is a Java keyword, we use the term "nil". 1146 */ 1147 public static final ArrayToken NIL = new ArrayToken(BaseType.NIL); 1148 1149 /////////////////////////////////////////////////////////////////// 1150 //// protected methods //// 1151 1152 /** Return a new token whose value is the value of the argument 1153 * token added to the value of this token. It is assumed that 1154 * this class is the class of the argument. 1155 * @param rightArgument The token whose value we add to the value 1156 * of this token. 1157 * @return A new array token containing the result. 1158 * @exception IllegalActionException If the argument is an 1159 * ArrayToken of different length, or calling the add method of 1160 * an element token throws it. 1161 */ 1162 @Override 1163 protected Token _add(Token rightArgument) throws IllegalActionException { 1164 Token[] result = null; 1165 1166 if (rightArgument instanceof ArrayToken) { 1167 // Right argument is an array. 1168 ArrayToken rightArray = (ArrayToken) rightArgument; 1169 // If array's lengths match, then do element-wise addition. 1170 if (rightArray.length() == length()) { 1171 result = new Token[length()]; 1172 for (int i = 0; i < length(); i++) { 1173 result[i] = getElement(i).add(rightArray.getElement(i)); 1174 } 1175 } else { 1176 if (rightArray.length() == 1) { 1177 // If the left array has only one element, then expand it 1178 // and do element-wise addition. 1179 result = new Token[length()]; 1180 for (int i = 0; i < length(); i++) { 1181 result[i] = getElement(i).add(rightArray.getElement(0)); 1182 } 1183 } else if (length() == 1) { 1184 // If the right array has only one element, then expand it 1185 // and do element-wise addition. 1186 result = new Token[rightArray.length()]; 1187 for (int i = 0; i < rightArray.length(); i++) { 1188 result[i] = getElement(0).add(rightArray.getElement(i)); 1189 } 1190 } else { 1191 // Use this method to get a consistent error message 1192 // defined in one place. 1193 _checkArgumentLength(rightArgument); 1194 // Note that we might not be setting result here. 1195 } 1196 1197 } 1198 } else { 1199 // Right argument is not an array. 1200 // Add right argument to each element in the array. 1201 result = new Token[length()]; 1202 for (int i = 0; i < length(); i++) { 1203 result[i] = getElement(i).add(rightArgument); 1204 } 1205 } 1206 if (result == null) { 1207 // FindBugs wants us to check to see if result is null. 1208 throw new InternalErrorException("result was null?"); 1209 } 1210 return new ArrayToken(result); 1211 } 1212 1213 /** Return a new token whose value is the value of this token 1214 * divided by the value of the argument token. If the argument 1215 * is an array, then the division is done 1216 * elementwise. Otherwise, this method assumes that each 1217 * element can be divided by the argument and performs the 1218 * division. 1219 * @param rightArgument The token to divide this token by. 1220 * @return A new token containing the result. 1221 * @exception IllegalActionException If the argument is an 1222 * ArrayToken of different length, or calling the divide method 1223 * of the element token throws it. 1224 */ 1225 @Override 1226 protected Token _divide(Token rightArgument) throws IllegalActionException { 1227 Token[] result = new Token[length()]; 1228 if (rightArgument instanceof ArrayToken) { 1229 ArrayToken rightArray = (ArrayToken) rightArgument; 1230 if (rightArray.length() == length()) { 1231 for (int i = 0; i < length(); i++) { 1232 result[i] = getElement(i).divide(rightArray.getElement(i)); 1233 } 1234 } else { 1235 // Maybe one argument or the other is an array 1236 // of length one, converted automatically from 1237 // a scalar. 1238 if (rightArray.length() == 1) { 1239 Token scalar = rightArray.getElement(0); 1240 for (int i = 0; i < length(); i++) { 1241 result[i] = getElement(i).divide(scalar); 1242 } 1243 } else if (length() == 1) { 1244 result = new Token[rightArray.length()]; 1245 Token scalar = getElement(0); 1246 for (int i = 0; i < rightArray.length(); i++) { 1247 result[i] = scalar.divide(rightArray.getElement(i)); 1248 } 1249 } else { 1250 // Use this method to get a consistent error message 1251 // defined in one place. 1252 _checkArgumentLength(rightArgument); 1253 } 1254 } 1255 } else { 1256 for (int i = 0; i < length(); i++) { 1257 result[i] = getElement(i).divide(rightArgument); 1258 } 1259 } 1260 return new ArrayToken(result); 1261 } 1262 1263 /** Return a new token whose value is the value of this token 1264 * divided into the value of the argument token. If the argument 1265 * is an array, then the division is done 1266 * elementwise. Otherwise, this method assumes that the argument 1267 * can be divided by each element of this array and performs the 1268 * division. 1269 * @param rightArgument The token into which to divide this token. 1270 * @return A new token containing the result. 1271 * @exception IllegalActionException If the argument is an 1272 * ArrayToken of different length, or calling the divide method 1273 * of the element token throws it. 1274 */ 1275 protected Token _divideReverse(Token rightArgument) 1276 throws IllegalActionException { 1277 if (rightArgument instanceof ArrayToken) { 1278 return ((ArrayToken) rightArgument).divide(this); 1279 } else { 1280 Token[] result = new Token[length()]; 1281 for (int i = 0; i < length(); i++) { 1282 result[i] = rightArgument.divide(getElement(i)); 1283 } 1284 return new ArrayToken(result); 1285 } 1286 } 1287 1288 /** Test whether the value of this token is close to the first argument, 1289 * where "close" means that the distance between them is less than 1290 * or equal to the second argument. This method only makes sense 1291 * for tokens where the distance between them is reasonably 1292 * represented as a double. It is assumed that the argument is 1293 * an ArrayToken, and the isCloseTo() method of the array elements 1294 * is used. 1295 * @param token The token to compare to this token. 1296 * @param epsilon The value that we use to determine whether two 1297 * tokens are close. 1298 * @exception IllegalActionException If the elements do not support 1299 * this comparison. 1300 * @return A true-valued token if the first argument is close 1301 * to this token. 1302 */ 1303 @Override 1304 protected BooleanToken _isCloseTo(Token token, double epsilon) 1305 throws IllegalActionException { 1306 ArrayToken rightArray = (ArrayToken) token; 1307 1308 if (length() != rightArray.length()) { 1309 return BooleanToken.FALSE; 1310 } 1311 1312 for (int i = 0; i < length(); i++) { 1313 // Here is where isCloseTo() differs from isEqualTo(). 1314 // Note that we return false the first time we hit an 1315 // element token that is not close to our current element token. 1316 BooleanToken result = getElement(i) 1317 .isCloseTo(rightArray.getElement(i), epsilon); 1318 1319 if (result.booleanValue() == false) { 1320 return BooleanToken.FALSE; 1321 } 1322 } 1323 1324 return BooleanToken.TRUE; 1325 } 1326 1327 /** Return a true-valued token if the argument is equal to this one. 1328 * The isEqualTo() method of the element tokens is used to make the 1329 * comparison. It is assumed that the argument is an ArrayToken. 1330 * @param token The token to compare to this token. 1331 * @exception IllegalActionException If the element types do not 1332 * support this comparison. 1333 * @return A true-valued token if the argument is equal. 1334 */ 1335 @Override 1336 protected BooleanToken _isEqualTo(Token token) 1337 throws IllegalActionException { 1338 if (isNil() || token.isNil()) { 1339 return BooleanToken.FALSE; 1340 } 1341 1342 _checkArgumentLength(token); 1343 1344 ArrayToken rightArray = (ArrayToken) token; 1345 1346 for (int i = 0; i < length(); i++) { 1347 BooleanToken result = getElement(i) 1348 .isEqualTo(rightArray.getElement(i)); 1349 1350 if (result.booleanValue() == false) { 1351 return BooleanToken.FALSE; 1352 } 1353 } 1354 1355 return BooleanToken.TRUE; 1356 } 1357 1358 /** Return a new token whose value is the value of this token 1359 * modulo the value of the argument token. It is assumed that 1360 * this class is the class of the argument. 1361 * @param rightArgument The token to modulo this token by. 1362 * @return A new token containing the result. 1363 * @exception IllegalActionException If the argument is an 1364 * ArrayToken of different length, or calling the modulo method 1365 * of the element token throws it. 1366 */ 1367 @Override 1368 protected Token _modulo(Token rightArgument) throws IllegalActionException { 1369 Token[] result = new Token[length()]; 1370 if (rightArgument instanceof ArrayToken) { 1371 ArrayToken rightArray = (ArrayToken) rightArgument; 1372 if (rightArray.length() == length()) { 1373 for (int i = 0; i < length(); i++) { 1374 result[i] = getElement(i).modulo(rightArray.getElement(i)); 1375 } 1376 } else { 1377 // Maybe one argument or the other is an array 1378 // of length one, converted automatically from 1379 // a scalar. 1380 if (rightArray.length() == 1) { 1381 Token scalar = rightArray.getElement(0); 1382 for (int i = 0; i < length(); i++) { 1383 result[i] = getElement(i).modulo(scalar); 1384 } 1385 } else if (length() == 1) { 1386 result = new Token[rightArray.length()]; 1387 Token scalar = getElement(0); 1388 for (int i = 0; i < rightArray.length(); i++) { 1389 result[i] = scalar.modulo(rightArray.getElement(i)); 1390 } 1391 } else { 1392 // Use this method to get a consistent error message 1393 // defined in one place. 1394 _checkArgumentLength(rightArgument); 1395 } 1396 } 1397 } else { 1398 for (int i = 0; i < length(); i++) { 1399 result[i] = getElement(i).modulo(rightArgument); 1400 } 1401 } 1402 return new ArrayToken(result); 1403 } 1404 1405 /** Return a new token whose value is the value of this token 1406 * modulo the value of the argument token. If the argument 1407 * is an array, then the modulo is done 1408 * elementwise. Otherwise, this method assumes that the argument 1409 * can be moduloed by each element of this array and performs the 1410 * modulo. 1411 * @param rightArgument The token into which to modulo this token. 1412 * @return A new token containing the result. 1413 * @exception IllegalActionException If the argument is an 1414 * ArrayToken of different length, or calling the modulo method 1415 * of the element token throws it. 1416 */ 1417 protected Token _moduloReverse(Token rightArgument) 1418 throws IllegalActionException { 1419 if (rightArgument instanceof ArrayToken) { 1420 return ((ArrayToken) rightArgument).modulo(this); 1421 } else { 1422 Token[] result = new Token[length()]; 1423 for (int i = 0; i < length(); i++) { 1424 result[i] = rightArgument.modulo(getElement(i)); 1425 } 1426 return new ArrayToken(result); 1427 } 1428 } 1429 1430 /** Return a new token whose value is the value of this token 1431 * multiplied by the value of the argument token. If the argument 1432 * is an array token, then it is required to have the same length 1433 * as this array token, and the multiplication is performed 1434 * elementwise. Otherwise, each element of this array is multiplied 1435 * by the argument. 1436 * @param rightArgument The token to multiply this token by. 1437 * @return A new token containing the result. 1438 * @exception IllegalActionException If the argument is an 1439 * ArrayToken of different length, or calling the multiply method 1440 * of the element token throws it. 1441 */ 1442 @Override 1443 protected Token _multiply(Token rightArgument) 1444 throws IllegalActionException { 1445 Token[] result = new Token[length()]; 1446 if (rightArgument instanceof ArrayToken) { 1447 ArrayToken rightArray = (ArrayToken) rightArgument; 1448 if (rightArray.length() == length()) { 1449 for (int i = 0; i < length(); i++) { 1450 result[i] = getElement(i) 1451 .multiply(rightArray.getElement(i)); 1452 } 1453 } else { 1454 // Maybe one argument or the other is an array 1455 // of length one, converted automatically from 1456 // a scalar. 1457 if (rightArray.length() == 1) { 1458 Token scalar = rightArray.getElement(0); 1459 for (int i = 0; i < length(); i++) { 1460 result[i] = getElement(i).multiply(scalar); 1461 } 1462 } else if (length() == 1) { 1463 result = new Token[rightArray.length()]; 1464 Token scalar = getElement(0); 1465 for (int i = 0; i < rightArray.length(); i++) { 1466 result[i] = rightArray.getElement(i).multiply(scalar); 1467 } 1468 } else { 1469 // Use this method to get a consistent error message 1470 // defined in one place. 1471 _checkArgumentLength(rightArgument); 1472 } 1473 } 1474 } else { 1475 for (int i = 0; i < length(); i++) { 1476 result[i] = getElement(i).multiply(rightArgument); 1477 } 1478 } 1479 return new ArrayToken(result); 1480 } 1481 1482 /** Return a new token whose value is the value of the argument 1483 * token subtracted from the value of this token. It is assumed 1484 * that this class is the class of the argument. 1485 * @param rightArgument The token to subtract to this token. 1486 * @return A new token containing the result. 1487 * @exception IllegalActionException If the argument is an 1488 * ArrayToken of different length, or calling the subtract method 1489 * of the element token throws it. 1490 */ 1491 @Override 1492 protected Token _subtract(Token rightArgument) 1493 throws IllegalActionException { 1494 Token[] result = new Token[length()]; 1495 if (rightArgument instanceof ArrayToken) { 1496 ArrayToken rightArray = (ArrayToken) rightArgument; 1497 if (rightArray.length() == length()) { 1498 for (int i = 0; i < length(); i++) { 1499 result[i] = getElement(i) 1500 .subtract(rightArray.getElement(i)); 1501 } 1502 } else { 1503 // Maybe one argument or the other is an array 1504 // of length one, converted automatically from 1505 // a scalar. 1506 if (rightArray.length() == 1) { 1507 Token scalar = rightArray.getElement(0); 1508 for (int i = 0; i < length(); i++) { 1509 result[i] = getElement(i).subtract(scalar); 1510 } 1511 } else if (length() == 1) { 1512 result = new Token[rightArray.length()]; 1513 Token scalar = getElement(0); 1514 for (int i = 0; i < rightArray.length(); i++) { 1515 result[i] = scalar.subtract(rightArray.getElement(i)); 1516 } 1517 } else { 1518 // Use this method to get a consistent error message 1519 // defined in one place. 1520 _checkArgumentLength(rightArgument); 1521 } 1522 } 1523 } else { 1524 for (int i = 0; i < length(); i++) { 1525 result[i] = getElement(i).subtract(rightArgument); 1526 } 1527 } 1528 return new ArrayToken(result); 1529 } 1530 1531 /** Return a new token whose value is the value of this token 1532 * subtracted from the value of the argument token. If the argument 1533 * is an array with the same length as this one, then the division is done 1534 * elementwise. Otherwise, this method assumes that the argument 1535 * can be subtracted from each element of this array and performs the 1536 * subtraction. 1537 * @param rightArgument The token from which to subtract this token. 1538 * @return A new token containing the result. 1539 * @exception IllegalActionException If the argument is an 1540 * ArrayToken of different length (and not length 1), or calling the subtract method 1541 * of the element token throws it. 1542 */ 1543 protected Token _subtractReverse(Token rightArgument) 1544 throws IllegalActionException { 1545 if (rightArgument instanceof ArrayToken) { 1546 return ((ArrayToken) rightArgument).subtract(this); 1547 } else { 1548 Token[] result = new Token[length()]; 1549 for (int i = 0; i < length(); i++) { 1550 result[i] = rightArgument.subtract(getElement(i)); 1551 } 1552 return new ArrayToken(result); 1553 } 1554 } 1555 1556 /////////////////////////////////////////////////////////////////// 1557 //// protected variables //// 1558 1559 /** The depth of the hierarchy of array tokens used to represent 1560 * this array. If this array is an instance of this base class, 1561 * then the depth is 0. Subclasses, however, represent the array 1562 * in terms of instances of ArrayToken, and in that case, the 1563 * value of this variable will be the longest path in the hierarchy 1564 * to the an instance of this ArrayToken class. 1565 */ 1566 protected int _depth = 0; 1567 1568 /** The type of this array. */ 1569 protected Type _elementType; 1570 1571 /////////////////////////////////////////////////////////////////// 1572 //// private methods //// 1573 // Throw an exception if the argument is not an ArrayToken of the 1574 // same length. 1575 private void _checkArgumentLength(Token token) 1576 throws IllegalActionException { 1577 int length = ((ArrayToken) token).length(); 1578 1579 if (length() != length) { 1580 throw new IllegalActionException("The length of the argument (" 1581 + length + ") is not the same as the length of this token (" 1582 + length() + ")."); 1583 } 1584 } 1585 1586 /////////////////////////////////////////////////////////////////// 1587 //// private variables //// 1588 1589 /** The array of values of this array token. */ 1590 private Token[] _value; 1591}