KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > value > BigIntegerValue


1 package net.sf.saxon.value;
2 import net.sf.saxon.expr.Token;
3 import net.sf.saxon.expr.XPathContext;
4 import net.sf.saxon.trans.DynamicError;
5 import net.sf.saxon.trans.XPathException;
6 import net.sf.saxon.type.*;
7 import net.sf.saxon.ConversionContext;
8
9 import java.math.BigDecimal JavaDoc;
10 import java.math.BigInteger JavaDoc;
11
12 /**
13  * An integer value: note this is a subtype of decimal in XML Schema, not a primitive type.
14  * The class IntegerValue is used to represent xs:integer values that fit comfortably
15  * in a Java long; this class is used to represent xs:integer values outside this range,
16  * including the built-in subtype xs:unsignedLong
17  */

18
19 public final class BigIntegerValue extends NumericValue {
20
21     private BigInteger JavaDoc value;
22     private ItemType type;
23
24     private static final BigInteger JavaDoc MAX_INT = BigInteger.valueOf(Integer.MAX_VALUE);
25     private static final BigInteger JavaDoc MIN_INT = BigInteger.valueOf(Integer.MIN_VALUE);
26     private static final BigInteger JavaDoc MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE);
27     private static final BigInteger JavaDoc MIN_LONG = BigInteger.valueOf(Long.MIN_VALUE);
28     public static final BigInteger JavaDoc MAX_UNSIGNED_LONG = new BigInteger JavaDoc("18446744073709551615");
29     public static final BigIntegerValue ZERO = new BigIntegerValue(BigInteger.ZERO);
30
31     public BigIntegerValue(BigInteger JavaDoc value) {
32         this.value = value;
33         this.type = Type.INTEGER_TYPE;
34     }
35
36     public BigIntegerValue(long value) {
37         this.value = BigInteger.valueOf(value);
38         this.type = Type.INTEGER_TYPE;
39     }
40
41     /**
42      * This class allows subtypes of xs:integer to be held, as well as xs:integer values.
43      * This method sets the required type label. This method should only be used for values that
44      * @param type the subtype of integer required
45      * @return null if the operation succeeds, or a ValidationException if the value is out of range
46      */

47
48     public ValidationException convertToSubType(AtomicType type, boolean validate) {
49         if (!validate) {
50             this.type = type;
51             return null;
52         }
53         if (IntegerValue.checkBigRange(value, type)) {
54             this.type = type;
55             return null;
56         } else {
57             ValidationException err = new ValidationException(
58                     "Integer value is out of range for subtype " + type.getDisplayName());
59             err.setErrorCode("FORG0001");
60             return err;
61         }
62     }
63
64     /**
65      * Factory method: makes either an IntegerValue or a BigIntegerValue depending on the value supplied
66      */

67
68     public static NumericValue makeValue(BigInteger JavaDoc value) {
69         if (value.compareTo(MAX_LONG) > 0 || value.compareTo(MIN_LONG) < 0) {
70             return new BigIntegerValue(value);
71         } else {
72             return new IntegerValue(value.longValue());
73         }
74     }
75
76     /**
77      * Get the hashCode. This must conform to the rules for other NumericValue hashcodes
78      * @see NumericValue#hashCode
79      */

80
81     public int hashCode() {
82         if (value.compareTo(MIN_INT) >= 0 && value.compareTo(MAX_INT) <= 0) {
83             return value.intValue();
84         } else {
85             return new Double JavaDoc(this.getDoubleValue()).hashCode();
86         }
87     }
88
89     /**
90      * Get the value as a long
91      *
92      * @return the value of the xs:integer, as a Java long
93      */

94
95     public long longValue() {
96         return value.longValue();
97     }
98
99     /**
100      * Get the value as a BigInteger
101      * @return teh value of the xs:integer as a Java BigInteger
102      */

