001/* A token that contains a short (16 bit integer)
002
003 Copyright (c) 2007-2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027
028 */
029package ptolemy.data;
030
031import ptolemy.data.type.BaseType;
032import ptolemy.data.type.Type;
033import ptolemy.data.type.TypeLattice;
034import ptolemy.data.unit.UnitUtilities;
035import ptolemy.graph.CPO;
036import ptolemy.kernel.util.IllegalActionException;
037import ptolemy.math.Complex;
038import ptolemy.math.FixPoint;
039
040///////////////////////////////////////////////////////////////////
041//// ShortToken
042
043/**
044 A token that contains a signed 16-bit integer number.  Generally, this
045 class handles overflow the same way that overflow Java native types
046 are handled. In other words, overflow just past java.lang.Short.MAX_VALUE
047 results in negative values close to java.lang.Short.MIN_VALUE.
048
049 @author Isaac Liu, based on IntToken by Neil Smyth, Yuhong Xiong, Steve Neuendorffer, contributor: Christopher Brooks
050 @version $Id$
051 @since Ptolemy II 6.1
052 @Pt.ProposedRating Red (iliu)
053 @Pt.AcceptedRating Red (iliu)
054 */
055public class ShortToken extends ScalarToken {
056    /** Construct a token with short 0.
057     */
058    public ShortToken() {
059        _value = 0;
060    }
061
062    /** Construct a token with the specified value.
063     *  @param value The specified value.
064     */
065    public ShortToken(final short value) {
066        _value = value;
067    }
068
069    /** Construct a ShortToken with the specified integer value.
070     *  This method's cast to (byte) keeps only the low
071     *  order 16 bits of the integer.
072     *  @param value The specified value.
073     */
074    public ShortToken(int value) {
075        _value = (short) value;
076    }
077
078    /** Construct an ShortToken from the specified string.
079     *  @param init The specified string.
080     *  @exception IllegalActionException If the token could not
081     *  be created with the given String.
082     */
083    public ShortToken(String init) throws IllegalActionException {
084        if (init == null || init.equals("nil")) {
085            throw new IllegalActionException(
086                    notSupportedNullNilStringMessage("ShortToken", init));
087        }
088        try {
089            _value = Short.parseShort(init);
090        } catch (NumberFormatException e) {
091            throw new IllegalActionException(null, e,
092                    "Failed to parse \"" + init + "\" as a number.");
093        }
094    }
095
096    ///////////////////////////////////////////////////////////////////
097    ////                         public methods                    ////
098
099    /** Return the value of this token as a Complex. The real part
100     *  of the Complex is the value of this token, the imaginary part
101     *  is set to 0.
102     *  @return A Complex.
103     */
104    @Override
105    public Complex complexValue() {
106        return new Complex(_value);
107    }
108
109    /** Convert the specified token into an instance of ShortToken.
110     *  This method does lossless conversion.  The units of the
111     *  returned token will be the same as the units of the given
112     *  token.  If the argument is already an instance of ShortToken, it
113     *  is returned without any change.  If the argument is a
114     *  nil token, then {@link #NIL} is returned.
115     *  Otherwise, if the argument is below ShortToken in the type
116     *  hierarchy, it is converted to an instance of ShortToken or one
117     *  of the subclasses of ShortToken and returned. If none of the
118     *  above condition is met, an exception is thrown.
119     *
120     *  @param token The token to be converted to a ShortToken.
121     *  @return A ShortToken.
122     *  @exception IllegalActionException If the conversion
123     *   cannot be carried out.
124     */
125    public static ShortToken convert(Token token)
126            throws IllegalActionException {
127        if (token instanceof ShortToken) {
128            return (ShortToken) token;
129        }
130        if (token.isNil()) {
131            return ShortToken.NIL;
132        }
133
134        int compare = TypeLattice.compare(BaseType.SHORT, token);
135
136        if (compare == CPO.LOWER || compare == CPO.INCOMPARABLE) {
137            throw new IllegalActionException(
138                    notSupportedIncomparableConversionMessage(token, "short"));
139        }
140
141        compare = TypeLattice.compare(BaseType.UNSIGNED_BYTE, token);
142
143        if (compare == CPO.SAME || compare == CPO.HIGHER) {
144            UnsignedByteToken unsignedByteToken = UnsignedByteToken
145                    .convert(token);
146            ShortToken result = new ShortToken(unsignedByteToken.shortValue());
147            if (unsignedByteToken._unitCategoryExponents != null
148                    && !UnitUtilities.isUnitless(
149                            unsignedByteToken._unitCategoryExponents)) {
150                result._unitCategoryExponents = unsignedByteToken
151                        ._copyOfCategoryExponents();
152            }
153            return result;
154        }
155
156        // The argument is below UnsignedByteToken in the type hierarchy,
157        // but I don't recognize it.
158        throw new IllegalActionException(
159                notSupportedConversionMessage(token, "short"));
160    }
161
162    /** Return the value in the token as a double.
163     *  @return The value contained in this token as a double.
164     */
165    @Override
166    public double doubleValue() {
167        return _value;
168    }
169
170    /** Return true if the argument's class is ShortToken and it has the
171     *  same values as this token.
172     *  @param object An instance of Object.
173     *  @return True if the argument is an ShortToken with the same
174     *  value. If either this object or the argument is a nil Token, return
175     *  false.
176     */
177    @Override
178    public boolean equals(Object object) {
179        if (object == null) {
180            return false;
181        }
182        // This test rules out subclasses.
183        if (object.getClass() != getClass()) {
184            return false;
185        }
186
187        if (this.isNil() || ((ShortToken) object).isNil()) {
188            return false;
189        }
190
191        if (((ShortToken) object).shortValue() == _value) {
192            return true;
193        }
194
195        return false;
196    }
197
198    /** Return the value in the token as a fixpoint.
199     *  @return The value contained in this token as a fixpoint.
200     */
201    @Override
202    public FixPoint fixValue() {
203        // FIXME: Does FixPoint need to specially handle Short?
204        return new FixPoint(_value);
205    }
206
207    /** Return the value in the token as a float.
208     *  @return The value contained in this token as a float.
209     */
210    @Override
211    public float floatValue() {
212        return _value;
213    }
214
215    /** Return the type of this token.
216     *  @return BaseType.SHORT
217     */
218    @Override
219    public Type getType() {
220        return BaseType.SHORT;
221    }
222
223    /** Return a hash code value for this token. This method just returns the
224     *  contained short casted to integer.
225     *  @return A hash code value for this token.
226     */
227    @Override
228    public int hashCode() {
229        return _value;
230    }
231
232    /** Return the value in the token as an int.
233     *  @return The int value contained in this token.
234     */
235    @Override
236    public int intValue() {
237        return _value;
238    }
239
240    /** Return true if the token is nil, (aka null or missing).
241     *  Nil or missing tokens occur when a data source is sparsely populated.
242     *  @return True if the token is the {@link #NIL} token.
243     */
244    @Override
245    public boolean isNil() {
246        // We use a method here so that we can easily change how
247        // we determine if a token is nil without modify lots of classes.
248        // Can't use equals() here, or we'll go into an infinite loop.
249        return this == ShortToken.NIL;
250    }
251
252    /** Returns a token representing the result of shifting the bits
253     *  of this token towards the most significant bit, filling the
254     *  least significant bits with zeros.
255     *  @param bits The number of bits to shift.
256     *  @return The left shift.
257     *  If this token is nil, then {@link #NIL} is returned.
258     */
259    @Override
260    public ScalarToken leftShift(int bits) {
261        if (isNil()) {
262            return ShortToken.NIL;
263        }
264        return new ShortToken(_value << bits);
265    }
266
267    /** Returns a token representing the result of shifting the bits
268     *  of this token towards the least significant bit, filling the
269     *  most significant bits with zeros.  This treats the value as an
270     *  unsigned number, which may have the effect of destroying the
271     *  sign of the value.
272     *  @param bits The number of bits to shift.
273     *  @return The logical right shift.
274     *  If this token is nil, then {@link #NIL} is returned.
275     */
276    @Override
277    public ScalarToken logicalRightShift(int bits) {
278        if (isNil()) {
279            return ShortToken.NIL;
280        }
281        short returnValue = (short) (_value >>> bits);
282        returnValue = (short) (returnValue & 0x7FFF);
283        return new ShortToken(returnValue);
284    }
285
286    /** Return the value in the token as a long.
287     *  @return The short value contained in this token as a long.
288     */
289    @Override
290    public long longValue() {
291        return _value;
292    }
293
294    /** Returns an ShortToken with value 1.
295     *  @return An ShortToken with value 1.
296     */
297    @Override
298    public Token one() {
299        return ONE;
300    }
301
302    /** Returns a token representing the result of shifting the bits
303     *  of this token towards the least significant bit, filling the
304     *  most significant bits with the sign of the value.  This preserves
305     *  the sign of the result.
306     *  @param bits The number of bits to shift.
307     *  @return The right shift.
308     *  If this token is nil, then {@link #NIL} is returned.
309     */
310    @Override
311    public ScalarToken rightShift(int bits) {
312        if (isNil()) {
313            return ShortToken.NIL;
314        }
315        return new ShortToken(_value >> bits);
316    }
317
318    /** Return the value in the token as a short.
319     *  @return The value contained in this token as a short.
320     */
321    @Override
322    public short shortValue() {
323        return _value;
324    }
325
326    /** Return the value of this token as a string that can be parsed
327     *  by the expression language to recover a token with the same value.
328     *  If this token has a unit, the return string also includes a unit
329     *  string produced by the unitsString() method in the super class.
330     *  @return A String representing the int value and the units (if
331     *   any) of this token.
332     *  @see ptolemy.data.ScalarToken#unitsString
333     */
334    @Override
335    public String toString() {
336        String unitString = "";
337
338        if (!_isUnitless()) {
339            unitString = " * " + unitsString();
340        }
341
342        if (isNil()) {
343            // FIXME: what about units?
344            return super.toString();
345        }
346        return Short.toString(_value) + "s" + unitString;
347    }
348
349    /** Returns an ShortToken with value 0.
350     *  @return An ShortToken with value 0.
351     */
352    @Override
353    public Token zero() {
354        return ZERO;
355    }
356
357    ///////////////////////////////////////////////////////////////////
358    ////                         public variables                  ////
359
360    /** A token that represents a missing value.
361     *  Null or missing tokens are common in analytical systems
362     *  like R and SAS where they are used to handle sparsely populated data
363     *  sources.  In database parlance, missing tokens are sometimes called
364     *  null tokens.  Since null is a Java keyword, we use the term "nil".
365     *  The toString() method on a nil token returns the string "nil".
366     */
367    public static final ShortToken NIL = new ShortToken(Short.MAX_VALUE);
368
369    /** A ShortToken with the value 1.0. */
370    public static final ShortToken ONE = new ShortToken(1);
371
372    /** A ShortToken with the value 0.0. */
373    public static final ShortToken ZERO = new ShortToken(0);
374
375    ///////////////////////////////////////////////////////////////////
376    ////                         protected methods                 ////
377
378    /** Return a ScalarToken containing the absolute value of the
379     *  value of this token. If this token contains a non-negative
380     *  number, it is returned directly; otherwise, a new token is
381     *  returned.  Note that it is explicitly allowable to return this
382     *  token, since the units are the same.
383     *  @return An ShortToken.
384     */
385    @Override
386    protected ScalarToken _absolute() {
387        ShortToken result;
388
389        if (_value >= 0) {
390            result = this;
391        } else {
392            result = new ShortToken(-_value);
393        }
394
395        return result;
396    }
397
398    /** Return a new token whose value is the value of the
399     *  argument Token added to the value of this Token.  It is assumed
400     *  that the type of the argument is an ShortToken.
401     *  @param rightArgument The token to add to this token.
402     *  @return A new ShortToken containing the result.
403     */
404    @Override
405    protected ScalarToken _add(ScalarToken rightArgument) {
406        short sum = (short) (_value
407                + ((ShortToken) rightArgument).shortValue());
408        return new ShortToken(sum);
409    }
410
411    /** Returns a token representing the bitwise AND of this token and
412     *  the given token.  It is assumed that the type of the argument
413     *  is an ShortToken.
414     *  @param rightArgument The ShortToken to bitwise AND with this one.
415     *  @return The bitwise AND.
416     */
417    @Override
418    protected ScalarToken _bitwiseAnd(ScalarToken rightArgument) {
419        short sum = (short) (_value
420                & ((ShortToken) rightArgument).shortValue());
421        return new ShortToken(sum);
422    }
423
424    /** Returns a token representing the bitwise NOT of this token.
425     *  @return The bitwise NOT of this token.
426     */
427    @Override
428    protected ScalarToken _bitwiseNot() {
429        ShortToken result = new ShortToken(~_value);
430        return result;
431    }
432
433    /** Returns a token representing the bitwise OR of this token and
434     *  the given token.  It is assumed that
435     *  the type of the argument is an ShortToken.
436     *  @param rightArgument The ShortToken to bitwise OR with this one.
437     *  @return The bitwise OR.
438     */
439    @Override
440    protected ScalarToken _bitwiseOr(ScalarToken rightArgument) {
441        short sum = (short) (_value
442                | ((ShortToken) rightArgument).shortValue());
443        return new ShortToken(sum);
444    }
445
446    /** Returns a token representing the bitwise XOR of this token and
447     *  the given token.  It is assumed that
448     *  the type of the argument is an ShortToken.
449     *  @param rightArgument The ShortToken to bitwise XOR with this one.
450     *  @return The bitwise XOR.
451     */
452    @Override
453    protected ScalarToken _bitwiseXor(ScalarToken rightArgument) {
454        short sum = (short) (_value
455                ^ ((ShortToken) rightArgument).shortValue());
456        return new ShortToken(sum);
457    }
458
459    /** Return a new token whose value is the value of this token
460     *  divided by the value of the argument token. It is assumed that
461     *  the type of the argument is an ShortToken.
462     *  @param rightArgument The token to divide this token by.
463     *  @return A new ShortToken containing the result.
464     */
465    @Override
466    protected ScalarToken _divide(ScalarToken rightArgument) {
467        short quotient = (short) (_value
468                / ((ShortToken) rightArgument).shortValue());
469        return new ShortToken(quotient);
470    }
471
472    /** Test whether the value of this token is close to the first
473     *  argument, where "close" means that the distance between their
474     *  values is less than or equal to the second argument. It is
475     *  assumed that the type of the first argument is ShortToken.
476     *  @param rightArgument The token to compare to this token.
477     *  @param epsilon The distance.
478     *  @return A token containing true if the value of the first
479     *   argument is close to the value of this token.
480     */
481    @Override
482    protected BooleanToken _isCloseTo(ScalarToken rightArgument,
483            double epsilon) {
484        // NOTE: This code is duplicated in
485        // ptolemy.math.IntegerMatrixMath.within(); if this
486        // implementation changes, also change the corresponding
487        // implementation there.
488        double right = ((ShortToken) rightArgument).doubleValue();
489        double left = doubleValue();
490
491        if (right > left + epsilon || right < left - epsilon) {
492            return BooleanToken.FALSE;
493        } else {
494            return BooleanToken.TRUE;
495        }
496    }
497
498    /** Test for ordering of the values of this Token and the argument
499     *  Token.  It is assumed that the type of the argument is ShortToken.
500     *  @param rightArgument The token to add to this token.
501     *  @exception IllegalActionException If this method is not
502     *  supported by the derived class.
503     *  @return A new Token containing the result.
504     */
505    @Override
506    protected BooleanToken _isLessThan(ScalarToken rightArgument)
507            throws IllegalActionException {
508        ShortToken convertedArgument = (ShortToken) rightArgument;
509        return BooleanToken
510                .getInstance(_value < convertedArgument.shortValue());
511    }
512
513    /** Return a new token whose value is the value of this token
514     *  modulo the value of the argument token.  It is assumed that
515     *  the type of the argument is an ShortToken.
516     *  @param rightArgument The token to modulo this token by.
517     *  @return A new ShortToken containing the result.
518     */
519    @Override
520    protected ScalarToken _modulo(ScalarToken rightArgument) {
521        short remainder = (short) (_value
522                % ((ShortToken) rightArgument).shortValue());
523        return new ShortToken(remainder);
524    }
525
526    /** Return a new token whose value is the value of this token
527     *  multiplied by the value of the argument token.  It is assumed that
528     *  the type of the argument is an ShortToken.
529     *  @param rightArgument The token to multiply this token by.
530     *  @return A new ShortToken containing the result.
531     */
532    @Override
533    protected ScalarToken _multiply(ScalarToken rightArgument) {
534        short product = (short) (_value
535                * ((ShortToken) rightArgument).shortValue());
536        return new ShortToken(product);
537    }
538
539    /** Return a new token whose value is the value of the argument token
540     *  subtracted from the value of this token.  It is assumed that
541     *  the type of the argument is an ShortToken.
542     *  @param rightArgument The token to subtract from this token.
543     *  @return A new ShortToken containing the result.
544     */
545    @Override
546    protected ScalarToken _subtract(ScalarToken rightArgument) {
547        short difference = (short) (_value
548                - ((ShortToken) rightArgument).shortValue());
549        return new ShortToken(difference);
550    }
551
552    ///////////////////////////////////////////////////////////////////
553    ////                         private variables                 ////
554    private final short _value;
555}