sandygao 2002/10/25 13:28:42 Modified: java/src/org/apache/xerces/impl/dv/xs DecimalDV.java Log: Performance: we were using java.math.BigDecimal and BigInteger to represent decimal values. These classes are too heavy, and involve a lot of object creations. Now we use a light weight object for decimal values. We may want to add more functionality to this new representation later, but it now has everything necessary for schema validation. Revision Changes Path 1.5 +127 -71 xml-xerces/java/src/org/apache/xerces/impl/dv/xs/DecimalDV.java Index: DecimalDV.java =================================================================== RCS file: /home/cvs/xml-xerces/java/src/org/apache/xerces/impl/dv/xs/DecimalDV.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- DecimalDV.java 18 Jul 2002 20:48:43 -0000 1.4 +++ DecimalDV.java 25 Oct 2002 20:28:42 -0000 1.5 @@ -77,115 +77,171 @@ } public Object getActualValue(String content, ValidationContext context) throws InvalidDatatypeValueException { + try { + return new MyDecimal(content); + } catch (NumberFormatException nfe) { + throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "decimal"}); + } + } + + public boolean isEqual(Object value1, Object value2) { + if (!(value1 instanceof MyDecimal) || !(value2 instanceof MyDecimal)) + return false; + return ((MyDecimal)value1).equals((MyDecimal)value2); + } + + public int compare(Object value1, Object value2){ + return ((MyDecimal)value1).compareTo((MyDecimal)value2); + } + + public int getTotalDigits(Object value){ + return ((MyDecimal)value).totalDigits; + } + + public int getFractionDigits(Object value){ + return ((MyDecimal)value).fracDigits; + } + +} // class DecimalDV +// Avoid using the heavy-weight java.math.BigDecimal +class MyDecimal { + // sign: 0 for vlaue 0; 1 for positive values; -1 for negative values + int sign = 1; + // total digits. >= 1 + int totalDigits = 0; + // integer digits when sign != 0 + int intDigits = 0; + // fraction digits when sign != 0 + int fracDigits = 0; + // the string representing the integer part + String ivalue = ""; + // the string representing the fraction part + String fvalue = ""; + + MyDecimal(String content) throws NumberFormatException { + if (content.equals("0")) { + int i = 0; + } int len = content.length(); if (len == 0) - throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "decimal"}); - + throw new NumberFormatException(); + // these 4 variables are used to indicate where the integre/fraction // parts start/end. int intStart = 0, intEnd = 0, fracStart = 0, fracEnd = 0; - + // Deal with leading sign symbol if present if (content.charAt(0) == '+') { // skip '+', so intStart should be 1 - intStart = intEnd = 1; + intStart = 1; } else if (content.charAt(0) == '-') { // keep '-', so intStart is stil 0 - intEnd = 1; + intStart = 1; + sign = -1; + } + + // skip leading zeroes in integer part + int actualIntStart = intStart; + while (actualIntStart < len && content.charAt(actualIntStart) == '0') { + actualIntStart++; } // Find the ending position of the integer part - while (intEnd < len && isDigit(content.charAt(intEnd))) - intEnd++; - + for (intEnd = actualIntStart; + intEnd < len && TypeValidator.isDigit(content.charAt(intEnd)); + intEnd++); + // Not reached the end yet if (intEnd < len) { // the remaining part is not ".DDD", error if (content.charAt(intEnd) != '.') - throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "decimal"}); + throw new NumberFormatException(); // fraction part starts after '.', and ends at the end of the input fracStart = intEnd + 1; fracEnd = len; } - + // no integer part, no fraction part, error. if (intStart == intEnd && fracStart == fracEnd) - throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "decimal"}); + throw new NumberFormatException(); - // count leading zeroes in integer part - int actualIntStart = content.charAt(intStart) == '-' ? intStart + 1 : intStart; - while (actualIntStart < intEnd && content.charAt(actualIntStart) == '0') { - actualIntStart++; - } - // ignore trailing zeroes in fraction part while (fracEnd > fracStart && content.charAt(fracEnd-1) == '0') { fracEnd--; } - + // check whether there is non-digit characters in the fraction part for (int fracPos = fracStart; fracPos < fracEnd; fracPos++) { - if (!isDigit(content.charAt(fracPos))) - throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "decimal"}); + if (!TypeValidator.isDigit(content.charAt(fracPos))) + throw new NumberFormatException(); } - - int fracNum = fracEnd - fracStart; - - // concatenate the two parts to one integer string - String intString = null; - if (intEnd > intStart) { - intString = content.substring(intStart, intEnd); - if (fracNum > 0) - intString += content.substring(fracStart, fracEnd); + + intDigits = intEnd - actualIntStart; + fracDigits = fracEnd - fracStart; + totalDigits = (intDigits == 0 ? 1 : intDigits) + fracDigits; + + if (intDigits > 0) { + ivalue = content.substring(actualIntStart, intEnd); + if (fracDigits > 0) + fvalue = content.substring(fracStart, fracEnd); } else { - if (fracNum > 0) - intString = content.substring(fracStart, fracEnd); - else + if (fracDigits > 0) { + fvalue = content.substring(fracStart, fracEnd); + } + else { // ".00", treat it as "0" - intString = "0"; - } - - try { - // create a BigInteger using the integer string - BigInteger intVal = new BigInteger(intString); - // carete a MyDecimal using the BigInteger and scale - return new XDecimal(intVal, intEnd - actualIntStart, fracNum); - } catch (Exception nfe) { - throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object[]{content, "decimal"}); + sign = 0; + } } } - - public boolean isEqual(Object value1, Object value2) { - if (!(value1 instanceof BigDecimal) || !(value2 instanceof BigDecimal)) + public boolean equals(MyDecimal val) { + if (val == null) return false; - return ((BigDecimal)value1).compareTo((BigDecimal)value2) == 0; + if (val == this) + return true; + + if (sign != val.sign) + return false; + if (sign == 0) + return true; + + return intDigits == val.intDigits && fracDigits == val.fracDigits && + ivalue.equals(val.ivalue) && fvalue.equals(val.fvalue); } - - public int compare(Object value1, Object value2){ - return ((BigDecimal)value1).compareTo((BigDecimal)value2); + public int compareTo(MyDecimal val) { + if (sign != val.sign) + return sign > val.sign ? 1 : -1; + if (sign == 0) + return 0; + return sign * intComp(val); } - - public int getTotalDigits(Object value){ - return ((XDecimal)value).totalDigits; + private int intComp(MyDecimal val) { + if (intDigits != val.intDigits) + return intDigits > val.intDigits ? 1 : -1; + int ret = ivalue.compareTo(val.ivalue); + if (ret != 0) + return ret > 0 ? 1 : -1;; + ret = fvalue.compareTo(val.fvalue); + return ret == 0 ? 0 : (ret > 0 ? 1 : -1); } - - public int getFractionDigits(Object value){ - return ((BigDecimal)value).scale(); - } - -} // class DecimalDV - -// store total digits in this class -class XDecimal extends java.math.BigDecimal { - int totalDigits = 0; - XDecimal(BigInteger intVal, int intNum, int fracNum) { - super(intVal, fracNum); - // the canonical form of decimal requires at least one digit - // on both sides of the decimal point - totalDigits = (intNum == 0 ? 1 : intNum) + fracNum; + public String toString() { + if (sign == 0) + return "0"; + StringBuffer buffer = new StringBuffer(totalDigits+2); + if (sign == -1) + buffer.append('-'); + if (intDigits != 0) + buffer.append(ivalue); + else + buffer.append('0'); + if (fracDigits != 0) { + buffer.append('.'); + buffer.append(fvalue); + } + return buffer.toString(); } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]