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 ; 10 import java.math.BigInteger ; 11 12 18 19 public final class BigIntegerValue extends NumericValue { 20 21 private BigInteger value; 22 private ItemType type; 23 24 private static final BigInteger MAX_INT = BigInteger.valueOf(Integer.MAX_VALUE); 25 private static final BigInteger MIN_INT = BigInteger.valueOf(Integer.MIN_VALUE); 26 private static final BigInteger MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE); 27 private static final BigInteger MIN_LONG = BigInteger.valueOf(Long.MIN_VALUE); 28 public static final BigInteger MAX_UNSIGNED_LONG = new BigInteger ("18446744073709551615"); 29 public static final BigIntegerValue ZERO = new BigIntegerValue(BigInteger.ZERO); 30 31 public BigIntegerValue(BigInteger 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 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 67 68 public static NumericValue makeValue(BigInteger 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 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 (this.getDoubleValue()).hashCode(); 86 } 87 } 88 89 94 95 public long longValue() { 96 return value.longValue(); 97 } 98 99 103 104 public BigInteger 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 asDecimal() { 113 return new BigDecimal (value); 114 } 115 116 123 public boolean effectiveBooleanValue(XPathContext context) { 124 return value.compareTo(BigInteger.ZERO) != 0; 125 } 126 127 134 135 public int compareTo(Object 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 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 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 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 (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.setErrorCode("FORG0001"); 260 return new ValidationErrorValue(err); 261 } 262 } 263 264 268 269 public String getStringValue() { 270 return value.toString(); 271 } 272 273 277 278 public NumericValue negate() { 279 return new BigIntegerValue(value.negate()); 280 } 281 282 286 287 public NumericValue floor() { 288 return this; 289 } 290 291 295 296 public NumericValue ceiling() { 297 return this; 298 } 299 300 304 305 public NumericValue round() { 306 return this; 307 } 308 309 317 318 public NumericValue roundToHalfEven(int scale) { 319 if (scale >= 0) { 320 return this; 321 } else { 322 BigInteger factor = BigInteger.valueOf(10).pow(-scale); 323 BigInteger [] pair = value.divideAndRemainder(factor); 324 int up = pair[1].compareTo(factor.divide(BigInteger.valueOf(2))); 325 if (up > 0) { 326 pair[0] = pair[0].add(BigInteger.valueOf(1)); 328 } else if (up == 0) { 329 if (pair[0].mod(BigInteger.valueOf(2)).signum() != 0) { 331 pair[0] = pair[0].add(BigInteger.valueOf(1)); 333 } 334 } 335 return makeValue(pair[0].multiply(factor)); 336 } 337 } 338 339 343 344 public double signum() { 345 return value.signum(); 346 } 347 348 354 355 public boolean isWholeNumber() { 356 return true; 357 } 358 359 369 370 public NumericValue arithmetic(int operator, NumericValue other, XPathContext context) throws XPathException { 371 if (other instanceof BigIntegerValue) { 372 BigInteger 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 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 (value)); 396 DecimalValue b = new DecimalValue(new BigDecimal (that)); 397 return a.arithmetic(operator, b, context); 398 case Token.MOD: 399 return makeValue(value.remainder(that)); 400 default: 401 throw new UnsupportedOperationException ("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 418 419 public ItemType getItemType() { 420 return type; 421 } 422 423 431 432 public Object convertToJava(Class 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 .class) { 439 return value; 440 } else { 441 return convert(Type.DECIMAL, context).convertToJava(target, context); 442 } 443 } 444 445 446 } 447 448 466 | Popular Tags |