103
104     public BigInteger JavaDoc getBigInteger() {
105         return value;
106     }
107
108     public boolean isWithinLongRange() {
109         return value.compareTo(MIN_LONG) >= 0 && value.compareTo(MAX_LONG) <= 0;
110     }
111
112     public BigDecimal JavaDoc asDecimal() {
113         return new BigDecimal JavaDoc(value);
114     }
115
116     /**
117      * Return the effective boolean value of this integer
118      *
119      * @param context The dynamic evaluation context; ignored in this
120      * implementation of the method
121      * @return false if the integer is zero, otherwise true
122      */

123     public boolean effectiveBooleanValue(XPathContext context) {
124         return value.compareTo(BigInteger.ZERO) != 0;
125     }
126
127     /**
128      * Compare the value to another numeric value
129      *
130      * @param other the numeric value to be compared to this value
131      * @return -1 if this value is less than the other, 0 if they are equal,
132      * +1 if this value is greater
133      */

134
135     public int compareTo(Object JavaDoc other) {
136         if (other instanceof BigIntegerValue) {
137             return value.compareTo(((BigIntegerValue)other).value);
138         } else if (other instanceof DecimalValue) {
139             return asDecimal().compareTo(((DecimalValue)other).getValue());
140         } else {
141             return super.compareTo(other);
142         }
143     }
144
145     /**
146      * Compare two values for equality. This supports identity constraints in XML Schema,
147      * which allow list-valued elements and attributes to participate in key and uniqueness constraints.
148      * This method returns false if any error occurs during the comparison, or if any of the items
149      * in either sequence is a node rather than an atomic value. The default implementation of
150      * schemaEquals() is the same as equals(), but subclasses can override this.
151      */

152
153     public boolean schemaEquals(Value obj) {
154         if (obj instanceof AtomicValue) {
155             obj = ((AtomicValue)obj).getPrimitiveValue();
156         }
157         if (obj instanceof DecimalValue) {
158             return obj.schemaEquals(this);
159         } else if (obj instanceof BigIntegerValue) {
160             return value.equals(((BigIntegerValue)obj).value);
161         } else if (obj instanceof IntegerValue) {
162             return equals(obj);
163         } else {
164             return false;
165         }
166     }
167
168
169     /**
170      * Convert to target data type
171      *
172      * @param requiredType an integer identifying the required atomic type
173      * @param conversion
174      * @return an AtomicValue, a value of the required type; or an ErrorValue
175      */

