commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From d...@apache.org
Subject svn commit: r591782 - in /commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl: Arithmetic.java JexlArithmetic.java
Date Sun, 04 Nov 2007 13:56:12 GMT
Author: dion
Date: Sun Nov  4 05:56:11 2007
New Revision: 591782

URL: http://svn.apache.org/viewvc?rev=591782&view=rev
Log:
add pluggable arithmetic operators

Added:
    commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/Arithmetic.java
    commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlArithmetic.java

Added: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/Arithmetic.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/Arithmetic.java?rev=591782&view=auto
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/Arithmetic.java (added)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/Arithmetic.java Sun
Nov  4 05:56:11 2007
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.jexl;
+/**
+ * Pluggable arithmetic operators. 
+ */
+interface Arithmetic {
+
+    /**
+     * Add two values together.
+     *
+     * @param left first value
+     * @param right second value
+     * @return left + right.
+     */
+    Object add(Object left, Object right);
+
+    /**
+     * Divide the left value by the right.
+     *
+     * @param left first value
+     * @param right second value
+     * @return left - right.
+     */
+    Object divide(Object left, Object right);
+
+    /**
+     * left value mod right.
+     *
+     * @param left first value
+     * @param right second value
+     * @return left mod right.
+     */
+    Object mod(Object left, Object right);
+
+    /**
+     * Multiply the left value by the right.
+     *
+     * @param left first value
+     * @param right second value
+     * @return left * right.
+     */
+    Object multiply(Object left, Object right);
+
+    /**
+     * Subtract the right value from the left.
+     *
+     * @param left first value
+     * @param right second value
+     * @return left + right.
+     */
+    Object subtract(Object left, Object right);
+}
\ No newline at end of file

