]> source.dussan.org Git - poi.git/commitdiff
removed AreaEval.getValues (initial work for bug 45358)
authorJosh Micich <josh@apache.org>
Sun, 31 Aug 2008 19:08:36 +0000 (19:08 +0000)
committerJosh Micich <josh@apache.org>
Sun, 31 Aug 2008 19:08:36 +0000 (19:08 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@690761 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/record/formula/eval/AreaEval.java
src/java/org/apache/poi/hssf/record/formula/eval/AreaEvalBase.java
src/java/org/apache/poi/hssf/record/formula/eval/NumberEval.java
src/java/org/apache/poi/hssf/record/formula/functions/Index.java
src/java/org/apache/poi/hssf/record/formula/functions/MultiOperandNumericFunction.java
src/java/org/apache/poi/hssf/record/formula/functions/Sumx2my2.java
src/java/org/apache/poi/hssf/record/formula/functions/Sumx2py2.java
src/java/org/apache/poi/hssf/record/formula/functions/Sumxmy2.java
src/java/org/apache/poi/hssf/record/formula/functions/XYNumericFunction.java
src/testcases/org/apache/poi/hssf/record/formula/functions/TestSumproduct.java

index 182b9b618b458587d6adc666930f02476a9a4e4b..eaecf267ace21cd739656a53a27d744e6e801def 100644 (file)
@@ -61,13 +61,6 @@ public interface AreaEval extends ValueEval {
      */
     boolean isColumn();
 
-    /**
-     * The array of values  in this area. Although the area
-     * maybe 1D (ie. isRow() or isColumn() returns true) or 2D
-     * the returned array is 1D.
-     */
-    ValueEval[] getValues();
-
     /**
      * @return the ValueEval from within this area at the specified row and col index. Never 
      * <code>null</code> (possibly {@link BlankEval}).  The specified indexes should be absolute 
index 1686e75f33a4a3f27d501162cd5726a892f66de3..0a812102dca94c44806975599fa8cd4df02149ab 100644 (file)
@@ -77,11 +77,6 @@ abstract class AreaEvalBase implements AreaEval {
                return _lastRow;
        }
 
-       public final ValueEval[] getValues() {
-               // TODO - clone() - but some junits rely on not cloning at the moment
-               return _values;
-       }
-
        public final ValueEval getValueAt(int row, int col) {
                int rowOffsetIx = row - _firstRow;
                int colOffsetIx = col - _firstColumn;
index 44a017f631d98347b8ab43b0f316f72362ef1bf7..e22957bd4ab14642d18ac44264ce4001f60f6082 100644 (file)
@@ -69,5 +69,11 @@ public class NumberEval implements NumericValueEval, StringValueEval {
             }
         }
     }
-    
+    public final String toString() {
+        StringBuffer sb = new StringBuffer(64);
+        sb.append(getClass().getName()).append(" [");
+        sb.append(getStringValue());
+        sb.append("]");
+        return sb.toString();
+    }
 }
index aebf6aab0d4843ab3b0b88f7aa1b2238e163123a..3c93c0846bdab7b908876774d4d8fde4a2fd4d80 100644 (file)
@@ -1,28 +1,28 @@
-/*
-* 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.
-*/
+/* ====================================================================
+   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.poi.hssf.record.formula.functions;
 
 import org.apache.poi.hssf.record.formula.eval.AreaEval;
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.RefEval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
+import org.apache.poi.hssf.record.formula.eval.OperandResolver;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
 /**
  * Implementation for the Excel function INDEX<p/>
@@ -51,15 +51,23 @@ public final class Index implements Function {
                        return ErrorEval.VALUE_INVALID;
                }
                Eval firstArg = args[0];
-               if(firstArg instanceof AreaEval) {
-                       AreaEval reference = (AreaEval) firstArg;
+               if(!(firstArg instanceof AreaEval)) {
+                       
+                       // else the other variation of this function takes an array as the first argument
+                       // it seems like interface 'ArrayEval' does not even exist yet
                        
-                       int rowIx = 0;
-                       int columnIx = 0;
-                       int areaIx = 0;
+                       throw new RuntimeException("Incomplete code - cannot handle first arg of type ("
+                                       + firstArg.getClass().getName() + ")");
+               }
+               AreaEval reference = (AreaEval) firstArg;
+               
+               int rowIx = 0;
+               int columnIx = 0;
+               int areaIx = 0;
+               try {   
                        switch(nArgs) {
                                case 4:
-                                       areaIx = convertIndexArgToZeroBase(args[3]);
+                                       areaIx = convertIndexArgToZeroBase(args[3], srcCellRow, srcCellCol);
                                        throw new RuntimeException("Incomplete code" +
                                                        " - don't know how to support the 'area_num' parameter yet)");
                                        // Excel expression might look like this "INDEX( (A1:B4, C3:D6, D2:E5 ), 1, 2, 3)
@@ -68,41 +76,41 @@ public final class Index implements Function {
                                        // The formula parser doesn't seem to support this yet. Not sure if the evaluator does either
                                        
                                case 3:
-                                       columnIx = convertIndexArgToZeroBase(args[2]);
+                                       columnIx = convertIndexArgToZeroBase(args[2], srcCellRow, srcCellCol);
                                case 2:
-                                       rowIx = convertIndexArgToZeroBase(args[1]);
+                                       rowIx = convertIndexArgToZeroBase(args[1], srcCellRow, srcCellCol);
                                        break;
                                default:
                                        // too many arguments
                                        return ErrorEval.VALUE_INVALID;
                        }
-                       
-               int nColumns = reference.getLastColumn()-reference.getFirstColumn()+1;
-                       int index = rowIx * nColumns + columnIx;
-                       
-                       return reference.getValues()[index];
+                       return getValueFromArea(reference, rowIx, columnIx);
+               } catch (EvaluationException e) {
+                       return e.getErrorEval();
                }
-               
-               // else the other variation of this function takes an array as the first argument
-               // it seems like interface 'ArrayEval' does not even exist yet
-               
-               throw new RuntimeException("Incomplete code - cannot handle first arg of type ("
-                               + firstArg.getClass().getName() + ")");
        }
        
+       private static ValueEval getValueFromArea(AreaEval ae, int rowIx, int columnIx) throws EvaluationException {
+               int width = ae.getWidth();
+               int height = ae.getHeight();
+               
+               // Slightly irregular logic for bounds checking errors
+               if (rowIx >= height || columnIx >= width) {
+                       throw new EvaluationException(ErrorEval.REF_INVALID);
+               }
+               if (rowIx < 0 || columnIx < 0) {
+                       throw new EvaluationException(ErrorEval.VALUE_INVALID);
+               }
+               return ae.getRelativeValue(rowIx, columnIx);
+       }
+
        /**
         * takes a NumberEval representing a 1-based index and returns the zero-based int value
         */
-       private static int convertIndexArgToZeroBase(Eval ev) {
-               NumberEval ne;
-               if(ev instanceof RefEval) {
-                       // TODO - write junit to justify this
-                       RefEval re = (RefEval) ev;
-                       ne = (NumberEval) re.getInnerValueEval();
-               } else {
-                       ne = (NumberEval)ev;
-               }
+       private static int convertIndexArgToZeroBase(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
                
-               return (int)ne.getNumberValue() - 1;
+               ValueEval ev = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+               int oneBasedVal = OperandResolver.coerceValueToInt(ev);
+               return oneBasedVal - 1;
        }
 }
index 0e7cce217e2ebc04e07c99e891ade018e83afb6e..a9e98ae313087f229d2b05da82d58b3b64ff84b8 100644 (file)
@@ -126,30 +126,34 @@ public abstract class MultiOperandNumericFunction extends NumericFunction {
         
         if (operand instanceof AreaEval) {
             AreaEval ae = (AreaEval) operand;
-            ValueEval[] values = ae.getValues();
             DoubleList retval = new DoubleList();
-            for (int j=0, jSize=values.length; j<jSize; j++) {
-                /*
-                 * TODO: For an AreaEval, we are constructing a RefEval
-                 * per element.
-                 * For now this is a tempfix solution since this may
-                 * require a more generic fix at the level of
-                 * HSSFFormulaEvaluator where we store an array
-                 * of RefEvals as the "values" array. 
-                 */
-                RefEval re = new Ref2DEval(null, values[j]);
-                ValueEval ve = singleOperandEvaluate(re, srcRow, srcCol);
-                
-                if (ve instanceof NumericValueEval) {
-                    NumericValueEval nve = (NumericValueEval) ve;
-                    retval.add(nve.getNumberValue());
-                }
-                else if (ve instanceof BlankEval) {
-                    // note - blanks are ignored, so returned array will be smaller.
-                } 
-                else {
-                    return null; // indicate to calling subclass that error occurred
-                }
+            int width = ae.getWidth();
+               int height = ae.getHeight();
+               for (int rrIx=0; rrIx<height; rrIx++) {
+                       for (int rcIx=0; rcIx<width; rcIx++) {
+                               ValueEval ve1 = ae.getRelativeValue(rrIx, rcIx);
+                     /*
+                     * TODO: For an AreaEval, we are constructing a RefEval
+                     * per element.
+                     * For now this is a tempfix solution since this may
+                     * require a more generic fix at the level of
+                     * HSSFFormulaEvaluator where we store an array
+                     * of RefEvals as the "values" array. 
+                     */
+                    RefEval re = new Ref2DEval(null, ve1);
+                    ValueEval ve = singleOperandEvaluate(re, srcRow, srcCol);
+                    
+                    if (ve instanceof NumericValueEval) {
+                        NumericValueEval nve = (NumericValueEval) ve;
+                        retval.add(nve.getNumberValue());
+                    }
+                    else if (ve instanceof BlankEval) {
+                        // note - blanks are ignored, so returned array will be smaller.
+                    } 
+                    else {
+                        return null; // indicate to calling subclass that error occurred
+                    }
+                       }
             }
             return retval.toArray();
         }
index 30ad5ec2303ee70347d5da2cd219d97a2bc17884..4dedf26574859fdef3f26b4a0c5138f4ff685aa7 100644 (file)
@@ -1,22 +1,23 @@
-/*
-* 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.
-*/
+/* ====================================================================
+   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.poi.hssf.record.formula.functions;
 
+
 /**
  * Implementation of Excel function SUMX2MY2()<p/>
  * 
@@ -30,7 +31,13 @@ package org.apache.poi.hssf.record.formula.functions;
  */
 public final class Sumx2my2 extends XYNumericFunction {
 
-    protected double evaluate(double[] xArray, double[] yArray) {
-       return MathX.sumx2my2(xArray, yArray);
-    }
+       private static final Accumulator XSquaredMinusYSquaredAccumulator = new Accumulator() {
+               public double accumulate(double x, double y) {
+                       return x * x - y * y;
+               }
+       };
+
+       protected Accumulator createAccumulator() {
+               return XSquaredMinusYSquaredAccumulator;
+       }
 }
index dfd730d12cd347b378de777bef046097f7888d94..c3af0bd3802b8b71c0b1f8277bf64f453fb1cfed 100644 (file)
@@ -1,22 +1,23 @@
-/*
-* 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.
-*/
+/* ====================================================================
+   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.poi.hssf.record.formula.functions;
 
+
 /**
  * Implementation of Excel function SUMX2PY2()<p/>
  * 
@@ -30,7 +31,13 @@ package org.apache.poi.hssf.record.formula.functions;
  */
 public final class Sumx2py2 extends XYNumericFunction {
 
-    protected double evaluate(double[] xArray, double[] yArray) {
-       return MathX.sumx2py2(xArray, yArray);
-    }
+       private static final Accumulator XSquaredPlusYSquaredAccumulator = new Accumulator() {
+               public double accumulate(double x, double y) {
+                       return x * x + y * y;
+               }
+       };
+
+       protected Accumulator createAccumulator() {
+               return XSquaredPlusYSquaredAccumulator;
+       }
 }
index a1b2fec9b2854ebd5910db2e3d1bad7ca9b09f6a..4fa11e36ba77ab9f658abc71fb9f1f5bc38cb9dc 100644 (file)
@@ -1,19 +1,19 @@
-/*
-* 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.
-*/
+/* ====================================================================
+   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.poi.hssf.record.formula.functions;
 
@@ -30,7 +30,14 @@ package org.apache.poi.hssf.record.formula.functions;
  */
 public final class Sumxmy2 extends XYNumericFunction {
 
-    protected double evaluate(double[] xArray, double[] yArray) {
-       return MathX.sumxmy2(xArray, yArray);
-    }
+       private static final Accumulator XMinusYSquaredAccumulator = new Accumulator() {
+               public double accumulate(double x, double y) {
+                       double xmy = x - y;
+                       return xmy * xmy;
+               }
+       };
+
+       protected Accumulator createAccumulator() {
+               return XMinusYSquaredAccumulator;
+       }
 }
index b989c33a26790fdbdab30d815aaf7bcd614009f3..1d83b363fda3fe5169a409f2cdc8c4a4c5f94481 100644 (file)
@@ -1,19 +1,19 @@
-/*
-* 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.
-*/
+/* ====================================================================
+   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.poi.hssf.record.formula.functions;
 
@@ -24,180 +24,162 @@ import org.apache.poi.hssf.record.formula.eval.EvaluationException;
 import org.apache.poi.hssf.record.formula.eval.NumberEval;
 import org.apache.poi.hssf.record.formula.eval.RefEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.functions.LookupUtils.ValueVector;
 
 /**
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
+ * 
  */
 public abstract class XYNumericFunction implements Function {
-    protected static final int X = 0;
-    protected static final int Y = 1;
-    
-    protected static final class DoubleArrayPair {
 
-               private final double[] _xArray;
-               private final double[] _yArray;
+       private static abstract class ValueArray implements ValueVector {
+               private final int _size;
+               protected ValueArray(int size) {
+                       _size = size;
+               }
+               public ValueEval getItem(int index) {
+                       if (index < 0 || index > _size) {
+                               throw new IllegalArgumentException("Specified index " + index
+                                               + " is outside range (0.." + (_size - 1) + ")");
+                       }
+                       return getItemInternal(index);
+               }
+               protected abstract ValueEval getItemInternal(int index);
+               public final int getSize() {
+                       return _size;
+               }
+       }
 
-               public DoubleArrayPair(double[] xArray, double[] yArray) {
-                       _xArray = xArray;
-                       _yArray = yArray;
+       private static final class SingleCellValueArray extends ValueArray {
+               private final ValueEval _value;
+               public SingleCellValueArray(ValueEval value) {
+                       super(1);
+                       _value = value;
                }
-               public double[] getXArray() {
-                       return _xArray;
+               protected ValueEval getItemInternal(int index) {
+                       return _value;
+               }
+       }
+
+       private static final class RefValueArray extends ValueArray {
+               private final RefEval _ref;
+               public RefValueArray(RefEval ref) {
+                       super(1);
+                       _ref = ref;
                }
-               public double[] getYArray() {
-                       return _yArray;
+               protected ValueEval getItemInternal(int index) {
+                       return _ref.getInnerValueEval();
                }
-    }
+       }
 
+       private static final class AreaValueArray extends ValueArray {
+               private final AreaEval _ae;
+               private final int _width;
+
+               public AreaValueArray(AreaEval ae) {
+                       super(ae.getWidth() * ae.getHeight());
+                       _ae = ae;
+                       _width = ae.getWidth();
+               }
+               protected ValueEval getItemInternal(int index) {
+                       int rowIx = index / _width;
+                       int colIx = index % _width;
+                       return _ae.getRelativeValue(rowIx, colIx);
+               }
+       }
+
+       protected static interface Accumulator {
+               double accumulate(double x, double y);
+       }
+
+       /**
+        * Constructs a new instance of the Accumulator used to calculated this function
+        */
+       protected abstract Accumulator createAccumulator();
+
+       public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+               if (args.length != 2) {
+                       return ErrorEval.VALUE_INVALID;
+               }
 
-    public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
-       if(args.length != 2) {
-               return ErrorEval.VALUE_INVALID;
-       }
-       
-        double[][] values;
+               double result;
                try {
-                       values = getValues(args[0], args[1]);
+                       ValueVector vvX = createValueVector(args[0]);
+                       ValueVector vvY = createValueVector(args[1]);
+                       int size = vvX.getSize();
+                       if (size == 0 || vvY.getSize() != size) {
+                               return ErrorEval.NA;
+                       }
+                       result = evaluateInternal(vvX, vvY, size);
                } catch (EvaluationException e) {
                        return e.getErrorEval();
                }
-        if (values==null 
-                || values[X] == null || values[Y] == null
-                || values[X].length == 0 || values[Y].length == 0
-                || values[X].length != values[Y].length) {
-            return ErrorEval.VALUE_INVALID;
-        }
-        
-        double d = evaluate(values[X], values[Y]);
-        if (Double.isNaN(d) || Double.isInfinite(d)) {
+               if (Double.isNaN(result) || Double.isInfinite(result)) {
                        return ErrorEval.NUM_ERROR;
                }
-               return new NumberEval(d);
-    }    
-    protected abstract double evaluate(double[] xArray, double[] yArray);
-
-    /**
-     * Returns a double array that contains values for the numeric cells
-     * from among the list of operands. Blanks and Blank equivalent cells
-     * are ignored. Error operands or cells containing operands of type
-     * that are considered invalid and would result in #VALUE! error in 
-     * excel cause this function to return null.
-     */
-    private static double[][] getNumberArray(Eval[] xops, Eval[] yops) throws EvaluationException {
-       
-       // check for errors first: size mismatch, value errors in x, value errors in y
-       
-       int nArrayItems = xops.length;
-               if(nArrayItems != yops.length) {
-               throw new EvaluationException(ErrorEval.NA);
-       }
-               for (int i = 0; i < xops.length; i++) {
-                       Eval eval = xops[i];
-                       if (eval instanceof ErrorEval) {
-                               throw new EvaluationException((ErrorEval) eval);
+               return new NumberEval(result);
+       }
+
+       private double evaluateInternal(ValueVector x, ValueVector y, int size)
+                       throws EvaluationException {
+               Accumulator acc = createAccumulator();
+
+               // error handling is as if the x is fully evaluated before y
+               ErrorEval firstXerr = null;
+               ErrorEval firstYerr = null;
+               boolean accumlatedSome = false;
+               double result = 0.0;
+
+               for (int i = 0; i < size; i++) {
+                       ValueEval vx = x.getItem(i);
+                       ValueEval vy = y.getItem(i);
+                       if (vx instanceof ErrorEval) {
+                               if (firstXerr == null) {
+                                       firstXerr = (ErrorEval) vx;
+                                       continue;
+                               }
                        }
-               }
-               for (int i = 0; i < yops.length; i++) {
-                       Eval eval = yops[i];
-                       if (eval instanceof ErrorEval) {
-                               throw new EvaluationException((ErrorEval) eval);
+                       if (vy instanceof ErrorEval) {
+                               if (firstYerr == null) {
+                                       firstYerr = (ErrorEval) vy;
+                                       continue;
+                               }
+                       }
+                       // only count pairs if both elements are numbers
+                       if (vx instanceof NumberEval && vy instanceof NumberEval) {
+                               accumlatedSome = true;
+                               NumberEval nx = (NumberEval) vx;
+                               NumberEval ny = (NumberEval) vy;
+                               result += acc.accumulate(nx.getNumberValue(), ny.getNumberValue());
+                       } else {
+                               // all other combinations of value types are silently ignored
                        }
                }
-               
-        double[] xResult = new double[nArrayItems];
-        double[] yResult = new double[nArrayItems];
-       
-        int count = 0;
-        
-               for (int i=0, iSize=nArrayItems; i<iSize; i++) {
-                   Eval xEval = xops[i];
-                   Eval yEval = yops[i];
-                   
-                   if (isNumberEval(xEval) && isNumberEval(yEval)) {
-                       xResult[count] = getDoubleValue(xEval);
-                       yResult[count] = getDoubleValue(yEval);
-                       if (Double.isNaN(xResult[count]) || Double.isNaN(xResult[count])) {
-                           throw new EvaluationException(ErrorEval.NUM_ERROR);
-                       }
-                       count++;
-                   }
-               }
-        
-               return new double[][] {
-               trimToSize(xResult, count),
-            trimToSize(yResult, count),
-               };
-    }
-    
-    private static double[][] getValues(Eval argX, Eval argY) throws EvaluationException {
-       
-       if (argX instanceof ErrorEval) {
-                       throw new EvaluationException((ErrorEval) argX);
-               }
-       if (argY instanceof ErrorEval) {
-                       throw new EvaluationException((ErrorEval) argY);
-               }
-       
-        Eval[] xEvals;
-               Eval[] yEvals;
-               if (argX instanceof AreaEval) {
-                   AreaEval ae = (AreaEval) argX;
-                   xEvals = ae.getValues();
-               } else {
-                   xEvals = new Eval[] { argX, };
-               }
-               
-               if (argY instanceof AreaEval) {
-                   AreaEval ae = (AreaEval) argY;
-                   yEvals = ae.getValues();
-               } else {
-                   yEvals = new Eval[] { argY, };
-               }
-               
-               return getNumberArray(xEvals, yEvals);
-    }
-    
-    private static double[] trimToSize(double[] arr, int len) {
-        double[] tarr = arr;
-        if (arr.length > len) {
-            tarr = new double[len];
-            System.arraycopy(arr, 0, tarr, 0, len);
-        }
-        return tarr;
-    }
-    
-    private static boolean isNumberEval(Eval eval) {
-        boolean retval = false;
-        
-        if (eval instanceof NumberEval) {
-            retval = true;
-        }
-        else if (eval instanceof RefEval) {
-            RefEval re = (RefEval) eval;
-            ValueEval ve = re.getInnerValueEval();
-            retval = (ve instanceof NumberEval);
-        }
-        
-        return retval;
-    }
-    
-    private static double getDoubleValue(Eval eval) {
-        double retval = 0;
-        if (eval instanceof NumberEval) {
-            NumberEval ne = (NumberEval) eval;
-            retval = ne.getNumberValue();
-        }
-        else if (eval instanceof RefEval) {
-            RefEval re = (RefEval) eval;
-            ValueEval ve = re.getInnerValueEval();
-                retval = (ve instanceof NumberEval)
-                    ? ((NumberEval) ve).getNumberValue()
-                    : Double.NaN;
-        }
-        else if (eval instanceof ErrorEval) {
-            retval = Double.NaN;
-        }
-        return retval;
-    }
+               if (firstXerr != null) {
+                       throw new EvaluationException(firstXerr);
+               }
+               if (firstYerr != null) {
+                       throw new EvaluationException(firstYerr);
+               }
+               if (!accumlatedSome) {
+                       throw new EvaluationException(ErrorEval.DIV_ZERO);
+               }
+               return result;
+       }
+
+       private static ValueVector createValueVector(Eval arg) throws EvaluationException {
+               if (arg instanceof ErrorEval) {
+                       throw new EvaluationException((ErrorEval) arg);
+               }
+               if (arg instanceof AreaEval) {
+                       return new AreaValueArray((AreaEval) arg);
+               }
+               if (arg instanceof RefEval) {
+                       return new RefValueArray((RefEval) arg);
+               }
+               if (arg instanceof ValueEval) {
+                       return new SingleCellValueArray((ValueEval) arg);
+               }
+               throw new RuntimeException("Unexpected eval class (" + arg.getClass().getName() + ")");
+       }
 }
index 2f9a6314be54222bd69195d188dcebc3449424bc..884b9b4a3620facc7da0b0327b898d73c403865c 100755 (executable)
@@ -113,7 +113,6 @@ public final class TestSumproduct extends TestCase {
                };
                AreaEval aeA = EvalFactory.createAreaEval("A1:A2", aValues);
                AreaEval aeB = EvalFactory.createAreaEval("B1:B2", new ValueEval[2]);
-               aeB.getValues()[1] = ErrorEval.REF_INVALID;
 
                Eval[] args = { aeA, aeB, };
                assertEquals(ErrorEval.REF_INVALID, invokeSumproduct(args));