176
177     public AtomicValue convertPrimitive(BuiltInAtomicType requiredType, boolean validate, ConversionContext conversion) {
178         switch (requiredType.getFingerprint()) {
179             case Type.BOOLEAN:
180                 return BooleanValue.get(effectiveBooleanValue(null));
181
182             case Type.NUMBER:
183             case Type.INTEGER:
184             case Type.LONG:
185             case Type.ATOMIC:
186             case Type.ITEM:
187                 return this;
188
189             case Type.NON_POSITIVE_INTEGER:
190             case Type.NEGATIVE_INTEGER:
191             case Type.INT:
192             case Type.SHORT:
193             case Type.BYTE:
194             case Type.NON_NEGATIVE_INTEGER:
195             case Type.POSITIVE_INTEGER:
196             case Type.UNSIGNED_INT:
197             case Type.UNSIGNED_SHORT:
198             case Type.UNSIGNED_BYTE:
199                 if (isWithinLongRange()) {
200                     IntegerValue val = new IntegerValue(longValue());
201                     ValidationException err = val.convertToSubtype(requiredType, validate);
202                     if (err == null) {
203                         return val;
204                     } else {
205                         return new ValidationErrorValue(err);
206                     }
207                 } else {
208                     BigIntegerValue val = new BigIntegerValue(value);
209                     ValidationException err = val.convertToSubType(requiredType, validate);
210                     if (err == null) {
211                         return val;
212                     } else {
213                         return new ValidationErrorValue(err);
214                     }
215                 }
216
217             case Type.UNSIGNED_LONG:
218                 if (value.signum() < 0 || value.bitLength() > 64) {
219                     ValidationException err = new ValidationException("Integer value is out of range for type " +
220                             requiredType.getDisplayName());
221                     err.setErrorCode("FORG0001");
222                     //err.setXPathContext(context);
223
return new ValidationErrorValue(err);
224                 } else if (isWithinLongRange()) {
225                     IntegerValue val = new IntegerValue(longValue());
226                     ValidationException err = val.convertToSubtype(requiredType, validate);
227                     if (err != null) {
228                         return new ValidationErrorValue(err);
229                     }
230                     return val;
231                 } else {
232                     BigIntegerValue nv = new BigIntegerValue(value);
233                     ValidationException err = nv.convertToSubType(requiredType, validate);
234                     if (err != null) {
235                         return new ValidationErrorValue(err);
236                     }
237                     return nv;
238                 }
239
240             case Type.DOUBLE:
241                 return new DoubleValue(value.doubleValue());
242
243             case Type.FLOAT:
244                 return new FloatValue(value.floatValue());
245
246             case Type.DECIMAL:
247                 return new DecimalValue(new BigDecimal JavaDoc(value));
248
249             case Type.STRING:
250                 return new StringValue(getStringValueCS());
251
252             case Type.UNTYPED_ATOMIC:
253                 return new UntypedAtomicValue(getStringValueCS());
254
255             default:
256                 ValidationException err = new ValidationException("Cannot convert integer to " +
257                                          requiredType.getDisplayName());
258                 //err.setXPathContext(context);
259
err.setErrorCode("FORG0001");
260                 return new ValidationErrorValue(err);
261         }
262     }
263
264     /**
265      * Get the value as a String
266      * @return a String representation of the value
267      */

268
269     public String JavaDoc getStringValue() {
270         return value.toString();
271     }
272
273     /**
274      * Negate the value
275      * @return the result of inverting the sign of the value
276      */

277
278     public NumericValue negate() {
279         return new BigIntegerValue(value.negate());
280     }
281
282     /**
283      * Implement the XPath floor() function
284      * @return the integer value, unchanged
285      */

286
287     public NumericValue floor() {
288         return this;
289     }
290
291     /**
292      * Implement the XPath ceiling() function
293      * @return the integer value, unchanged
294      */

295
296     public NumericValue ceiling() {
297         return this;
298     }
299
300     /**
301      * Implement the XPath round() function
302      * @return the integer value, unchanged
303      */

304
305     public NumericValue round() {
306         return this;
307     }
308
309     /**
310      * Implement the XPath round-to-half-even() function
311      *
312      * @param scale number of digits required after the decimal point; the
313      * value -2 (for example) means round to a multiple of 100
314      * @return if the scale is >=0, return this value unchanged. Otherwise
315      * round it to a multiple of 10**-scale
316      */

317
318     public NumericValue roundToHalfEven(int scale) {
319         if (scale >= 0) {
320             return this;
321         } else {
322             BigInteger JavaDoc factor = BigInteger.valueOf(10).pow(-scale);
323             BigInteger JavaDoc[] pair = value.divideAndRemainder(factor);
324             int up = pair[1].compareTo(factor.divide(BigInteger.valueOf(2)));
325             if (up > 0) {
326                 // remainder is > .5
327
pair[0] = pair[0].add(BigInteger.valueOf(1));
328             } else if (up == 0) {
329                 // remainder == .5
330
if (pair[0].mod(BigInteger.valueOf(2)).signum() != 0) {
331                     // last digit of quotient is odd: make it even
332
pair[0] = pair[0].add(BigInteger.valueOf(1));
333                 }
334             }
335             return makeValue(pair[0].multiply(factor));
336         }
337     }
338
339     /**
340      * Determine whether the value is negative, zero, or positive
341      * @return -1 if negative, 0 if zero, +1 if positive, NaN if NaN
342      */

343
344     public double signum() {
345         return value.signum();
346     }
347
348     /**
349      * Determine whether the value is a whole number, that is, whether it compares
350      * equal to some integer
351      *
352      * @return always true for this implementation
353      */