Added: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlArithmetic.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlArithmetic.java?rev=591782&view=auto
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlArithmetic.java
(added)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlArithmetic.java
Sun Nov  4 05:56:11 2007
@@ -0,0 +1,301 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.jexl;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import org.apache.commons.jexl.util.Coercion;
+
+/**
+ * Perform arithmetic.
+ * @since 2.0
+ */
+class JexlArithmetic implements Arithmetic {
+
+    /**
+     * Add two values together.
+     * Rules are:<ol>
+     * <li>If both are null, result is 0</li>
+     * <li>If either are floating point numbers, coerce to BigDecimals
+     *      and add together</li>
+     * <li>Else treat as BigIntegers and add together</li>
+     * <li>If either numeric add fails on coercion to the appropriate type,
+     *      treat as Strings and do concatenation</li>
+     * </ol>
+     * @param left first value
+     * @param right second value
+     * @return left + right.
+     */
+    public Object add(Object left, Object right) {
+        if (left == null && right == null) {
+            return new Long(0);
+        }
+        
+        try {
+            if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
+                double l = Coercion.coercedouble(left);
+                double r = Coercion.coercedouble(right);
+                return new Double(l + r);
+            }
+        
+            // if both are bigintegers use that type
+            if (left instanceof BigInteger && right instanceof BigInteger) {
+                BigInteger l = Coercion.coerceBigInteger(left);
+                BigInteger r = Coercion.coerceBigInteger(right);
+                return l.add(r);
+            }
+            
+            // if either are bigdecimal use that type 
+            if (left instanceof BigDecimal || right instanceof BigDecimal) {
+                BigDecimal l = Coercion.coerceBigDecimal(left);
+                BigDecimal r = Coercion.coerceBigDecimal(right);
+                return l.add(r);
+            }
+            
+            // otherwise treat as integers
+            BigInteger l = Coercion.coerceBigInteger(left);
+            BigInteger r = Coercion.coerceBigInteger(right);
+            BigInteger result = l.add(r);
+            BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); 
+            if (result.compareTo(maxLong) <= 0) {
+                return new Long(result.longValue());
+            }
+            return result;
+        } catch (java.lang.NumberFormatException nfe) {
+            // Well, use strings!
+            return left.toString().concat(right.toString());
+        }
+    }
+
+    /**
+     * Divide the left value by the right.
+     * Rules are:<ol>
+     * <li>If both are null, result is 0</li>
+     * <li>Treat as BigDecimals and divide</li>
+     * </ol>
+     * @param left first value
+     * @param right second value
+     * @return left - right.
+     */
+    public Object divide(Object left, Object right) {
+        if (left == null && right == null) {
+            return new Long(0);
+        }
+
+        // if both are bigintegers use that type
+        if (left instanceof BigInteger && right instanceof BigInteger) {
+            BigInteger l = Coercion.coerceBigInteger(left);
+            BigInteger r = Coercion.coerceBigInteger(right);
+            if (r.compareTo(BigInteger.valueOf(0)) == 0) {
+                return r;
+            }
+            return l.divide(r);
+        }
+        
+        // if either are bigdecimal use that type 
+        if (left instanceof BigDecimal || right instanceof BigDecimal) {
+            BigDecimal l = Coercion.coerceBigDecimal(left);
+            BigDecimal r = Coercion.coerceBigDecimal(right);
+            if (r.compareTo(BigDecimal.valueOf(0)) == 0) {
+                return r;
+            }
+            return l.divide(r, BigDecimal.ROUND_HALF_UP);
+        }
+
+        double l = Coercion.coercedouble(left);
+        double r = Coercion.coercedouble(right);
+        if (r == 0) {
+            return new Double(r);
+        }
+        return new Double(l / r);
+
+    }
+    
+    /**
+     * left value mod right.
+     * Rules are:<ol>
+     * <li>If both are null, result is 0</li>
+     * <li>Treat both as BigIntegers and perform modulus</li>
+     * </ol>
+     * @param left first value
+     * @param right second value
+     * @return left mod right.
+     */
+    public Object mod(Object left, Object right) {
+        if (left == null && right == null) {
+            return new Long(0);
+        }
+
+        if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
+            double l = Coercion.coercedouble(left);
+            double r = Coercion.coercedouble(right);
+            return new Double(l % r);
+        }
+
+        // if both are bigintegers use that type
+        if (left instanceof BigInteger && right instanceof BigInteger) {
+            BigInteger l = Coercion.coerceBigInteger(left);
+            BigInteger r = Coercion.coerceBigInteger(right);
+            if (r.compareTo(BigInteger.valueOf(0)) == 0) {
+                return r;
+            }
+            return l.mod(r);
+        }
+
+        // if either are bigdecimal use that type 
+        if (left instanceof BigDecimal || right instanceof BigDecimal) {
+            BigDecimal l = Coercion.coerceBigDecimal(left);
+            BigDecimal r = Coercion.coerceBigDecimal(right);
+            if (r.compareTo(BigDecimal.valueOf(0)) == 0) {
+                return r;
+            }
+            BigInteger intDiv = l.divide(r, BigDecimal.ROUND_HALF_UP).toBigInteger();
+            BigInteger intValue = (r.multiply(new BigDecimal(intDiv))).toBigInteger();
+            BigDecimal remainder = new BigDecimal(l.subtract(new BigDecimal(intValue)).toBigInteger());
+            return remainder;
+        }
+
+        // otherwise treat as integers
+        BigInteger l = Coercion.coerceBigInteger(left);
+        BigInteger r = Coercion.coerceBigInteger(right);
+        BigInteger result = l.mod(r);
+        BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); 
+        if (result.compareTo(maxLong) <= 0) {
+            return new Long(result.longValue());
+        }
+        return result;
+    }
+    
+    /**
+     * Multiply the left value by the right.
+     * Rules are:<ol>
+     * <li>If both are null, result is 0</li>
+     * <li>If either are floating point numbers, coerce to BigDecimals
+     *      and multiply</li>
+     * <li>Else treat as BigIntegers and multiply</li>
+     * <li>If either numeric operation fails on coercion to the appropriate type,
+     *      treat as Strings and do concatenation</li>
+     * </ol>
+     * @param left first value
+     * @param right second value
+     * @return left * right.
+     */
+    public Object multiply(Object left, Object right) {
+        if (left == null && right == null) {
+            return new Long(0);
+        }
+        
+        if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
+            double l = Coercion.coercedouble(left);
+            double r = Coercion.coercedouble(right);
+            return new Double(l * r);
+        }
+        
+        // if both are bigintegers use that type
+        if (left instanceof BigInteger && right instanceof BigInteger) {
+            BigInteger l = Coercion.coerceBigInteger(left);
+            BigInteger r = Coercion.coerceBigInteger(right);
+            return l.multiply(r);
+        }
+        
+        // if either are bigdecimal use that type 
+        if (left instanceof BigDecimal || right instanceof BigDecimal) {
+            BigDecimal l = Coercion.coerceBigDecimal(left);
+            BigDecimal r = Coercion.coerceBigDecimal(right);
+            return l.multiply(r);
+        }
+
+        // otherwise treat as integers
+        BigInteger l = Coercion.coerceBigInteger(left);
+        BigInteger r = Coercion.coerceBigInteger(right);
+        BigInteger result = l.multiply(r);
+        BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); 
+        if (result.compareTo(maxLong) <= 0) {
+            return new Long(result.longValue());
+        }
+        return result;
+    }
+    
+    /**
+     * Subtract the right value from the left.
+     * Rules are:<ol>
+     * <li>If both are null, result is 0</li>
+     * <li>If either are floating point numbers, coerce to BigDecimals
+     *      and subtract</li>
+     * <li>Else treat as BigIntegers and subtract</li>
+     * <li>If either numeric operation fails on coercion to the appropriate type,
+     *      treat as Strings and do concatenation</li>
+     * </ol>
+     * @param left first value
+     * @param right second value
+     * @return left + right.
+     */
+    public Object subtract(Object left, Object right) {
+        if (left == null && right == null) {
+            return new Long(0);
+        }
+        
+        if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
+            double l = Coercion.coercedouble(left);
+            double r = Coercion.coercedouble(right);
+            return new Double(l - r);
+        }
+        
+        // if both are bigintegers use that type
+        if (left instanceof BigInteger && right instanceof BigInteger) {
+            BigInteger l = Coercion.coerceBigInteger(left);
+            BigInteger r = Coercion.coerceBigInteger(right);
+            return l.subtract(r);
+        }
+        
+        // if either are bigdecimal use that type 
+        if (left instanceof BigDecimal || right instanceof BigDecimal) {
+            BigDecimal l = Coercion.coerceBigDecimal(left);
+            BigDecimal r = Coercion.coerceBigDecimal(right);
+            return l.subtract(r);
+        }
+
+        // otherwise treat as integers
+        BigInteger l = Coercion.coerceBigInteger(left);
+        BigInteger r = Coercion.coerceBigInteger(right);
+        BigInteger result = l.subtract(r);
+        BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); 
+        if (result.compareTo(maxLong) <= 0) {
+            return new Long(result.longValue());
+        }
+        return result;
+    }
+    
+    /**
+     * Test if the passed value is a floating point number, i.e. a float, double
+     * or string with ( "." | "E" | "e").
+     *
+     * @param val the object to be tested
+     * @return true if it is, false otherwise.
+     */
+    private boolean isFloatingPointNumber(Object val) {
+        if (val instanceof Float || val instanceof Double) {
+            return true;
+        }
+        if (val instanceof String) {
+            String string = (String) val;
+            return string.indexOf(".") != -1 || string.indexOf("e") != -1 || string.indexOf("E")
!= -1;
+        }
+        return false;
+    }
+}



Mime
View raw message