001/* Abstract base class for tokens that contain a scalar. 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 FIXME: setUnitCategory seems to violate immutability. 028 */ 029package ptolemy.data; 030 031import ptolemy.data.type.Type; 032import ptolemy.data.type.TypeLattice; 033import ptolemy.data.unit.UnitUtilities; 034import ptolemy.graph.CPO; 035import ptolemy.kernel.util.IllegalActionException; 036import ptolemy.math.Complex; 037import ptolemy.math.FixPoint; 038 039/////////////////////////////////////////////////////////////////// 040//// ScalarToken 041 042/** 043 Abstract base class for tokens that contain a scalar. This base class 044 extends the Token class to properly implement type conversion and the 045 units portion of the standard operations for scalar tokens. It also 046 adds methods for querying the natural ordering between scalars. 047 048 <p> This class has a number of protected abstract methods that subclasses 049 must implement. These methods need only implement the numerical 050 portion of the operation between two tokens of the same type. This 051 base class will handle the conversion of tokens from different types 052 to the same type before calling the protected method, and the proper 053 computation of the units of the returned token afterwards. 054 055 <p> In general, any instance of a scalar token may be optionally 056 associated with a set of units. In the arithmetic methods add(), 057 modulo(), and subtract(), the two operands must have the same 058 units. Otherwise, an exception will be thrown. In the methods 059 multiply() and divide(), the units of the resulting token will be 060 computed automatically. IMPORTANT: The protected methods implemented 061 in derived classes are expected to return a new token in the case of 062 multiply and divide. This new token will automatically have its units 063 set correctly by this base class implementation. Certain cases, such 064 as multiplication by one, cannot be optimized to simply return an the 065 input token without performing the multiplication, since the units of 066 the result may be different than the units of either input token. 067 068 @author Yuhong Xiong, Mudit Goel, Steve Neuendorffer 069 @version $Id$ 070 @since Ptolemy II 0.2 071 @Pt.ProposedRating Green (neuendor) 072 @Pt.AcceptedRating Green (yuhong) 073 */ 074public abstract class ScalarToken extends Token 075 implements BitwiseOperationToken, PartiallyOrderedToken { 076 /////////////////////////////////////////////////////////////////// 077 //// public methods //// 078 079 /** Return a ScalarToken containing the absolute value of the 080 * value of this token. If this token contains a non-negative 081 * number, it is returned directly; otherwise, a new token is 082 * returned. Note that it is explicitly allowable to return this 083 * token, since the units are the same. This method defers to 084 * the _absolute() method to perform the operation, and derived 085 * classes should implement that method to provide type-specific 086 * behavior. 087 * @return A ScalarToken with the same units, and likely to be of 088 * the same type as this token. 089 * If this token is a nil token, then {@link ptolemy.data.Token#NIL} 090 * is returned. 091 */ 092 public final ScalarToken absolute() { 093 if (isNil()) { 094 return this; 095 } 096 ScalarToken result = _absolute(); 097 098 if (_unitCategoryExponents != null && !_isUnitless()) { 099 result._unitCategoryExponents = _copyOfCategoryExponents(); 100 } 101 return result; 102 } 103 104 /** Return a new token whose value is the sum of this token and 105 * the argument. Type conversion also occurs here, so that the 106 * operation is performed at the least type necessary to ensure 107 * precision. The returned type is the same as the type chosen 108 * for the operation, which is the higher of the type of this 109 * token and the argument type. Subclasses should implement the 110 * protected _add() method to perform the correct type-specific 111 * operation. 112 * @param rightArgument The token to add to this token. 113 * @return A new token containing the result. 114 * @exception IllegalActionException If the argument token and 115 * this token are of incomparable types, or have different units, 116 * or the operation does not make sense for the given types. 117 */ 118 @Override 119 public final Token add(Token rightArgument) throws IllegalActionException { 120 int typeInfo = TypeLattice.compare(getType(), rightArgument); 121 122 if (typeInfo == CPO.SAME || getClass() == rightArgument.getClass()) { 123 return _doAdd(rightArgument); 124 } else if (typeInfo == CPO.HIGHER) { 125 ScalarToken convertedArgument = (ScalarToken) getType() 126 .convert(rightArgument); 127 128 try { 129 return _doAdd(convertedArgument); 130 } catch (IllegalActionException ex) { 131 // If the type-specific operation fails, then create a 132 // better error message that has the types of the 133 // arguments that were passed in. 134 throw new IllegalActionException(null, ex, 135 notSupportedMessage("add", this, rightArgument)); 136 } 137 } else if (typeInfo == CPO.LOWER 138 || rightArgument instanceof MatrixToken) { 139 // NOTE: If the right argument is an instance of MatrixToken, 140 // then we try reversing the add. 141 return rightArgument.addReverse(this); 142 } else { 143 // Items being added are incomparable. 144 // However, addition may still be possible because 145 // the LUB of the types might support it. E.g., [double]+complex, 146 // where the LUB is [complex]. 147 Type lubType = (Type) TypeLattice.lattice() 148 .leastUpperBound(getType(), rightArgument.getType()); 149 150 // If the LUB is a new type, try it. 151 if (!lubType.equals(getType())) { 152 Token lub = lubType.convert(this); 153 154 // Caution: convert() might return this again, e.g. 155 // if lubType is general. Only proceed if the conversion 156 // returned a new type. 157 if (!lub.getType().equals(getType())) { 158 return lub.add(rightArgument); 159 } 160 } 161 162 throw new IllegalActionException(notSupportedIncomparableMessage( 163 "add", this, rightArgument)); 164 } 165 } 166 167 /** Return a new token whose value is the sum of this token and 168 * the argument. Type conversion also occurs here, so that the 169 * operation is performed at the least type necessary to ensure 170 * precision. The returned type is the same as the type chosen 171 * for the operation, which is the higher of the type of this 172 * token and the argument type. Subclasses should implement the 173 * protected _add() method to perform the correct type-specific 174 * operation. 175 * @param leftArgument The token to add this token to. 176 * @return A new token containing the result. 177 * @exception IllegalActionException If the argument token and 178 * this token are of incomparable types, or have different units, 179 * or the operation does not make sense for the given types. 180 */ 181 @Override 182 public final Token addReverse(ptolemy.data.Token leftArgument) 183 throws IllegalActionException { 184 int typeInfo = TypeLattice.compare(leftArgument, getType()); 185 186 // We would normally expect this to be LOWER, since this will almost 187 // always be called by add, so put that case first. 188 if (typeInfo == CPO.LOWER) { 189 ScalarToken convertedArgument = (ScalarToken) getType() 190 .convert(leftArgument); 191 192 try { 193 return convertedArgument._doAdd(this); 194 } catch (IllegalActionException ex) { 195 // If the type-specific operation fails, then create a 196 // better error message that has the types of the 197 // arguments that were passed in. 198 throw new IllegalActionException(null, ex, 199 notSupportedMessage("addReverse", this, leftArgument)); 200 } 201 } else if (typeInfo == CPO.SAME) { 202 return ((ScalarToken) leftArgument)._doAdd(this); 203 } else if (typeInfo == CPO.HIGHER) { 204 return leftArgument.add(this); 205 } else { 206 throw new IllegalActionException(notSupportedIncomparableMessage( 207 "addReverse", this, leftArgument)); 208 } 209 } 210 211 /** Returns a token representing the bitwise AND of this token and 212 * the given token. 213 * @param rightArgument The ScalarToken to bitwise AND with this one. 214 * @return The bitwise AND. 215 * @exception IllegalActionException If the given token is not 216 * compatible for this operation, or the operation does not make 217 * sense for this type. 218 */ 219 @Override 220 public BitwiseOperationToken bitwiseAnd(Token rightArgument) 221 throws IllegalActionException { 222 int typeInfo = TypeLattice.compare(getType(), rightArgument); 223 224 if (typeInfo == CPO.SAME) { 225 return _doBitwiseAnd(rightArgument); 226 } else if (typeInfo == CPO.HIGHER) { 227 ScalarToken convertedArgument = (ScalarToken) getType() 228 .convert(rightArgument); 229 230 try { 231 return _doBitwiseAnd(convertedArgument); 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("bitwiseAnd", this, rightArgument)); 238 } 239 } else if (typeInfo == CPO.LOWER) { 240 if (!(rightArgument instanceof BitwiseOperationToken)) { 241 throw new IllegalActionException( 242 notSupportedMessage("bitwiseAnd", this, rightArgument)); 243 } else { 244 // This code uses the fact that bitwise AND is always 245 // commutative, there is no need to add a bitwiseAndReverse 246 // method. 247 return ((BitwiseOperationToken) rightArgument).bitwiseAnd(this); 248 } 249 } else { 250 throw new IllegalActionException(notSupportedIncomparableMessage( 251 "bitwiseAnd", this, rightArgument)); 252 } 253 } 254 255 /** Returns a token representing the bitwise NOT of this token. 256 * @return The bitwise NOT of this token. 257 * @exception IllegalActionException If the given token is not 258 * compatible for this operation, or the operation does not make 259 * sense for this type. 260 */ 261 @Override 262 public BitwiseOperationToken bitwiseNot() throws IllegalActionException { 263 ScalarToken result = _bitwiseNot(); 264 if (_unitCategoryExponents != null && !_isUnitless()) { 265 result._unitCategoryExponents = _copyOfCategoryExponents(); 266 } 267 return result; 268 } 269 270 /** Returns a token representing the bitwise OR of this token and 271 * the given token. 272 * @param rightArgument The ScalarToken to bitwise OR with this one. 273 * @return The bitwise OR. 274 * @exception IllegalActionException If the given token is not 275 * compatible for this operation, or the operation does not make 276 * sense for this type. 277 */ 278 @Override 279 public BitwiseOperationToken bitwiseOr(Token rightArgument) 280 throws IllegalActionException { 281 int typeInfo = TypeLattice.compare(getType(), rightArgument); 282 283 if (typeInfo == CPO.SAME) { 284 return _doBitwiseOr(rightArgument); 285 } else if (typeInfo == CPO.HIGHER) { 286 ScalarToken convertedArgument = (ScalarToken) getType() 287 .convert(rightArgument); 288 289 try { 290 return _doBitwiseOr(convertedArgument); 291 } catch (IllegalActionException ex) { 292 // If the type-specific operation fails, then create a 293 // better error message that has the types of the 294 // arguments that were passed in. 295 throw new IllegalActionException(null, ex, 296 notSupportedMessage("bitwiseOr", this, rightArgument)); 297 } 298 } else if (typeInfo == CPO.LOWER) { 299 if (!(rightArgument instanceof BitwiseOperationToken)) { 300 throw new IllegalActionException( 301 notSupportedMessage("bitwiseOr", this, rightArgument)); 302 } else { 303 // This code uses the fact that bitwise OR is always 304 // commutative, there is no need to add a bitwiseOrReverse 305 // method. 306 return ((BitwiseOperationToken) rightArgument).bitwiseOr(this); 307 } 308 } else { 309 throw new IllegalActionException(notSupportedIncomparableMessage( 310 "bitwiseOr", this, rightArgument)); 311 } 312 } 313 314 /** Returns a token representing the bitwise XOR of this token and 315 * the given token. 316 * @param rightArgument The ScalarToken to bitwise XOR with this one. 317 * @return The bitwise XOR. 318 * @exception IllegalActionException If the given token is not 319 * compatible for this operation, or the operation does not make 320 * sense for this type. 321 */ 322 @Override 323 public BitwiseOperationToken bitwiseXor(Token rightArgument) 324 throws IllegalActionException { 325 int typeInfo = TypeLattice.compare(getType(), rightArgument); 326 327 if (typeInfo == CPO.SAME) { 328 return _doBitwiseXor(rightArgument); 329 } else if (typeInfo == CPO.HIGHER) { 330 ScalarToken convertedArgument = (ScalarToken) getType() 331 .convert(rightArgument); 332 333 try { 334 return _doBitwiseXor(convertedArgument); 335 } catch (IllegalActionException ex) { 336 // If the type-specific operation fails, then create a 337 // better error message that has the types of the 338 // arguments that were passed in. 339 throw new IllegalActionException(null, ex, 340 notSupportedMessage("bitwiseXor", this, rightArgument)); 341 } 342 } else if (typeInfo == CPO.LOWER) { 343 if (!(rightArgument instanceof BitwiseOperationToken)) { 344 throw new IllegalActionException( 345 notSupportedMessage("bitwiseXor", this, rightArgument)); 346 } else { 347 // This code uses the fact that bitwise XOR is always 348 // commutative, there is no need to add a bitwiseXorReverse 349 // method. 350 return ((BitwiseOperationToken) rightArgument).bitwiseXor(this); 351 } 352 } else { 353 throw new IllegalActionException(notSupportedIncomparableMessage( 354 "bitwiseXor", this, rightArgument)); 355 } 356 } 357 358 // /** If the token is an instance of a subclass of ScalarToken, 359 // * then return the token. Otherwise, throw an exception. 360 // * @param token The token to be converted to a ScalarToken. 361 // * @return An instance of ScalarToken. 362 // * @exception IllegalActionException If the argument is not 363 // * already an instance of ScalarToken. 364 // */ 365 // public static ScalarToken convert(Token token) 366 // throws IllegalActionException { 367 // if (token instanceof ScalarToken) { 368 // return (ScalarToken) token; 369 // } 370 // throw new IllegalActionException( 371 // notSupportedIncomparableConversionMessage(token, "scalar")); 372 // } 373 374 /** Return the value in the token as a byte. 375 * In this base class, we just throw an exception. 376 * @return The byte value contained in this token. 377 * @exception IllegalActionException Always thrown. 378 */ 379 public byte byteValue() throws IllegalActionException { 380 throw new IllegalActionException( 381 notSupportedConversionMessage(this, "byte")); 382 } 383 384 /** Return the value of this token as a Complex. 385 * In this base class, we just throw an exception. 386 * @return A Complex 387 * @exception IllegalActionException Always thrown. 388 */ 389 public Complex complexValue() throws IllegalActionException { 390 throw new IllegalActionException( 391 notSupportedConversionMessage(this, "Complex")); 392 } 393 394 /** Return a new token whose value is the value of this token 395 * divided by the value of the argument token. Type conversion 396 * also occurs here, so that the operation is performed at the 397 * least type necessary to ensure precision. The returned type 398 * is the same as the type chosen for the operation, which is the 399 * higher of the type of this token and the argument type. The 400 * returned token will also have the correct units. Subclasses 401 * should implement the protected _divide() method to perform the 402 * correct type-specific operation. 403 * @param rightArgument The token to divide into this token. 404 * @return A new token containing the result. 405 * @exception IllegalActionException If the argument token and 406 * this token are of incomparable types, or the operation does 407 * not make sense for the given types. 408 */ 409 @Override 410 public final Token divide(Token rightArgument) 411 throws IllegalActionException { 412 int typeInfo = TypeLattice.compare(getType(), rightArgument); 413 414 if (typeInfo == CPO.SAME || getClass() == rightArgument.getClass()) { 415 return _doDivide(rightArgument); 416 } else if (typeInfo == CPO.HIGHER) { 417 ScalarToken convertedArgument = (ScalarToken) getType() 418 .convert(rightArgument); 419 420 try { 421 return _doDivide(convertedArgument); 422 } catch (IllegalActionException ex) { 423 // If the type-specific operation fails, then create a 424 // better error message that has the types of the 425 // arguments that were passed in. 426 throw new IllegalActionException(null, ex, 427 notSupportedMessage("divide", this, rightArgument)); 428 } 429 } else if (typeInfo == CPO.LOWER) { 430 return rightArgument.divideReverse(this); 431 } else { 432 // Items being divided are incomparable. 433 // However, division may still be possible because 434 // the LUB of the types might support it. E.g., [double]/complex, 435 // where the LUB is [complex]. 436 Type lubType = (Type) TypeLattice.lattice() 437 .leastUpperBound(getType(), rightArgument.getType()); 438 439 // If the LUB is a new type, try it. 440 if (lubType != null && !lubType.equals(getType())) { 441 Token lub = lubType.convert(this); 442 443 // Caution: convert() might return this again, e.g. 444 // if lubType is general. Only proceed if the conversion 445 // returned a new type. 446 if (!lub.getType().equals(getType())) { 447 return lub.divide(rightArgument); 448 } 449 } 450 451 // LUB does not support it, but it still might be 452 // possible, e.g. with expressions like double / {double}. 453 // Only divideReverse() could support it at this time however. 454 // This will throw an exception if it is not supported. 455 return rightArgument.divideReverse(this); 456 } 457 } 458 459 /** Return a new token whose value is the value of this token 460 * divided into the value of the argument token. Type conversion 461 * also occurs here, so that the operation is performed at the 462 * least type necessary to ensure precision. The returned type 463 * is the same as the type chosen for the operation, which is the 464 * higher of the type of this token and the argument type. The 465 * returned token will also have the correct units. Subclasses 466 * should implement the protected _divide() method to perform the 467 * correct type-specific operation. 468 * @param leftArgument The token to be divided into the value of 469 * this token. 470 * @return A new token containing the result. 471 * @exception IllegalActionException If the argument token and 472 * this token are of incomparable types, or the operation does 473 * not make sense for the given types. 474 */ 475 @Override 476 public final Token divideReverse(Token leftArgument) 477 throws IllegalActionException { 478 int typeInfo = TypeLattice.compare(leftArgument, getType()); 479 480 // We would normally expect this to be LOWER, since this will almost 481 // always be called by divide, so put that case first. 482 if (typeInfo == CPO.LOWER) { 483 ScalarToken convertedArgument = (ScalarToken) getType() 484 .convert(leftArgument); 485 486 try { 487 return convertedArgument._doDivide(this); 488 } catch (IllegalActionException ex) { 489 // If the type-specific operation fails, then create a 490 // better error message that has the types of the 491 // arguments that were passed in. 492 throw new IllegalActionException(null, ex, notSupportedMessage( 493 "divideReverse", this, leftArgument)); 494 } 495 } else if (typeInfo == CPO.SAME) { 496 return ((ScalarToken) leftArgument)._doDivide(this); 497 } else if (typeInfo == CPO.HIGHER) { 498 return leftArgument.divide(this); 499 } else { 500 throw new IllegalActionException(notSupportedIncomparableMessage( 501 "divideReverse", this, leftArgument)); 502 } 503 } 504 505 /** Return the value of this token as a double. 506 * In this base class, we just throw an exception. 507 * @return A double 508 * @exception IllegalActionException Always thrown 509 */ 510 public double doubleValue() throws IllegalActionException { 511 throw new IllegalActionException( 512 notSupportedConversionMessage(this, "double")); 513 } 514 515 /** Return the value of this token as a FixPoint. 516 * In this base class, we just throw an exception. 517 * @return A FixPoint 518 * @exception IllegalActionException Always thrown. 519 */ 520 public FixPoint fixValue() throws IllegalActionException { 521 throw new IllegalActionException( 522 notSupportedConversionMessage(this, "fixedpoint")); 523 } 524 525 /** Return the value of this token as a float 526 * In this base class, we just throw an exception. 527 * @return A float 528 * @exception IllegalActionException Always thrown 529 */ 530 public float floatValue() throws IllegalActionException { 531 throw new IllegalActionException( 532 notSupportedConversionMessage(this, "float")); 533 } 534 535 /** Return the type of this token. Subclasses must implement this method 536 * to return the correct type. 537 * @return BaseType.SCALAR 538 */ 539 @Override 540 public abstract Type getType(); 541 542 /** Return a scalar token that contains the value of this token in the 543 * units of the argument token. The unit category of the argument token 544 * must be the same as that of this token, otherwise, an exception will 545 * be thrown. The returned token is unitless. 546 * @param units A scalar token that represents a unit. 547 * @return A scalar token that does not have a unit. 548 * @exception IllegalActionException If the unit category of the 549 * argument token is not the same as that of this one. 550 */ 551 public ScalarToken inUnitsOf(ScalarToken units) 552 throws IllegalActionException { 553 if (!_areUnitsEqual(units)) { 554 throw new IllegalActionException( 555 notSupportedMessage("inUnitsOf", this, units) 556 + " because the units are not the same."); 557 } 558 559 return (ScalarToken) this.divide(units); 560 } 561 562 /** Return the value of this token as an int. 563 * In this base class, we just throw an exception. 564 * @return The value of this token as an int. 565 * @exception IllegalActionException Always thrown. 566 */ 567 public int intValue() throws IllegalActionException { 568 throw new IllegalActionException( 569 notSupportedConversionMessage(this, "int")); 570 } 571 572 /** Test whether the value of this Token is close to the argument 573 * Token. The argument and this token are converted to 574 * equivalent types, and then compared. Generally, this is the 575 * higher of the type of this token and the argument type. 576 * Subclasses should implement the protected _isCloseTo() method 577 * to perform the correct type-specific operation. 578 * @see #isEqualTo 579 * @param rightArgument The token to test closeness of this token with. 580 * @param epsilon The value that we use to determine whether two 581 * tokens are close. 582 * @return A boolean token that contains the value true if the 583 * units of this token and the argument token are the same, and their 584 * values are close. 585 * @exception IllegalActionException If the argument token is not 586 * of a type that can be compared with this token, or the units 587 * are not the same. 588 */ 589 @Override 590 public final BooleanToken isCloseTo(Token rightArgument, double epsilon) 591 throws IllegalActionException { 592 // Note that if we had absolute(), subtraction() and islessThan() 593 // we could perhaps define this method for all tokens. However, 594 // Precise classes like IntToken not bother doing the absolute(), 595 // subtraction(), and isLessThan() method calls and should go 596 // straight to isEqualTo(). Also, these methods might introduce 597 // exceptions because of type conversion issues. 598 int typeInfo = TypeLattice.compare(getType(), rightArgument); 599 600 if (typeInfo == CPO.SAME || getClass() == rightArgument.getClass()) { 601 return _doIsCloseTo(rightArgument, epsilon); 602 } else if (typeInfo == CPO.HIGHER) { 603 ScalarToken convertedArgument = (ScalarToken) getType() 604 .convert(rightArgument); 605 606 try { 607 return _doIsCloseTo(convertedArgument, epsilon); 608 } catch (IllegalActionException ex) { 609 // If the type-specific operation fails, then create a 610 // better error message that has the types of the 611 // arguments that were passed in. 612 throw new IllegalActionException(null, ex, 613 notSupportedMessage("isCloseTo", this, rightArgument)); 614 } 615 } else if (typeInfo == CPO.LOWER) { 616 return rightArgument.isCloseTo(this, epsilon); 617 } else { 618 throw new IllegalActionException(notSupportedIncomparableMessage( 619 "isCloseTo", this, rightArgument)); 620 } 621 } 622 623 /** Test for equality of the values of this Token and the argument 624 * Token. The argument and this token are converted to 625 * equivalent types, and then compared. Generally, this is the 626 * higher of the type of this token and the argument type. This 627 * method defers to the _isEqualTo() method to perform a 628 * type-specific equality check. Derived classes should implement 629 * that method to provide type specific actions for equality 630 * testing. 631 * 632 * @see #isCloseTo 633 * @param rightArgument The token with which to test equality. 634 * @exception IllegalActionException If this method is not 635 * supported by the derived class. 636 * @return A boolean token that contains the value true if the 637 * values and units of this token and the argument token are the same. 638 */ 639 @Override 640 public final BooleanToken isEqualTo(Token rightArgument) 641 throws IllegalActionException { 642 int typeInfo = TypeLattice.compare(getType(), rightArgument); 643 644 if (typeInfo == CPO.SAME || getClass() == rightArgument.getClass()) { 645 return _doIsEqualTo(rightArgument); 646 } else if (typeInfo == CPO.HIGHER) { 647 ScalarToken convertedArgument = (ScalarToken) getType() 648 .convert(rightArgument); 649 650 try { 651 return _doIsEqualTo(convertedArgument); 652 } catch (IllegalActionException ex) { 653 // If the type-specific operation fails, then create a 654 // better error message that has the types of the 655 // arguments that were passed in. 656 throw new IllegalActionException(null, ex, 657 notSupportedMessage("isEqualTo", this, rightArgument)); 658 } 659 } else if (typeInfo == CPO.LOWER) { 660 return rightArgument.isEqualTo(this); 661 } else { 662 throw new IllegalActionException(notSupportedIncomparableMessage( 663 "isEqualTo", this, rightArgument)); 664 } 665 } 666 667 /** Check whether the value of this token is strictly greater than 668 * that of the argument token. The argument and this token are 669 * converted to equivalent types, and then compared. Generally, 670 * this is the higher of the type of this token and the argument 671 * type. This method defers to the _isLessThan() method to perform 672 * a type-specific equality check. Derived classes should 673 * implement that method to provide type specific actions for 674 * equality testing. 675 * 676 * @param rightArgument The token to compare against. 677 * @return A boolean token with value true if this token has the 678 * same units as the argument, and is strictly greater than the 679 * argument. 680 * @exception IllegalActionException If the argument token and 681 * this token are of incomparable types, or have different units, 682 * or the operation does not make sense for the given types. 683 */ 684 public final BooleanToken isGreaterThan(ScalarToken rightArgument) 685 throws IllegalActionException { 686 int typeInfo = TypeLattice.compare(getType(), rightArgument); 687 688 if (typeInfo == CPO.SAME) { 689 return rightArgument._doIsLessThan(this); 690 } else if (typeInfo == CPO.HIGHER) { 691 ScalarToken convertedArgument = (ScalarToken) getType() 692 .convert(rightArgument); 693 694 try { 695 return convertedArgument._doIsLessThan(this); 696 } catch (IllegalActionException ex) { 697 // If the type-specific operation fails, then create a 698 // better error message that has the types of the 699 // arguments that were passed in. 700 throw new IllegalActionException(null, ex, notSupportedMessage( 701 "isGreaterThan", this, rightArgument)); 702 } 703 } else if (typeInfo == CPO.LOWER) { 704 return rightArgument.isLessThan(this); 705 } else { 706 throw new IllegalActionException(notSupportedIncomparableMessage( 707 "isGreaterThan", this, rightArgument)); 708 } 709 } 710 711 /** Check whether the value of this token is strictly less than that of the 712 * argument token. 713 * 714 * @param rightArgument The token to compare against. 715 * @return A boolean token with value true if this token is strictly 716 * less than the argument. 717 * @exception IllegalActionException If the argument token and 718 * this token are of incomparable types, or have different units, 719 * or the operation does not make sense for the given types. 720 */ 721 @Override 722 public final BooleanToken isLessThan(PartiallyOrderedToken rightArgument) 723 throws IllegalActionException { 724 if (!(rightArgument instanceof ScalarToken)) { 725 //// FIXME: Since PartiallyOrderedToken is an interface, we cannot do: 726 //throw new IllegalActionException(null, ex, notSupportedMessage( 727 // "isLessThan", this, rightArgument)) 728 //// and must do this instead: 729 throw new IllegalActionException( 730 "Cannot compare ScalarToken with " + rightArgument); 731 } 732 return isLessThan((ScalarToken) rightArgument); 733 } 734 735 /** Check whether the value of this token is strictly less than that of the 736 * argument token. The argument and this token are converted to 737 * equivalent types, and then compared. Generally, this is the 738 * higher of the type of this token and the argument type. This 739 * method defers to the _isLessThan() method to perform a 740 * type-specific equality check. Derived classes should implement 741 * that method to provide type specific actions for equality 742 * testing. 743 * 744 * @param rightArgument The token to compare against. 745 * @return A boolean token with value true if this token has the 746 * same units as the argument, and is strictly less than the 747 * argument. 748 * @exception IllegalActionException If the argument token and 749 * this token are of incomparable types, or have different units, 750 * or the operation does not make sense for the given types. 751 */ 752 public final BooleanToken isLessThan(ScalarToken rightArgument) 753 throws IllegalActionException { 754 int typeInfo = TypeLattice.compare(getType(), rightArgument); 755 756 if (typeInfo == CPO.SAME) { 757 return _doIsLessThan(rightArgument); 758 } else if (typeInfo == CPO.HIGHER) { 759 ScalarToken convertedArgument = (ScalarToken) getType() 760 .convert(rightArgument); 761 762 try { 763 return _doIsLessThan(convertedArgument); 764 } catch (IllegalActionException ex) { 765 // If the type-specific operation fails, then create a 766 // better error message that has the types of the 767 // arguments that were passed in. 768 throw new IllegalActionException(null, ex, 769 notSupportedMessage("isLessThan", this, rightArgument)); 770 } 771 } else if (typeInfo == CPO.LOWER) { 772 return rightArgument.isGreaterThan(this); 773 } else { 774 throw new IllegalActionException(notSupportedIncomparableMessage( 775 "isLessThan", this, rightArgument)); 776 } 777 } 778 779 /** Returns a token representing the result of shifting the bits 780 * of this token towards the most significant bit, filling the 781 * least significant bits with zeros. 782 * @param bits The number of bits to shift. 783 * @return The left shift. 784 * @exception IllegalActionException If the given token is not 785 * compatible for this operation, or the operation does not make 786 * sense for this type. 787 */ 788 public ScalarToken leftShift(int bits) throws IllegalActionException { 789 throw new IllegalActionException( 790 notSupportedMessage("leftShift", this, new IntToken(bits))); 791 } 792 793 /** Returns a token representing the result of shifting the bits 794 * of this token towards the least significant bit, filling the 795 * most significant bits with zeros. This treats the value as an 796 * unsigned number, which may have the effect of destroying the 797 * sign of the value. 798 * @param bits The number of bits to shift. 799 * @return The right shift. 800 * @exception IllegalActionException If the given token is not 801 * compatible for this operation, or the operation does not make 802 * sense for this type. 803 */ 804 public ScalarToken logicalRightShift(int bits) 805 throws IllegalActionException { 806 throw new IllegalActionException(notSupportedMessage( 807 "logicalRightShift", this, new IntToken(bits))); 808 } 809 810 /** Return the value of this token as a long integer. 811 * In this base class, we just throw an exception. 812 * @return The value of this token as a long. 813 * @exception IllegalActionException Always thrown. 814 */ 815 public long longValue() throws IllegalActionException { 816 throw new IllegalActionException( 817 notSupportedConversionMessage(this, "long")); 818 } 819 820 /** Return a new token whose value is the value of this token 821 * modulo the value of the argument token. Type conversion also 822 * occurs here, so that the operation is performed at the least 823 * type necessary to ensure precision. The returned type is the 824 * same as the type chosen for the operation, which is the higher 825 * of the type of this token and the argument type. Subclasses 826 * should implement the protected _modulo() method to perform the 827 * correct type-specific operation. 828 * @param rightArgument The token to modulo with this token. 829 * @return A new token containing the result. 830 * @exception IllegalActionException If the argument token and 831 * this token are of incomparable types, or have different units, 832 * or the operation does not make sense for the given types. 833 */ 834 @Override 835 public final Token modulo(Token rightArgument) 836 throws IllegalActionException { 837 int typeInfo = TypeLattice.compare(getType(), rightArgument); 838 839 if (typeInfo == CPO.SAME || getClass() == rightArgument.getClass()) { 840 return _doModulo(rightArgument); 841 } else if (typeInfo == CPO.HIGHER) { 842 ScalarToken convertedArgument = (ScalarToken) getType() 843 .convert(rightArgument); 844 845 try { 846 return _doModulo(convertedArgument); 847 } catch (IllegalActionException ex) { 848 // If the type-specific operation fails, then create a 849 // better error message that has the types of the 850 // arguments that were passed in. 851 throw new IllegalActionException(null, ex, 852 notSupportedMessage("modulo", this, rightArgument)); 853 } 854 } else if (typeInfo == CPO.LOWER) { 855 return rightArgument.moduloReverse(this); 856 } else { 857 // Items being moduloed are incomparable. However, modulo 858 // may still be possible because the LUB of the types 859 // might support it. E.g., int mod arrayType(int, 2), 860 // where the LUB is arrayType(int). 861 Type lubType = (Type) TypeLattice.lattice() 862 .leastUpperBound(getType(), rightArgument.getType()); 863 864 // If the LUB is a new type, try it. 865 if (lubType != null && !lubType.equals(getType())) { 866 Token lub = lubType.convert(this); 867 868 // Caution: convert() might return this again, e.g. 869 // if lubType is general. Only proceed if the conversion 870 // returned a new type. 871 if (!lub.getType().equals(getType())) { 872 return lub.modulo(rightArgument); 873 } 874 } 875 876 // LUB does not support it, but it still might be 877 // possible, e.g. with expressions like double modulo {double}. 878 // Only moduloReverse() could support it at this time however. 879 // This will throw an exception if it is not supported. 880 return rightArgument.moduloReverse(this); 881 } 882 } 883 884 /** Return a new token whose value is the value of this token 885 * modulo the value of the argument token. Type conversion also 886 * occurs here, so that the operation is performed at the least 887 * type necessary to ensure precision. The returned type is the 888 * same as the type chosen for the operation, which is the higher 889 * of the type of this token and the argument type. Subclasses 890 * should implement the protected _modulo() method to perform the 891 * correct type-specific operation. 892 * @param leftArgument The token to apply modulo to by the value 893 * of this token. 894 * @return A new token containing the result. 895 * @exception IllegalActionException If the argument token and 896 * this token are of incomparable types, or have different units, 897 * or the operation does not make sense for the given types. 898 */ 899 @Override 900 public final Token moduloReverse(Token leftArgument) 901 throws IllegalActionException { 902 int typeInfo = TypeLattice.compare(leftArgument, getType()); 903 904 // We would normally expect this to be LOWER, since this will almost 905 // always be called by modulo, so put that case first. 906 if (typeInfo == CPO.LOWER) { 907 ScalarToken convertedArgument = (ScalarToken) getType() 908 .convert(leftArgument); 909 910 try { 911 return convertedArgument._doModulo(this); 912 } catch (IllegalActionException ex) { 913 // If the type-specific operation fails, then create a 914 // better error message that has the types of the 915 // arguments that were passed in. 916 throw new IllegalActionException(null, ex, notSupportedMessage( 917 "moduloReverse", this, leftArgument)); 918 } 919 } else if (typeInfo == CPO.SAME) { 920 return ((ScalarToken) leftArgument)._doModulo(this); 921 } else if (typeInfo == CPO.HIGHER) { 922 return leftArgument.modulo(this); 923 } else { 924 throw new IllegalActionException(notSupportedIncomparableMessage( 925 "moduloReverse", this, leftArgument)); 926 } 927 } 928 929 /** Return a new token whose value is the value of this token 930 * multiplied by the value of the argument token. Type 931 * conversion also occurs here, so that the operation is 932 * performed at the least type necessary to ensure precision. 933 * The returned type is the same as the type chosen for the 934 * operation, which is the higher of the type of this token and 935 * the argument type. Subclasses should implement the protected 936 * _multiply() method to perform the correct type-specific 937 * operation. 938 * @param rightArgument The token to multiply this token by. 939 * @return A new token containing the result. 940 * @exception IllegalActionException If the argument token and 941 * this token are of incomparable types, or the operation does 942 * not make sense for the given types. 943 */ 944 @Override 945 public final Token multiply(Token rightArgument) 946 throws IllegalActionException { 947 int typeInfo = TypeLattice.compare(getType(), rightArgument); 948 949 if (typeInfo == CPO.SAME || getClass() == rightArgument.getClass()) { 950 return _doMultiply(rightArgument); 951 } else if (typeInfo == CPO.HIGHER) { 952 ScalarToken convertedArgument = (ScalarToken) getType() 953 .convert(rightArgument); 954 955 try { 956 return _doMultiply(convertedArgument); 957 } catch (IllegalActionException ex) { 958 // If the type-specific operation fails, then create a 959 // better error message that has the types of the 960 // arguments that were passed in. 961 throw new IllegalActionException(null, ex, 962 notSupportedMessage("multiply", this, rightArgument)); 963 } 964 } else if (typeInfo == CPO.LOWER 965 || rightArgument instanceof MatrixToken) { 966 // NOTE: If the right argument is an instance of MatrixToken, 967 // then we try reversing the multiply. 968 return rightArgument.multiplyReverse(this); 969 } else { 970 // Items being multiplied are incomparable. 971 // However, multiplication may still be possible because 972 // the LUB of the types might support it. E.g., [double]*complex, 973 // where the LUB is [complex]. 974 Type lubType = (Type) TypeLattice.lattice() 975 .leastUpperBound(getType(), rightArgument.getType()); 976 977 // If the LUB is a new type, try it. 978 if (lubType != null && !lubType.equals(getType())) { 979 Token lub = lubType.convert(this); 980 981 // Caution: convert() might return this again, e.g. 982 // if lubType is general. Only proceed if the conversion 983 // returned a new type. 984 if (!lub.getType().equals(getType())) { 985 return lub.multiply(rightArgument); 986 } 987 } 988 989 // LUB does not support it, but it still might be 990 // possible, e.g. with expressions like double * {double}. 991 // Only multiplyReverse() could support it at this time however. 992 // This will throw an exception if it is not supported. 993 return rightArgument.multiplyReverse(this); 994 } 995 } 996 997 /** Return a new token whose value is the value of this token 998 * multiplied by the value of the argument token. Type 999 * conversion also occurs here, so that the operation is 1000 * performed at the least type necessary to ensure precision. 1001 * The returned type is the same as the type chosen for the 1002 * operation, which is the higher of the type of this token and 1003 * the argument type. Subclasses should implement the protected 1004 * _multiply() method to perform the correct type-specific 1005 * operation. 1006 * @param leftArgument The token to be multiplied by the value of 1007 * this token. 1008 * @return A new token containing the result. 1009 * @exception IllegalActionException If the argument token and 1010 * this token are of incomparable types, or the operation does 1011 * not make sense for the given types. 1012 */ 1013 @Override 1014 public final Token multiplyReverse(Token leftArgument) 1015 throws IllegalActionException { 1016 int typeInfo = TypeLattice.compare(leftArgument, getType()); 1017 1018 // We would normally expect this to be LOWER, since this will almost 1019 // always be called by multiply, so put that case first. 1020 if (typeInfo == CPO.LOWER) { 1021 ScalarToken convertedArgument = (ScalarToken) getType() 1022 .convert(leftArgument); 1023 1024 try { 1025 return convertedArgument._doMultiply(this); 1026 } catch (IllegalActionException ex) { 1027 // If the type-specific operation fails, then create a 1028 // better error message that has the types of the 1029 // arguments that were passed in. 1030 throw new IllegalActionException(null, ex, notSupportedMessage( 1031 "multiplyReverse", this, leftArgument)); 1032 } 1033 } else if (typeInfo == CPO.SAME) { 1034 return ((ScalarToken) leftArgument)._doMultiply(this); 1035 } else if (typeInfo == CPO.HIGHER 1036 || leftArgument instanceof MatrixToken) { 1037 // NOTE: If the left argument is an instance of MatrixToken, 1038 // then we try reversing the multiply. 1039 return leftArgument.multiply(this); 1040 } else { 1041 // Items being multiplied are incomparable. 1042 // However, multiplication may still be possible because 1043 // the LUB of the types might support it. E.g., [double]*complex, 1044 // where the LUB is [complex]. 1045 Type lubType = (Type) TypeLattice.lattice() 1046 .leastUpperBound(getType(), leftArgument.getType()); 1047 1048 // If the LUB is a new type, try it. 1049 if (!lubType.equals(getType())) { 1050 Token lub = lubType.convert(this); 1051 1052 // Caution: convert() might return this again, e.g. 1053 // if lubType is general. Only proceed if the conversion 1054 // returned a new type. 1055 if (!lub.getType().equals(getType())) { 1056 return lub.multiplyReverse(leftArgument); 1057 } 1058 } 1059 1060 throw new IllegalActionException(notSupportedIncomparableMessage( 1061 "multiplyReverse", leftArgument, this)); 1062 } 1063 } 1064 1065 /** Returns a token representing the result of shifting the bits 1066 * of this token towards the least significant bit, filling the 1067 * most significant bits with the sign of the value. This preserves 1068 * the sign of the result. 1069 * @param bits The number of bits to shift. 1070 * @return The right shift. 1071 * @exception IllegalActionException If the given token is not 1072 * compatible for this operation, or the operation does not make 1073 * sense for this type. 1074 */ 1075 public ScalarToken rightShift(int bits) throws IllegalActionException { 1076 throw new IllegalActionException( 1077 notSupportedMessage("rightShift", this, new IntToken(bits))); 1078 } 1079 1080 /** Set the unit category this token belongs to. This method is 1081 * called from within the units system to create tokens 1082 * representing base units. This method should not be called by 1083 * user code. 1084 * @param index The unit category index. 1085 * @deprecated We need a better way of manufacturing the tokens 1086 * for base units, since this method violates the immutability of 1087 * tokens. 1088 */ 1089 @Deprecated 1090 public void setUnitCategory(int index) { 1091 // FIXME: shouldn't this be protected??? it violates the 1092 // immutability of tokens. 1093 _unitCategoryExponents = UnitUtilities.newUnitArrayInCategory(index); 1094 } 1095 1096 /** Return the value of this token as a short. 1097 * In this base class, we just throw an exception. 1098 * @return A short 1099 * @exception IllegalActionException Always thrown 1100 */ 1101 public short shortValue() throws IllegalActionException { 1102 throw new IllegalActionException( 1103 notSupportedConversionMessage(this, "short")); 1104 } 1105 1106 /** Return a new token whose value is the value of the argument 1107 * token subtracted from the value of this token. Type 1108 * conversion also occurs here, so that the operation is 1109 * performed at the least type necessary to ensure precision. 1110 * The returned type is the same as the type chosen for the 1111 * operation, which is the higher of the type of this token and 1112 * the argument type. Subclasses should implement the protected 1113 * _subtract() method to perform the correct type-specific 1114 * operation. 1115 * @param rightArgument The token to subtract from this token. 1116 * @return A new token containing the result. 1117 * @exception IllegalActionException If the argument token and 1118 * this token are of incomparable types, or have different units, 1119 * or the operation does not make sense for the given types. 1120 */ 1121 @Override 1122 public final Token subtract(Token rightArgument) 1123 throws IllegalActionException { 1124 int typeInfo = TypeLattice.compare(getType(), rightArgument); 1125 1126 if (typeInfo == CPO.SAME || getClass() == rightArgument.getClass()) { 1127 return _doSubtract(rightArgument); 1128 } else if (typeInfo == CPO.HIGHER) { 1129 ScalarToken convertedArgument = (ScalarToken) getType() 1130 .convert(rightArgument); 1131 1132 try { 1133 return _doSubtract(convertedArgument); 1134 } catch (IllegalActionException ex) { 1135 // If the type-specific operation fails, then create a 1136 // better error message that has the types of the 1137 // arguments that were passed in. 1138 throw new IllegalActionException(null, ex, 1139 notSupportedMessage("subtract", this, rightArgument)); 1140 } 1141 } else if (typeInfo == CPO.LOWER 1142 || rightArgument instanceof MatrixToken) { 1143 // NOTE: If the right argument is an instance of MatrixToken, 1144 // then we try reversing the subtract. 1145 return rightArgument.subtractReverse(this); 1146 } else { 1147 // Items being subtracted are incomparable. 1148 // However, addition may still be possible because 1149 // the LUB of the types might support it. E.g., [double]-complex, 1150 // where the LUB is [complex]. 1151 Type lubType = (Type) TypeLattice.lattice() 1152 .leastUpperBound(getType(), rightArgument.getType()); 1153 1154 // If the LUB is a new type, try it. 1155 if (!lubType.equals(getType())) { 1156 Token lub = lubType.convert(this); 1157 1158 // Caution: convert() might return this again, e.g. 1159 // if lubType is general. Only proceed if the conversion 1160 // returned a new type. 1161 if (!lub.getType().equals(getType())) { 1162 return lub.subtract(rightArgument); 1163 } 1164 } 1165 1166 throw new IllegalActionException(notSupportedIncomparableMessage( 1167 "subtract", this, rightArgument)); 1168 } 1169 } 1170 1171 /** Return a new token whose value is the value of the argument 1172 * token subtracted from the value of this token. Type 1173 * conversion also occurs here, so that the operation is 1174 * performed at the least type necessary to ensure precision. 1175 * The returned type is the same as the type chosen for the 1176 * operation, which is the higher of the type of this token and 1177 * the argument type. Subclasses should implement the protected 1178 * _subtract() method to perform the correct type-specific 1179 * operation. 1180 * @param leftArgument The token to subtract this token from. 1181 * @return A new token containing the result. 1182 * @exception IllegalActionException If the argument token and 1183 * this token are of incomparable types, or have different units, 1184 * or the operation does not make sense for the given types. 1185 */ 1186 @Override 1187 public final Token subtractReverse(Token leftArgument) 1188 throws IllegalActionException { 1189 int typeInfo = TypeLattice.compare(leftArgument, getType()); 1190 1191 // We would normally expect this to be LOWER, since this will almost 1192 // always be called by subtract, so put that case first. 1193 if (typeInfo == CPO.LOWER) { 1194 ScalarToken convertedArgument = (ScalarToken) getType() 1195 .convert(leftArgument); 1196 1197 try { 1198 return convertedArgument._doSubtract(this); 1199 } catch (IllegalActionException ex) { 1200 // If the type-specific operation fails, then create a 1201 // better error message that has the types of the 1202 // arguments that were passed in. 1203 throw new IllegalActionException(null, ex, notSupportedMessage( 1204 "subtractReverse", this, leftArgument)); 1205 } 1206 } else if (typeInfo == CPO.SAME) { 1207 return ((ScalarToken) leftArgument)._doSubtract(this); 1208 } else if (typeInfo == CPO.HIGHER) { 1209 return leftArgument.subtract(this); 1210 } else { 1211 throw new IllegalActionException(notSupportedIncomparableMessage( 1212 "subtractReverse", this, leftArgument)); 1213 } 1214 } 1215 1216 /** Return the string representation of the units of this token. 1217 * The general format of the returned string is 1218 * "(l_1 * l_2 * ... * l_m) / (s_1 * s_2 * ... * s_n)". 1219 * For example: "(meter * kilogram) / (second * second)". 1220 * If m or n is 1, then the parenthesis above or below "/" is 1221 * omitted. For example: "meter / second". 1222 * If there is no term above "/", the format becomes 1223 * "1 / (s_1 * s_2 * ... * s_n)". For example: "1 / meter". 1224 * If this token does not have a unit, return an empty string. 1225 * @return A string representation of the units of this token. 1226 */ 1227 public String unitsString() { 1228 return UnitUtilities.unitsString(_unitCategoryExponents); 1229 } 1230 1231 /////////////////////////////////////////////////////////////////// 1232 //// protected methods //// 1233 1234 /** Return a ScalarToken containing the absolute value of the 1235 * value of this token. If this token contains a non-negative 1236 * number, it is returned directly; otherwise, a new token is 1237 * returned. Note that it is explicitly allowable to return this 1238 * token, since the units are the same. Derived classes must implement 1239 * this method in a type-specific fashion. 1240 * @return A ScalarToken, which is likely, but not required to be 1241 * the same type as this token. 1242 */ 1243 protected abstract ScalarToken _absolute(); 1244 1245 /** Return a new token whose value is the value of the argument 1246 * token added to the value of this token. It is guaranteed by 1247 * the caller that the type of the argument is the same as the 1248 * type of this class. This method should be overridden in 1249 * derived classes to provide type-specific operation and return 1250 * a token of the appropriate subclass. 1251 * @param rightArgument The token to add to this token. 1252 * @exception IllegalActionException If this method is not 1253 * supported by the derived class. 1254 * @return A new token containing the result. 1255 */ 1256 protected abstract ScalarToken _add(ScalarToken rightArgument) 1257 throws IllegalActionException; 1258 1259 /** Add the corresponding unit category exponents. 1260 * @param token A token whose exponent will be added with the 1261 * exponents of this token. 1262 * @return An int array containing the addition result, or null 1263 * if the result is unitless. 1264 */ 1265 protected int[] _addCategoryExponents(ScalarToken token) { 1266 return UnitUtilities.addUnitsArray(_unitCategoryExponents, 1267 token._unitCategoryExponents); 1268 } 1269 1270 /** Return true if the units of this token are the same as that of the 1271 * argument token. If both tokens do not have units, return true. 1272 * @param scalarToken A scalar token. 1273 * @return True if the units of this token is the same as that of the 1274 * argument token; false otherwise. 1275 */ 1276 protected boolean _areUnitsEqual(ScalarToken scalarToken) { 1277 return UnitUtilities.areUnitArraysEqual(_unitCategoryExponents, 1278 scalarToken._unitCategoryExponents); 1279 } 1280 1281 /** Returns a token representing the bitwise AND of this token and 1282 * the given token. 1283 * @param rightArgument The ScalarToken to bitwise AND with this one. 1284 * @return The bitwise AND. 1285 * @exception IllegalActionException If the given token is not 1286 * compatible for this operation, or the operation does not make 1287 * sense for this type. 1288 */ 1289 protected abstract ScalarToken _bitwiseAnd(ScalarToken rightArgument) 1290 throws IllegalActionException; 1291 1292 /** Returns a token representing the bitwise NOT of this token. 1293 * @return The bitwise NOT of this token. 1294 * @exception IllegalActionException If the given token is not 1295 * compatible for this operation, or the operation does not make 1296 * sense for this type. 1297 */ 1298 protected abstract ScalarToken _bitwiseNot() throws IllegalActionException; 1299 1300 /** Returns a token representing the bitwise OR of this token and 1301 * the given token. 1302 * @param rightArgument The ScalarToken to bitwise OR with this one. 1303 * @return The bitwise OR. 1304 * @exception IllegalActionException If the given token is not 1305 * compatible for this operation, or the operation does not make 1306 * sense for this type. 1307 */ 1308 protected abstract ScalarToken _bitwiseOr(ScalarToken rightArgument) 1309 throws IllegalActionException; 1310 1311 /** Returns a token representing the bitwise XOR of this token and 1312 * the given token. 1313 * @param rightArgument The ScalarToken to bitwise XOR with this one. 1314 * @return The bitwise XOR. 1315 * @exception IllegalActionException If the given token is not 1316 * compatible for this operation, or the operation does not make 1317 * sense for this type. 1318 */ 1319 protected abstract ScalarToken _bitwiseXor(ScalarToken rightArgument) 1320 throws IllegalActionException; 1321 1322 /** Return a copy of the unit category exponents array. If this 1323 * token does not have a unit, return null; 1324 * @return An int array that is a copy of the unit category 1325 * exponents of this token. 1326 */ 1327 protected int[] _copyOfCategoryExponents() { 1328 return UnitUtilities.copyUnitsArray(_unitCategoryExponents); 1329 } 1330 1331 /** Return a new token whose value is the value of this token 1332 * divided by the value of the argument token. It is guaranteed 1333 * by the caller that the type of the argument is the same as the 1334 * type of this class. This method should be overridden in 1335 * derived classes to provide type-specific operation and return 1336 * a token of the appropriate subclass. 1337 * @param rightArgument The token to divide this token by. 1338 * @exception IllegalActionException If this method is not 1339 * supported by the derived class. 1340 * @return A new Token containing the result. 1341 */ 1342 protected abstract ScalarToken _divide(ScalarToken rightArgument) 1343 throws IllegalActionException; 1344 1345 /** Test whether the value of this token is close to the first argument, 1346 * where "close" means that the distance between them is less than 1347 * or equal to the second argument. This method only makes sense 1348 * for tokens where the distance between them is reasonably 1349 * represented as a double. 1350 * @param rightArgument The token to compare to this token. 1351 * @param epsilon The value that we use to determine whether two 1352 * tokens are close. 1353 * @return A token containing true if the value of the first 1354 * argument is close to the value of this token. 1355 * @exception IllegalActionException If there is a problem processing 1356 * the rightArgument. 1357 */ 1358 protected abstract BooleanToken _isCloseTo(ScalarToken rightArgument, 1359 double epsilon) throws IllegalActionException; 1360 1361 /** Test for equality of the values of this token and the argument. 1362 * This base class delegates to the equals() method. 1363 * @param token The token to compare to this token. 1364 * @return A token containing true if the value element of the first 1365 * argument is equal to the value of this token. 1366 * @exception IllegalActionException Not thrown in this base class. 1367 */ 1368 protected BooleanToken _isEqualTo(ScalarToken token) 1369 throws IllegalActionException { 1370 return BooleanToken.getInstance(equals(token)); 1371 } 1372 1373 /** Test for ordering of the values of this Token and the argument 1374 * Token. It is guaranteed by the caller that the type and 1375 * units of the argument is the same as the type of this class. 1376 * This method should be overridden in derived classes to provide 1377 * type-specific operation and return a token of the appropriate 1378 * subclass. 1379 * @param rightArgument The token to add to this token. 1380 * @exception IllegalActionException If this method is not 1381 * supported by the derived class. 1382 * @return A new Token containing the result. 1383 */ 1384 protected abstract BooleanToken _isLessThan(ScalarToken rightArgument) 1385 throws IllegalActionException; 1386 1387 /** Return true if this token does not have a unit. 1388 * @return True if this token does not have a unit. 1389 */ 1390 protected boolean _isUnitless() { 1391 return UnitUtilities.isUnitless(_unitCategoryExponents); 1392 } 1393 1394 /** Return a new token whose value is the value of this token 1395 * modulo the value of the argument token. It is guaranteed by 1396 * the caller that the type of the argument is the same as the 1397 * type of this class. This method should be overridden in 1398 * derived classes to provide type-specific operation and return 1399 * a token of the appropriate subclass. 1400 * @param rightArgument The token to modulo this token by. 1401 * @exception IllegalActionException If this method is not 1402 * supported by the derived class. 1403 * @return A new Token containing the result. 1404 */ 1405 protected abstract ScalarToken _modulo(ScalarToken rightArgument) 1406 throws IllegalActionException; 1407 1408 /** Return a new token whose value is the value of this token 1409 * multiplied by the value of the argument token. It is 1410 * guaranteed by the caller that the type of the argument is the 1411 * same as the type of this class. This method should be 1412 * overridden in derived classes to provide type-specific 1413 * operation and return a token of the appropriate subclass. 1414 * @param rightArgument The token to multiply this token by. 1415 * @exception IllegalActionException If this method is not 1416 * supported by the derived class. 1417 * @return A new Token containing the result. 1418 */ 1419 protected abstract ScalarToken _multiply(ScalarToken rightArgument) 1420 throws IllegalActionException; 1421 1422 /** Return a new token whose value is the value of the argument 1423 * token subtracted from the value of this token. It is 1424 * guaranteed by the caller that the type of the argument is the 1425 * same as the type of this class. This method should be 1426 * overridden in derived classes to provide type-specific 1427 * operation and return a token of the appropriate subclass. 1428 * @param rightArgument The token to subtract from this token. 1429 * @exception IllegalActionException If this method is not 1430 * supported by the derived class. 1431 * @return A new Token containing the result. 1432 */ 1433 protected abstract ScalarToken _subtract(ScalarToken rightArgument) 1434 throws IllegalActionException; 1435 1436 /** Subtract the corresponding unit category exponents of the 1437 * argument token from that of this token. 1438 * @param token A token whose exponent will be subtracted from 1439 * the exponents of this token. 1440 * @return An array of int containing the result, or null if the 1441 * result is unitless. 1442 */ 1443 protected int[] _subtractCategoryExponents(ScalarToken token) { 1444 return UnitUtilities.subtractUnitsArray(_unitCategoryExponents, 1445 token._unitCategoryExponents); 1446 } 1447 1448 /////////////////////////////////////////////////////////////////// 1449 //// protected variables //// 1450 1451 /** The unit category exponents. 1452 * The unit system contains a set of base unit categories and derived 1453 * categories. The base categories are customizable by the user. 1454 * For example, the user may choose to use the SI unit system which 1455 * has 7 base categories: length, mass, time, electric current, 1456 * thermodynamic temperature, amount of substance, and luminous 1457 * intensity. The customization is done by defining a MoML file to specify 1458 * the categories and the units in each category. Each category has an 1459 * index, assigned by the order the category appears in the MoML file. 1460 * Derived units are recorded by the exponents of the category. For 1461 * example, the category speed, which is length/time, is stored by an 1462 * exponent of 1 for the length category, and an exponent of -1 for the 1463 * time category. 1464 * This array records the exponents of the base categories. 1465 */ 1466 protected int[] _unitCategoryExponents = null; 1467 1468 /////////////////////////////////////////////////////////////////// 1469 //// private methods //// 1470 1471 /** Return a new token whose value is the value of the argument 1472 * Token added to the value of this Token. It is guaranteed by 1473 * the caller that the type of the argument is the same as the 1474 * type of this class and has the same units as this token. The 1475 * resulting token will also have the same type and units. This 1476 * method defers to the _add() method that takes a ScalarToken. 1477 * Derived classes should implement that method instead to 1478 * provide type-specific operation. 1479 * @param rightArgument The token to add to this token. 1480 * @return A new Token containing the result. 1481 * If either this token or the argument token is a nil token, then 1482 * then {@link ptolemy.data.Token#NIL} is returned. 1483 * @exception IllegalActionException If this operation is not 1484 * supported by the derived class. 1485 */ 1486 private Token _doAdd(Token rightArgument) throws IllegalActionException { 1487 if (isNil() || rightArgument.isNil()) { 1488 return getType().convert(Token.NIL); 1489 } 1490 1491 ScalarToken convertedArgument = (ScalarToken) rightArgument; 1492 if (!_areUnitsEqual(convertedArgument)) { 1493 throw new IllegalActionException( 1494 notSupportedMessage("add", this, rightArgument) 1495 + " because the units are not the same."); 1496 } 1497 1498 ScalarToken result = _add(convertedArgument); 1499 if (_unitCategoryExponents != null && !_isUnitless()) { 1500 result._unitCategoryExponents = _copyOfCategoryExponents(); 1501 } 1502 return result; 1503 } 1504 1505 /* Return a new token whose value is the value of the argument 1506 * Token bitwise ANDed to the value of this Token. It is guaranteed 1507 * by the caller that the type of the argument is the same as the 1508 * type of this class. The resulting token will also have the same 1509 * type. This method checks that the two tokens have the same units 1510 * and throws an exception if the units are not the same. The resulting 1511 * token will have the same units as the operands. This method defers 1512 * to the _bitwiseAnd() method that takes a ScalarToken. 1513 * @param rightArgument The token to bitwise AND to this token. 1514 * @return A new Token containing the result. 1515 * If either this token or the argument token is a nil token, then 1516 * then {@link ptolemy.data.Token#NIL} is returned. 1517 * @exception IllegalActionException If this operation is not 1518 * supported by the derived class. 1519 */ 1520 private BitwiseOperationToken _doBitwiseAnd(Token rightArgument) 1521 throws IllegalActionException { 1522 if (isNil() || rightArgument.isNil()) { 1523 return (BitwiseOperationToken) getType().convert(Token.NIL); 1524 } 1525 ScalarToken convertedArgument = (ScalarToken) rightArgument; 1526 1527 if (!_areUnitsEqual(convertedArgument)) { 1528 throw new IllegalActionException( 1529 notSupportedMessage("bitwiseAnd", this, rightArgument) 1530 + " because the units of this token: " 1531 + unitsString() 1532 + " are not the same as those of the argument: " 1533 + convertedArgument.unitsString()); 1534 } 1535 1536 ScalarToken result = _bitwiseAnd(convertedArgument); 1537 if (_unitCategoryExponents != null && !_isUnitless()) { 1538 result._unitCategoryExponents = _copyOfCategoryExponents(); 1539 } 1540 return result; 1541 } 1542 1543 /* Return a new token whose value is the value of the argument 1544 * Token bitwise ORed to the value of this Token. It is guaranteed 1545 * by the caller that the type of the argument is the same as the 1546 * type of this class. The resulting token will also have the same 1547 * type. This method checks that the two tokens have the same units 1548 * and throws an exception if the units are not the same. The resulting 1549 * token will have the same units as the operands. This method defers 1550 * to the _bitwiseOr() method that takes a ScalarToken. 1551 * @param rightArgument The token to bitwise OR to this token. 1552 * @return A new Token containing the result. 1553 * If either this token or the argument token is a nil token, then 1554 * then {@link ptolemy.data.Token#NIL} is returned. 1555 * @exception IllegalActionException If this operation is not 1556 * supported by the derived class. 1557 */ 1558 private BitwiseOperationToken _doBitwiseOr(Token rightArgument) 1559 throws IllegalActionException { 1560 if (isNil() || rightArgument.isNil()) { 1561 return (BitwiseOperationToken) getType().convert(Token.NIL); 1562 } 1563 1564 ScalarToken convertedArgument = (ScalarToken) rightArgument; 1565 1566 if (!_areUnitsEqual(convertedArgument)) { 1567 throw new IllegalActionException( 1568 notSupportedMessage("bitwiseOr", this, rightArgument) 1569 + " because the units of this token: " 1570 + unitsString() 1571 + " are not the same as those of the argument: " 1572 + convertedArgument.unitsString()); 1573 } 1574 1575 ScalarToken result = _bitwiseOr(convertedArgument); 1576 if (_unitCategoryExponents != null && !_isUnitless()) { 1577 result._unitCategoryExponents = _copyOfCategoryExponents(); 1578 } 1579 return result; 1580 } 1581 1582 /* Return a new token whose value is the value of the argument 1583 * Token bitwise XORed to the value of this Token. It is guaranteed 1584 * by the caller that the type of the argument is the same as the 1585 * type of this class. The resulting token will also have the same 1586 * type. This method checks that the two tokens have the same units 1587 * and throws an exception if the units are not the same. The resulting 1588 * token will have the same units as the operands. This method defers 1589 * to the _bitwiseXOR() method that takes a ScalarToken. 1590 * @param rightArgument The token to bitwise XOR to this token. 1591 * @return A new Token containing the result. 1592 * If either this token or the argument token is a nil token, then 1593 * then {@link ptolemy.data.Token#NIL} is returned. 1594 * @exception IllegalActionException If this operation is not 1595 * supported by the derived class. 1596 */ 1597 private BitwiseOperationToken _doBitwiseXor(Token rightArgument) 1598 throws IllegalActionException { 1599 if (isNil() || rightArgument.isNil()) { 1600 return (BitwiseOperationToken) getType().convert(Token.NIL); 1601 } 1602 1603 ScalarToken convertedArgument = (ScalarToken) rightArgument; 1604 1605 if (!_areUnitsEqual(convertedArgument)) { 1606 throw new IllegalActionException( 1607 notSupportedMessage("bitwiseXor", this, rightArgument) 1608 + " because the units of this token: " 1609 + unitsString() 1610 + " are not the same as those of the argument: " 1611 + convertedArgument.unitsString()); 1612 } 1613 1614 ScalarToken result = _bitwiseXor(convertedArgument); 1615 if (_unitCategoryExponents != null && !_isUnitless()) { 1616 result._unitCategoryExponents = _copyOfCategoryExponents(); 1617 } 1618 return result; 1619 } 1620 1621 /** Return a new token whose value is the value of this token 1622 * divided by the value of the argument token. It is guaranteed 1623 * by the caller that the type of the argument is the same as the 1624 * type of this class. The resulting token will also have the 1625 * same type and appropriate units. This method defers to the 1626 * _divide method that takes a ScalarToken. Derived classes 1627 * should implement that method instead to provide type-specific 1628 * operation. 1629 * @param rightArgument The token to divide this token by. 1630 * @return A new Token containing the result. 1631 * If either this token or the argument token is a nil token, then 1632 * then {@link ptolemy.data.Token#NIL} is returned. 1633 * @exception IllegalActionException If this operation is not 1634 * supported by the derived class. 1635 */ 1636 private Token _doDivide(Token rightArgument) throws IllegalActionException { 1637 if (isNil() || rightArgument.isNil()) { 1638 return getType().convert(Token.NIL); 1639 } 1640 1641 ScalarToken convertedArgument = (ScalarToken) rightArgument; 1642 1643 ScalarToken result = _divide(convertedArgument); 1644 1645 // compute units 1646 if (_unitCategoryExponents != null && !_isUnitless() 1647 || convertedArgument._unitCategoryExponents != null 1648 && !convertedArgument._isUnitless()) { 1649 result._unitCategoryExponents = _subtractCategoryExponents( 1650 convertedArgument); 1651 } 1652 return result; 1653 } 1654 1655 /** Test for closeness of the values of this Token and the 1656 * argument Token. It is guaranteed by the caller that the type 1657 * and units of the argument is the same as the type of this 1658 * class. This method may defer to the _isCloseTo() method that 1659 * takes a ScalarToken. Derived classes should implement that 1660 * method instead to provide type-specific operation. 1661 * @param rightArgument The token with which to test closeness. 1662 * @return A BooleanToken which contains the result of the test. 1663 * If either this token or the argument token is a nil token, then 1664 * a BooleanToken that contains the value false is returned. 1665 * @exception IllegalActionException If the units of the argument 1666 * are not the same as the units of this token, or the method is 1667 * not supported by the derived class. 1668 */ 1669 private BooleanToken _doIsCloseTo(Token rightArgument, double epsilon) 1670 throws IllegalActionException { 1671 if (isNil() || rightArgument.isNil()) { 1672 return BooleanToken.FALSE; 1673 } 1674 1675 ScalarToken convertedArgument = (ScalarToken) rightArgument; 1676 1677 if (!_areUnitsEqual(convertedArgument)) { 1678 throw new IllegalActionException( 1679 notSupportedMessage("isCloseTo", this, rightArgument) 1680 + " because the units are not the same."); 1681 } 1682 1683 return _isCloseTo(convertedArgument, epsilon); 1684 } 1685 1686 /** Test for equality of the values of this Token and the argument 1687 * Token. It is guaranteed by the caller that the type of the 1688 * argument is the same as the type of this class. This method 1689 * returns BooleanToken.FALSE if the units of this token and the 1690 * given token are not identical. This method may defer to the 1691 * _isEqualTo() method that takes a ScalarToken. Derived classes 1692 * should implement that method instead to provide type-specific 1693 * operation. 1694 * @param rightArgument The token with which to test equality. 1695 * @return A BooleanToken which contains the result of the test. 1696 * If either this token or the argument token is a nil token, then 1697 * a BooleanToken that contains the value false is returned. 1698 * @exception IllegalActionException If this method is not 1699 * supported by the derived class. 1700 */ 1701 private BooleanToken _doIsEqualTo(Token rightArgument) 1702 throws IllegalActionException { 1703 if (isNil() || rightArgument.isNil()) { 1704 return BooleanToken.FALSE; 1705 } 1706 1707 ScalarToken convertedArgument = (ScalarToken) rightArgument; 1708 1709 if (!_areUnitsEqual(convertedArgument)) { 1710 return BooleanToken.FALSE; 1711 } 1712 1713 return _isEqualTo(convertedArgument); 1714 } 1715 1716 /** Test for ordering of the values of this Token and the argument 1717 * Token. It is guaranteed by the caller that the type and 1718 * units of the argument is the same as the type of this class. 1719 * This method may defer to the _isLessThan() method that takes a 1720 * ScalarToken. Derived classes should implement that method 1721 * instead to provide type-specific operation. 1722 * @param rightArgument The token with which to test ordering. 1723 * @return A BooleanToken which contains the result of the test. 1724 * @exception IllegalActionException If the units of the argument 1725 * are not the same as the units of this token, or the method is 1726 * not supported by the derived class or if either this token or 1727 * the argument token is a nil token. 1728 */ 1729 private BooleanToken _doIsLessThan(Token rightArgument) 1730 throws IllegalActionException { 1731 if (isNil() || rightArgument.isNil()) { 1732 throw new IllegalActionException( 1733 notSupportedMessage("isLessThan", this, rightArgument) 1734 + " because one or the other is nil"); 1735 } 1736 1737 ScalarToken convertedArgument = (ScalarToken) rightArgument; 1738 1739 if (!_areUnitsEqual(convertedArgument)) { 1740 throw new IllegalActionException( 1741 notSupportedMessage("isLessThan", this, rightArgument) 1742 + " because the units are not the same."); 1743 } 1744 1745 return _isLessThan(convertedArgument); 1746 } 1747 1748 /** Return a new token whose value is the value of this token 1749 * modulo the value of the argument token. It is guaranteed by 1750 * the caller that the type of the argument is the same as the 1751 * type of this class and has the same units as this token. The 1752 * resulting token will also have the same type and units. This 1753 * method defers to the _modulo() method that takes a 1754 * ScalarToken. Derived classes should implement that method 1755 * instead to provide type-specific operation. 1756 * @param rightArgument The token to modulo this token by. 1757 * @return A new Token containing the result. 1758 * If either this token or the argument token is a nil token, then 1759 * then {@link ptolemy.data.Token#NIL} is returned. 1760 * @exception IllegalActionException If the units are not 1761 * compatible, or this operation is not supported by the derived 1762 * class. 1763 */ 1764 private Token _doModulo(Token rightArgument) throws IllegalActionException { 1765 if (isNil() || rightArgument.isNil()) { 1766 return getType().convert(Token.NIL); 1767 } 1768 ScalarToken convertedArgument = (ScalarToken) rightArgument; 1769 1770 if (!_areUnitsEqual(convertedArgument)) { 1771 throw new IllegalActionException( 1772 notSupportedMessage("modulo", this, rightArgument) 1773 + " because the units are not the same."); 1774 } 1775 1776 ScalarToken result = _modulo(convertedArgument); 1777 if (_unitCategoryExponents != null && !_isUnitless()) { 1778 result._unitCategoryExponents = _copyOfCategoryExponents(); 1779 } 1780 return result; 1781 } 1782 1783 /** Return a new token whose value is the value of this token 1784 * multiplied by the value of the argument token. It is 1785 * guaranteed by the caller that the type of the argument is the 1786 * same as the type of this class. The resulting token will also 1787 * have the same type and appropriate units. This method defers 1788 * to the _multiply() method that takes a ScalarToken. Derived 1789 * classes should implement that method instead to provide 1790 * type-specific operation. 1791 * @param rightArgument The token to multiply this token by. 1792 * @return A new Token containing the result. 1793 * If either this token or the argument token is a nil token, then 1794 * then {@link ptolemy.data.Token#NIL} is returned. 1795 * @exception IllegalActionException If this operation is not 1796 * supported by the derived class. 1797 */ 1798 private Token _doMultiply(Token rightArgument) 1799 throws IllegalActionException { 1800 if (isNil() || rightArgument.isNil()) { 1801 return getType().convert(Token.NIL); 1802 } 1803 1804 ScalarToken convertedArgument = (ScalarToken) rightArgument; 1805 ScalarToken result = _multiply(convertedArgument); 1806 1807 // compute units 1808 if (_unitCategoryExponents != null && !_isUnitless() 1809 || convertedArgument._unitCategoryExponents != null 1810 && !convertedArgument._isUnitless()) { 1811 result._unitCategoryExponents = _addCategoryExponents( 1812 convertedArgument); 1813 1814 } 1815 return result; 1816 } 1817 1818 /** Return a new token whose value is the value of the argument 1819 * token subtracted from the value of this token. It is 1820 * guaranteed by the caller that the type of the argument is the 1821 * same as the type of this class and has the same units as this 1822 * token. The resulting token will also have the same type and 1823 * units. This method defers to the _subtract method that takes 1824 * a ScalarToken. Derived classes should implement that method 1825 * instead to provide type-specific operation. 1826 * @param rightArgument The token to subtract from this token. 1827 * @return A new Token containing the result. 1828 * If either this token or the argument token is a nil token, then 1829 * then {@link ptolemy.data.Token#NIL} is returned. 1830 * @exception IllegalActionException If the units are not 1831 * compatible, or this operation is not supported by the derived 1832 * class. 1833 */ 1834 private Token _doSubtract(Token rightArgument) 1835 throws IllegalActionException { 1836 if (isNil() || rightArgument.isNil()) { 1837 return getType().convert(Token.NIL); 1838 } 1839 ScalarToken convertedArgument = (ScalarToken) rightArgument; 1840 1841 if (!_areUnitsEqual(convertedArgument)) { 1842 throw new IllegalActionException( 1843 notSupportedMessage("subtract", this, rightArgument) 1844 + " because the units are not the same."); 1845 } 1846 1847 ScalarToken result = _subtract(convertedArgument); 1848 1849 if (_unitCategoryExponents != null && !_isUnitless()) { 1850 result._unitCategoryExponents = _copyOfCategoryExponents(); 1851 } 1852 return result; 1853 } 1854}