354
355     public boolean isWholeNumber() {
356         return true;
357     }
358
359     /**
360      * Evaluate a binary arithmetic operator.
361      *
362      * @param operator the operator to be applied, identified by a constant in
363      * the Tokenizer class
364      * @param other the other operand of the arithmetic expression
365      * @exception XPathException if an arithmetic failure occurs, e.g. divide
366      * by zero
367      * @return the result of performing the arithmetic operation
368      */

369
370     public NumericValue arithmetic(int operator, NumericValue other, XPathContext context) throws XPathException {
371         if (other instanceof BigIntegerValue) {
372             BigInteger JavaDoc that = ((BigIntegerValue)other).value;
373             switch(operator) {
374                 case Token.PLUS:
375                     return makeValue(value.add(that));
376                 case Token.MINUS:
377                     return makeValue(value.subtract(that));
378                 case Token.MULT:
379                     return makeValue(value.multiply(that));
380                 case Token.IDIV:
381                     try {
382                         return makeValue(value.divide(that));
383                     } catch (ArithmeticException JavaDoc err) {
384                         DynamicError e;
385                         if ("/ by zero".equals(err.getMessage())) {
386                             e = new DynamicError("Integer division by zero");
387                             e.setErrorCode("FOAR0001");
388                         } else {
389                             e = new DynamicError("Integer division failure", err);
390                         }
391                         e.setXPathContext(context);
392                         throw e;
393                     }
394                 case Token.DIV:
395                     DecimalValue a = new DecimalValue(new BigDecimal JavaDoc(value));
396                     DecimalValue b = new DecimalValue(new BigDecimal JavaDoc(that));
397                     return a.arithmetic(operator, b, context);
398                 case Token.MOD:
399                     return makeValue(value.remainder(that));
400                 default:
401                     throw new UnsupportedOperationException JavaDoc("Unknown operator");
402             }
403         } else if (other instanceof IntegerValue) {
404             BigIntegerValue val = new BigIntegerValue(other.longValue());
405             return arithmetic(operator, val, context);
406         } else {
407             NumericValue v = (NumericValue)convert(other.getItemType().getPrimitiveType(), context);
408             return v.arithmetic(operator, other, context);
409         }
410     }
411
412
413     /**
414      * Determine the data type of the expression
415      *
416      * @return the actual data type
417      */

418
419     public ItemType getItemType() {
420         return type;
421     }
422
423     /**
424      * Convert to Java object (for passing to external functions)
425      *
426      * @param target The Java class to which conversion is required
427      * @exception XPathException if conversion is not possible, or fails
428      * @return the Java object that results from the conversion; always an
429      * instance of the target class
430      */

431
432     public Object JavaDoc convertToJava(Class JavaDoc target, XPathContext context) throws XPathException {
433         if (isWithinLongRange()) {
434             IntegerValue val = new IntegerValue(longValue());
435             return val.convertToJava(target, context);
436         } else if (target.isAssignableFrom(IntegerValue.class)) {
437             return this;
438         } else if (target == BigInteger JavaDoc.class) {
439             return value;
440         } else {
441             return convert(Type.DECIMAL, context).convertToJava(target, context);
442         }
443     }
444
445
446 }
447
448 //
449
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
450
// you may not use this file except in compliance with the License. You may obtain a copy of the
451
// License at http://www.mozilla.org/MPL/
452
//
453
// Software distributed under the License is distributed on an "AS IS" basis,
454
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
455
// See the License for the specific language governing rights and limitations under the License.
456
//
457
// The Original Code is: all this file except the asStringXT() and zeros() methods (not currently used).
458
//
459
// The Initial Developer of the Original Code is Michael H. Kay.
460
//
461
// Portions created by (xt) are Copyright (C) (James Clark). All Rights Reserved.
462
//
463
// Contributor(s): none.
464
//
465

466
Popular Tags