001: // Copyright (c) 2006 Per M.A. Bothner.
002: // This is free software; for specifics see ../../../COPYING.
003:
004: package gnu.kawa.xml;
005:
006: import gnu.math.*;
007: import gnu.bytecode.*;
008: import java.math.*;
009: import gnu.kawa.functions.Arithmetic;
010:
011: /** A restriction (sub-range) of the integer type.
012: * Implements built-in XML Schema types derived from {@code xs:integer}.
013: */
014:
015: public class XIntegerType extends XDataType {
016: /** The lower bound, inclusive. of the value range of this type.
017: * If there is no lower bound then {@code minValue} is {@code null}. */
018: public final IntNum minValue;
019: /** The upper bound, inclusive. of the value range of this type.
020: * If there is no upper bound then {@code maxValue} is {@code null}. */
021: public final IntNum maxValue;
022:
023: static ClassType typeIntNum = ClassType.make("gnu.math.IntNum");
024:
025: boolean isUnsignedType;
026:
027: public boolean isUnsignedType() {
028: return isUnsignedType;
029: }
030:
031: public static final XIntegerType integerType = new XIntegerType(
032: "integer", decimalType, INTEGER_TYPE_CODE, null, null);
033: public static final XIntegerType longType = new XIntegerType(
034: "long", integerType, LONG_TYPE_CODE, IntNum
035: .make(Long.MIN_VALUE), IntNum.make(Long.MAX_VALUE));
036: public static final XIntegerType intType = new XIntegerType("int",
037: longType, INT_TYPE_CODE, IntNum.make(Integer.MIN_VALUE),
038: IntNum.make(Integer.MAX_VALUE));
039: public static final XIntegerType shortType = new XIntegerType(
040: "short", intType, SHORT_TYPE_CODE, IntNum
041: .make(Short.MIN_VALUE), IntNum
042: .make(Short.MAX_VALUE));
043: public static final XIntegerType byteType = new XIntegerType(
044: "byte", shortType, BYTE_TYPE_CODE, IntNum
045: .make(Byte.MIN_VALUE), IntNum.make(Byte.MAX_VALUE));
046: public static final XIntegerType nonPositiveIntegerType = new XIntegerType(
047: "nonPositiveInteger", integerType,
048: NON_POSITIVE_INTEGER_TYPE_CODE, null, IntNum.zero());
049: public static final XIntegerType negativeIntegerType = new XIntegerType(
050: "negativeInteger", nonPositiveIntegerType,
051: NEGATIVE_INTEGER_TYPE_CODE, null, IntNum.minusOne());
052: public static final XIntegerType nonNegativeIntegerType = new XIntegerType(
053: "nonNegativeInteger", integerType,
054: NONNEGATIVE_INTEGER_TYPE_CODE, IntNum.zero(), null);
055: public static final XIntegerType unsignedLongType = new XIntegerType(
056: "unsignedLong", nonNegativeIntegerType,
057: UNSIGNED_LONG_TYPE_CODE, IntNum.zero(), IntNum
058: .valueOf("18446744073709551615"));
059: public static final XIntegerType unsignedIntType = new XIntegerType(
060: "unsignedInt", unsignedLongType, UNSIGNED_INT_TYPE_CODE,
061: IntNum.zero(), IntNum.make(4294967295L));
062: public static final XIntegerType unsignedShortType = new XIntegerType(
063: "unsignedShort", unsignedIntType, UNSIGNED_SHORT_TYPE_CODE,
064: IntNum.zero(), IntNum.make(65535));
065: public static final XIntegerType unsignedByteType = new XIntegerType(
066: "unsignedByte", unsignedShortType, UNSIGNED_BYTE_TYPE_CODE,
067: IntNum.zero(), IntNum.make(255));
068: public static final XIntegerType positiveIntegerType = new XIntegerType(
069: "positiveInteger", nonNegativeIntegerType,
070: POSITIVE_INTEGER_TYPE_CODE, IntNum.one(), null);
071:
072: public XIntegerType(String name, XDataType base, int typeCode,
073: IntNum min, IntNum max) {
074: // FIXME Should convert NAME to xs:NAME.
075: this ((Object) name, base, typeCode, min, max);
076: isUnsignedType = name.startsWith("unsigned");
077: }
078:
079: public XIntegerType(Object name, XDataType base, int typeCode,
080: IntNum min, IntNum max) {
081: super (name, typeIntNum, typeCode);
082: minValue = min;
083: maxValue = max;
084: baseType = base;
085: }
086:
087: public boolean isInstance(Object obj) {
088: if (!(obj instanceof IntNum))
089: return false;
090: if (this == integerType)
091: return true;
092: XDataType objType = (obj instanceof XInteger ? ((XInteger) obj)
093: .getIntegerType() : integerType);
094: while (objType != null) {
095: if (objType == this )
096: return true;
097: objType = objType.baseType;
098: }
099: return false;
100: }
101:
102: public Object coerceFromObject(Object obj) {
103: return valueOf((IntNum) obj);
104: }
105:
106: public IntNum valueOf(IntNum value) {
107: if (this != integerType) {
108: if ((minValue != null && IntNum.compare(value, minValue) < 0)
109: || (maxValue != null && IntNum.compare(value,
110: maxValue) > 0))
111: throw new ClassCastException("cannot cast " + value
112: + " to " + name);
113: return new XInteger(value, this );
114: }
115: return value;
116: }
117:
118: public Object cast(Object value) {
119: if (value instanceof Boolean)
120: return valueOf(((Boolean) value).booleanValue() ? IntNum
121: .one() : IntNum.zero());
122: if (value instanceof IntNum)
123: return valueOf((IntNum) value);
124: if (value instanceof BigDecimal)
125: return valueOf(Arithmetic.asIntNum((BigDecimal) value));
126: if (value instanceof RealNum)
127: return valueOf(((RealNum) value)
128: .toExactInt(RealNum.TRUNCATE));
129: if (value instanceof Number)
130: return valueOf(RealNum.toExactInt(((Number) value)
131: .doubleValue(), RealNum.TRUNCATE));
132: return super .cast(value);
133: }
134:
135: public Object valueOf(String value) {
136: value = value.trim();
137: int len = value.length();
138: if (len > 0) {
139: char ch = value.charAt(0);
140: if ((ch == '-' || ch == '+') && isUnsignedType())
141: throw new ClassCastException("cannot cast " + value
142: + " to " + name);
143: else if (ch == '+')
144: value = value.substring(1);
145: }
146: return valueOf(IntNum.valueOf(value, 10));
147: }
148:
149: public IntNum valueOf(String value, int radix) {
150: return valueOf(IntNum.valueOf(value.trim(), radix));
151: }
152: }
|