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]

Reply via email to