1 package net.sf.saxon.value; 2 3 import net.sf.saxon.Err; 4 import net.sf.saxon.ConversionContext; 5 import net.sf.saxon.expr.Token; 6 import net.sf.saxon.expr.XPathContext; 7 import net.sf.saxon.trans.DynamicError; 8 import net.sf.saxon.trans.XPathException; 9 import net.sf.saxon.type.*; 10 11 import java.math.BigDecimal ; 12 import java.math.BigInteger ; 13 14 19 20 public final class IntegerValue extends NumericValue { 21 22 25 public static final IntegerValue MINUS_ONE = new IntegerValue(-1); 26 29 public static final IntegerValue ZERO = new IntegerValue(0); 30 33 public static final IntegerValue PLUS_ONE = new IntegerValue(+1); 34 37 public static final IntegerValue MAX_LONG = new IntegerValue(Long.MAX_VALUE); 38 41 public static final IntegerValue MIN_LONG = new IntegerValue(Long.MIN_VALUE); 42 43 private long value; 44 private ItemType type; 45 46 51 52 public IntegerValue(long value) { 53 this.value = value; 54 this.type = Type.INTEGER_TYPE; 55 } 56 57 65 66 public IntegerValue(long val, AtomicType type) throws DynamicError { 67 this.value = val; 68 this.type = type; 69 if (!checkRange(value, type)) { 70 DynamicError err = new DynamicError("Integer value " + val + 71 " is out of range for the requested type " + type.getDescription()); 72 err.setErrorCode("FORG0001"); 73 throw err; 74 }; 75 } 76 77 84 85 public ValidationException convertToSubtype(AtomicType subtype, boolean validate) { 86 if (!validate) { 87 setSubType(subtype); 88 return null; 89 } else if (checkRange(subtype)) { 90 return null; 91 } else { 92 ValidationException err = new ValidationException("String " + value + 93 " cannot be converted to integer subtype " + subtype.getDescription()); 94 err.setErrorCode("FORG0001"); 95 return err; 96 } 97 } 98 99 104 public void setSubType(AtomicType type) { 105 this.type = type; 106 } 107 108 114 public boolean checkRange(AtomicType type) { 115 this.type = type; 116 return checkRange(value, type); 117 } 118 119 125 126 public static AtomicValue stringToInteger(CharSequence s) { 127 128 int len = s.length(); 129 int start = 0; 130 while (start < len && s.charAt(start) <= 0x20) { 131 start++; 132 } 133 int last = len - 1; 134 while (last > start && s.charAt(last) <= 0x20) { 135 last--; 136 } 137 if (start > last) { 138 return numericError("Cannot convert zero-length string to an integer"); 139 } 140 if (last - start < 16) { 141 boolean negative = false; 143 long value = 0; 144 int i=start; 145 if (s.charAt(i) == '+') { 146 i++; 147 } else if (s.charAt(i) == '-') { 148 negative = true; 149 i++; 150 } 151 if (i > last) { 152 return numericError("Cannot convert string " + Err.wrap(s, Err.VALUE) + 153 " to integer: no digits after the sign"); 154 } 155 while (i <= last) { 156 char d = s.charAt(i++); 157 if (d >= '0' && d <= '9') { 158 value = 10*value + (d-'0'); 159 } else { 160 return numericError("Cannot convert string " + Err.wrap(s, Err.VALUE) + " to an integer"); 161 } 162 } 163 return new IntegerValue((negative ? -value : value)); 164 } else { 165 try { 167 CharSequence t = trimWhitespace(s); 168 if (t.charAt(0) == '+') { 169 t = t.subSequence(1, t.length()); 170 } 171 if (t.length() < 16) { 172 return new IntegerValue(Long.parseLong(t.toString())); 173 } else { 174 return new BigIntegerValue(new BigInteger (t.toString())); 175 } 176 } catch (NumberFormatException err) { 177 return numericError("Cannot convert string " + Err.wrap(s, Err.VALUE) + " to an integer"); 178 } 179 } 180 } 181 182 187 private static ValidationErrorValue numericError(String message) { 188 ValidationException err = new ValidationException(message); 189 err.setErrorCode("FORG0001"); 190 return new ValidationErrorValue(err); 191 } 192 193 200 201 static boolean checkRange(long value, AtomicType type) { 202 for (int i = 0; i < ranges.length; i += 3) { 203 if (ranges[i] == type.getFingerprint()) { 204 long min = ranges[i+1]; 205 if (min != NO_LIMIT && value < min) { 206 return false; 207 } 208 long max = ranges[i+2]; 209 if (max != NO_LIMIT && max != MAX_UNSIGNED_LONG && value > max) { 210 return false; 211 } 212 return true; 213 } 214 } 215 throw new IllegalArgumentException ( 216 "No range information found for integer subtype " + type.getDescription()); 217 } 218 219 223 224 static boolean checkBigRange(BigInteger big, AtomicType type) { 225 226 for (int i = 0; i < ranges.length; i += 3) { 227 if (ranges[i] == type.getFingerprint()) { 228 long min = ranges[i+1]; 229 if (min != NO_LIMIT && BigInteger.valueOf(min).compareTo(big) > 0) { 230 return false; 231 } 232 long max = ranges[i+2]; 233 if (max == NO_LIMIT) { 234 return true; 235 } else if (max == MAX_UNSIGNED_LONG) { 236 return BigIntegerValue.MAX_UNSIGNED_LONG.compareTo(big) >= 0; 237 } else { 238 return BigInteger.valueOf(max).compareTo(big) >= 0; 239 } 240 } 241 } 242 throw new IllegalArgumentException ( 243 "No range information found for integer subtype " + type.getDescription()); 244 } 245 246 253 private static long NO_LIMIT = -9999; 254 private static long MAX_UNSIGNED_LONG = -9998; 255 private static long[] ranges = { 256 Type.INTEGER, NO_LIMIT, NO_LIMIT, 257 Type.NON_POSITIVE_INTEGER, NO_LIMIT, 0, 258 Type.NEGATIVE_INTEGER, NO_LIMIT, -1, 259 Type.LONG, Long.MIN_VALUE, Long.MAX_VALUE, 260 Type.INT, Integer.MIN_VALUE, Integer.MAX_VALUE, 261 Type.SHORT, Short.MIN_VALUE, Short.MAX_VALUE, 262 Type.BYTE, Byte.MIN_VALUE, Byte.MAX_VALUE, 263 Type.NON_NEGATIVE_INTEGER, 0, NO_LIMIT, 264 Type.POSITIVE_INTEGER, 1, NO_LIMIT, 265 Type.UNSIGNED_LONG, 0, MAX_UNSIGNED_LONG, 266 Type.UNSIGNED_INT, 0, 4294967295L, 267 Type.UNSIGNED_SHORT, 0, 65535, 268 Type.UNSIGNED_BYTE, 0, 255}; 269 270 271 275 276 public int hashCode() { 277 if (value > Integer.MIN_VALUE && value < Integer.MAX_VALUE) { 278 return (int) value; 279 } else { 280 return new Double (this.getDoubleValue()).hashCode(); 281 } 282 } 283 284 288 289 public long longValue() { 290 return value; 291 } 292 293 299 public boolean effectiveBooleanValue(XPathContext context) { 300 return value != 0; 301 } 302 303 309 310 public int compareTo(Object other) { 311 if (other instanceof IntegerValue) { 312 long val2 = ((IntegerValue) other).value; 313 if (value == val2) return 0; 314 if (value < val2) return -1; 315 return 1; 316 } else if (other instanceof BigIntegerValue) { 317 return new BigIntegerValue(value).compareTo(other); 318 } else { 319 return super.compareTo(other); 320 } 321 } 322 323 330 331 public boolean schemaEquals(Value obj) { 332 if (obj instanceof AtomicValue) { 333 obj = ((AtomicValue)obj).getPrimitiveValue(); 334 } 335 if (obj instanceof DecimalValue) { 336 return obj.schemaEquals(this); 337 } else if (obj instanceof IntegerValue) { 338 return value == ((IntegerValue)obj).value; 339 } else if (obj instanceof BigIntegerValue) { 340 return equals(obj); 341 } else { 342 return false; 343 } 344 } 345 346 353 354 public AtomicValue convertPrimitive(BuiltInAtomicType requiredType, boolean validate, ConversionContext conversion) { 355 switch (requiredType.getFingerprint()) { 356 case Type.BOOLEAN: 357 return BooleanValue.get(value != 0); 358 359 case Type.NUMBER: 360 case Type.INTEGER: 361 case Type.ATOMIC: 362 case Type.ITEM: 363 return this; 364 365 case Type.NON_POSITIVE_INTEGER: 366 case Type.NEGATIVE_INTEGER: 367 case Type.LONG: 368 case Type.INT: 369 case Type.SHORT: 370 case Type.BYTE: 371 case Type.NON_NEGATIVE_INTEGER: 372 case Type.POSITIVE_INTEGER: 373 case Type.UNSIGNED_LONG: 374 case Type.UNSIGNED_INT: 375 case Type.UNSIGNED_SHORT: 376 case Type.UNSIGNED_BYTE: 377 IntegerValue val = new IntegerValue(value); 378 ValidationException err = val.convertToSubtype(requiredType, validate); 379 if (err != null) { 380 return new ValidationErrorValue(err); 381 } 382 return val; 383 384 case Type.DOUBLE: 385 return new DoubleValue((double) value); 386 387 case Type.FLOAT: 388 return new FloatValue((float) value); 389 390 case Type.DECIMAL: 391 return new DecimalValue(value); 392 393 case Type.STRING: 394 return new StringValue(getStringValue()); 395 396 case Type.UNTYPED_ATOMIC: 397 return new UntypedAtomicValue(getStringValue()); 398 399 default: 400 ValidationException err2 = new ValidationException("Cannot convert integer to " + 401 requiredType.getDisplayName()); 402 err2.setErrorCode("FORG0001"); 404 return new ValidationErrorValue(err2); 405 } 406 } 407 408 413 414 public String getStringValue() { 415 return value + ""; 416 } 417 418 423 424 public NumericValue negate() { 425 return new IntegerValue(-value); 426 } 427 428 432 433 public NumericValue floor() { 434 return this; 435 } 436 437 441 442 public NumericValue ceiling() { 443 return this; 444 } 445 446 450 451 public NumericValue round() { 452 return this; 453 } 454 455 463 464 public NumericValue roundToHalfEven(int scale) { 465 long absolute = Math.abs(value); 466 if (scale >= 0) { 467 return this; 468 } else { 469 if (scale < -15) { 470 return new BigIntegerValue(value).roundToHalfEven(scale); 471 } 472 long factor = 1; 473 for (long i = 1; i <= -scale; i++) { 474 factor *= 10; 475 } 476 long modulus = absolute % factor; 477 long rval = absolute - modulus; 478 long d = modulus * 2; 479 if (d > factor) { 480 rval += factor; 481 } else if (d < factor) { 482 } else { 484 if (rval % (2 * factor) == 0) { 486 } else { 488 rval += factor; 489 } 490 } 491 if (value < 0) rval = -rval; 492 return new IntegerValue(rval); 493 } 494 } 495 496 500 501 public double signum() { 502 if (value > 0) return +1; 503 if (value == 0) return 0; 504 return -1; 505 } 506 507 513 514 public boolean isWholeNumber() { 515 return true; 516 } 517 518 528 529 public NumericValue arithmetic(int operator, NumericValue other, XPathContext context) throws XPathException { 530 531 if (other instanceof IntegerValue) { 532 if (value >= Integer.MAX_VALUE || value <= Integer.MIN_VALUE || 534 ((IntegerValue) other).value >= Integer.MAX_VALUE || 535 ((IntegerValue) other).value <= Integer.MIN_VALUE) { 536 return new BigIntegerValue(value).arithmetic(operator, other, context); 537 } 538 switch (operator) { 539 case Token.PLUS: 540 return new IntegerValue(value + ((IntegerValue) other).value); 541 case Token.MINUS: 542 return new IntegerValue(value - ((IntegerValue) other).value); 543 case Token.MULT: 544 return new IntegerValue(value * ((IntegerValue) other).value); 545 case Token.IDIV: 546 try { 547 return new IntegerValue(value / ((IntegerValue) other).value); 548 } catch (ArithmeticException err) { 549 DynamicError e; 550 if ("/ by zero".equals(err.getMessage())) { 551 e = new DynamicError("Integer division by zero"); 552 e.setErrorCode("FOAR0001"); 553 } else { 554 e = new DynamicError("Integer division failure", err); 555 } 556 e.setXPathContext(context); 557 throw e; 558 } 559 case Token.DIV: 560 long quotient = ((IntegerValue) other).value; 563 if (quotient == 0) { 564 DynamicError err = new DynamicError("Integer division by zero"); 565 err.setXPathContext(context); 566 err.setErrorCode("FOAR0001"); 567 throw err; 568 } 569 if (value % quotient == 0) { 570 return new IntegerValue(value / quotient); 571 } 572 return new DecimalValue(value).arithmetic(Token.DIV, 573 new DecimalValue(quotient), context); 574 case Token.MOD: 575 return new IntegerValue(value % ((IntegerValue) other).value); 576 default: 577 throw new UnsupportedOperationException ("Unknown operator"); 578 } 579 } else if (other instanceof BigIntegerValue) { 580 return new BigIntegerValue(value).arithmetic(operator, other, context); 581 } else { 582 NumericValue v = (NumericValue) convert(other.getItemType().getPrimitiveType(), context); 583 return v.arithmetic(operator, other, context); 584 } 585 } 586 587 591 592 public ItemType getItemType() { 593 return type; 594 } 595 596 603 604 607 615 616 public Object convertToJava(Class target, XPathContext context) throws XPathException { 617 if (target == Object .class) { 618 return new Long (value); 619 } else if (target.isAssignableFrom(IntegerValue.class)) { 620 return this; 621 } else if (target == boolean.class) { 622 BooleanValue bval = (BooleanValue) convert(Type.BOOLEAN, context); 623 return Boolean.valueOf(bval.getBooleanValue()); 624 } else if (target == Boolean .class) { 625 BooleanValue bval = (BooleanValue) convert(Type.BOOLEAN, context); 626 return Boolean.valueOf(bval.getBooleanValue()); 627 } else if (target == String .class || target == CharSequence .class) { 628 return getStringValue(); 629 } else if (target == double.class || target == Double .class) { 630 return new Double (value); 631 } else if (target == float.class || target == Float .class) { 632 return new Float (value); 633 } else if (target == long.class || target == Long .class) { 634 return new Long (value); 635 } else if (target == int.class || target == Integer .class) { 636 return new Integer ((int) value); 637 } else if (target == short.class || target == Short .class) { 638 return new Short ((short) value); 639 } else if (target == byte.class || target == Byte .class) { 640 return new Byte ((byte) value); 641 } else if (target == char.class || target == Character .class) { 642 return new Character ((char) value); 643 } else if (target == BigInteger .class) { 644 return BigInteger.valueOf(value); 645 } else if (target == BigDecimal .class) { 646 return BigDecimal.valueOf(value); 647 } else { 648 Object o = super.convertToJava(target, context); 649 if (o == null) { 650 throw new DynamicError("Conversion of integer to " + target.getName() + 651 " is not supported"); 652 } 653 return o; 654 } 655 } 656 657 } 658 659 677 | Popular Tags |