mirror of https://github.com/apache/poi.git
removed AreaEval.getValues (initial work for bug 45358)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@690761 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
b944df7e56
commit
908e676d57
|
@ -61,13 +61,6 @@ public interface AreaEval extends ValueEval {
|
||||||
*/
|
*/
|
||||||
boolean isColumn();
|
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
|
* @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
|
* <code>null</code> (possibly {@link BlankEval}). The specified indexes should be absolute
|
||||||
|
|
|
@ -77,11 +77,6 @@ abstract class AreaEvalBase implements AreaEval {
|
||||||
return _lastRow;
|
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) {
|
public final ValueEval getValueAt(int row, int col) {
|
||||||
int rowOffsetIx = row - _firstRow;
|
int rowOffsetIx = row - _firstRow;
|
||||||
int colOffsetIx = col - _firstColumn;
|
int colOffsetIx = col - _firstColumn;
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
/*
|
/* ====================================================================
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
* this work for additional information regarding copyright ownership.
|
this work for additional information regarding copyright ownership.
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
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 not use this file except in compliance with
|
||||||
* the License. You may obtain a copy of the License at
|
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
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;
|
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.AreaEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
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.Eval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
import org.apache.poi.hssf.record.formula.eval.EvaluationException;
|
||||||
import org.apache.poi.hssf.record.formula.eval.RefEval;
|
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/>
|
* Implementation for the Excel function INDEX<p/>
|
||||||
|
@ -51,15 +51,23 @@ public final class Index implements Function {
|
||||||
return ErrorEval.VALUE_INVALID;
|
return ErrorEval.VALUE_INVALID;
|
||||||
}
|
}
|
||||||
Eval firstArg = args[0];
|
Eval firstArg = args[0];
|
||||||
if(firstArg instanceof AreaEval) {
|
if(!(firstArg instanceof AreaEval)) {
|
||||||
AreaEval reference = (AreaEval) firstArg;
|
|
||||||
|
|
||||||
int rowIx = 0;
|
// else the other variation of this function takes an array as the first argument
|
||||||
int columnIx = 0;
|
// it seems like interface 'ArrayEval' does not even exist yet
|
||||||
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) {
|
switch(nArgs) {
|
||||||
case 4:
|
case 4:
|
||||||
areaIx = convertIndexArgToZeroBase(args[3]);
|
areaIx = convertIndexArgToZeroBase(args[3], srcCellRow, srcCellCol);
|
||||||
throw new RuntimeException("Incomplete code" +
|
throw new RuntimeException("Incomplete code" +
|
||||||
" - don't know how to support the 'area_num' parameter yet)");
|
" - 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)
|
// 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
|
// The formula parser doesn't seem to support this yet. Not sure if the evaluator does either
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
columnIx = convertIndexArgToZeroBase(args[2]);
|
columnIx = convertIndexArgToZeroBase(args[2], srcCellRow, srcCellCol);
|
||||||
case 2:
|
case 2:
|
||||||
rowIx = convertIndexArgToZeroBase(args[1]);
|
rowIx = convertIndexArgToZeroBase(args[1], srcCellRow, srcCellCol);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// too many arguments
|
// too many arguments
|
||||||
return ErrorEval.VALUE_INVALID;
|
return ErrorEval.VALUE_INVALID;
|
||||||
}
|
}
|
||||||
|
return getValueFromArea(reference, rowIx, columnIx);
|
||||||
int nColumns = reference.getLastColumn()-reference.getFirstColumn()+1;
|
} catch (EvaluationException e) {
|
||||||
int index = rowIx * nColumns + columnIx;
|
return e.getErrorEval();
|
||||||
|
|
||||||
return reference.getValues()[index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
* takes a NumberEval representing a 1-based index and returns the zero-based int value
|
||||||
*/
|
*/
|
||||||
private static int convertIndexArgToZeroBase(Eval ev) {
|
private static int convertIndexArgToZeroBase(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
|
||||||
NumberEval ne;
|
|
||||||
if(ev instanceof RefEval) {
|
|
||||||
// TODO - write junit to justify this
|
|
||||||
RefEval re = (RefEval) ev;
|
|
||||||
ne = (NumberEval) re.getInnerValueEval();
|
|
||||||
} else {
|
|
||||||
ne = (NumberEval)ev;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int)ne.getNumberValue() - 1;
|
ValueEval ev = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
|
||||||
|
int oneBasedVal = OperandResolver.coerceValueToInt(ev);
|
||||||
|
return oneBasedVal - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,30 +126,34 @@ public abstract class MultiOperandNumericFunction extends NumericFunction {
|
||||||
|
|
||||||
if (operand instanceof AreaEval) {
|
if (operand instanceof AreaEval) {
|
||||||
AreaEval ae = (AreaEval) operand;
|
AreaEval ae = (AreaEval) operand;
|
||||||
ValueEval[] values = ae.getValues();
|
|
||||||
DoubleList retval = new DoubleList();
|
DoubleList retval = new DoubleList();
|
||||||
for (int j=0, jSize=values.length; j<jSize; j++) {
|
int width = ae.getWidth();
|
||||||
/*
|
int height = ae.getHeight();
|
||||||
* TODO: For an AreaEval, we are constructing a RefEval
|
for (int rrIx=0; rrIx<height; rrIx++) {
|
||||||
* per element.
|
for (int rcIx=0; rcIx<width; rcIx++) {
|
||||||
* For now this is a tempfix solution since this may
|
ValueEval ve1 = ae.getRelativeValue(rrIx, rcIx);
|
||||||
* require a more generic fix at the level of
|
/*
|
||||||
* HSSFFormulaEvaluator where we store an array
|
* TODO: For an AreaEval, we are constructing a RefEval
|
||||||
* of RefEvals as the "values" array.
|
* per element.
|
||||||
*/
|
* For now this is a tempfix solution since this may
|
||||||
RefEval re = new Ref2DEval(null, values[j]);
|
* require a more generic fix at the level of
|
||||||
ValueEval ve = singleOperandEvaluate(re, srcRow, srcCol);
|
* HSSFFormulaEvaluator where we store an array
|
||||||
|
* of RefEvals as the "values" array.
|
||||||
if (ve instanceof NumericValueEval) {
|
*/
|
||||||
NumericValueEval nve = (NumericValueEval) ve;
|
RefEval re = new Ref2DEval(null, ve1);
|
||||||
retval.add(nve.getNumberValue());
|
ValueEval ve = singleOperandEvaluate(re, srcRow, srcCol);
|
||||||
}
|
|
||||||
else if (ve instanceof BlankEval) {
|
if (ve instanceof NumericValueEval) {
|
||||||
// note - blanks are ignored, so returned array will be smaller.
|
NumericValueEval nve = (NumericValueEval) ve;
|
||||||
}
|
retval.add(nve.getNumberValue());
|
||||||
else {
|
}
|
||||||
return null; // indicate to calling subclass that error occurred
|
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();
|
return retval.toArray();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
/*
|
/* ====================================================================
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
* this work for additional information regarding copyright ownership.
|
this work for additional information regarding copyright ownership.
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
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 not use this file except in compliance with
|
||||||
* the License. You may obtain a copy of the License at
|
the License. You may obtain a copy of the License at
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
limitations under the License.
|
||||||
*/
|
==================================================================== */
|
||||||
|
|
||||||
package org.apache.poi.hssf.record.formula.functions;
|
package org.apache.poi.hssf.record.formula.functions;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of Excel function SUMX2MY2()<p/>
|
* Implementation of Excel function SUMX2MY2()<p/>
|
||||||
*
|
*
|
||||||
|
@ -30,7 +31,13 @@ package org.apache.poi.hssf.record.formula.functions;
|
||||||
*/
|
*/
|
||||||
public final class Sumx2my2 extends XYNumericFunction {
|
public final class Sumx2my2 extends XYNumericFunction {
|
||||||
|
|
||||||
protected double evaluate(double[] xArray, double[] yArray) {
|
private static final Accumulator XSquaredMinusYSquaredAccumulator = new Accumulator() {
|
||||||
return MathX.sumx2my2(xArray, yArray);
|
public double accumulate(double x, double y) {
|
||||||
}
|
return x * x - y * y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
protected Accumulator createAccumulator() {
|
||||||
|
return XSquaredMinusYSquaredAccumulator;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
/*
|
/* ====================================================================
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
* this work for additional information regarding copyright ownership.
|
this work for additional information regarding copyright ownership.
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
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 not use this file except in compliance with
|
||||||
* the License. You may obtain a copy of the License at
|
the License. You may obtain a copy of the License at
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
limitations under the License.
|
||||||
*/
|
==================================================================== */
|
||||||
|
|
||||||
package org.apache.poi.hssf.record.formula.functions;
|
package org.apache.poi.hssf.record.formula.functions;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of Excel function SUMX2PY2()<p/>
|
* Implementation of Excel function SUMX2PY2()<p/>
|
||||||
*
|
*
|
||||||
|
@ -30,7 +31,13 @@ package org.apache.poi.hssf.record.formula.functions;
|
||||||
*/
|
*/
|
||||||
public final class Sumx2py2 extends XYNumericFunction {
|
public final class Sumx2py2 extends XYNumericFunction {
|
||||||
|
|
||||||
protected double evaluate(double[] xArray, double[] yArray) {
|
private static final Accumulator XSquaredPlusYSquaredAccumulator = new Accumulator() {
|
||||||
return MathX.sumx2py2(xArray, yArray);
|
public double accumulate(double x, double y) {
|
||||||
}
|
return x * x + y * y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
protected Accumulator createAccumulator() {
|
||||||
|
return XSquaredPlusYSquaredAccumulator;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
/*
|
/* ====================================================================
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
* this work for additional information regarding copyright ownership.
|
this work for additional information regarding copyright ownership.
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
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 not use this file except in compliance with
|
||||||
* the License. You may obtain a copy of the License at
|
the License. You may obtain a copy of the License at
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
limitations under the License.
|
||||||
*/
|
==================================================================== */
|
||||||
|
|
||||||
package org.apache.poi.hssf.record.formula.functions;
|
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 {
|
public final class Sumxmy2 extends XYNumericFunction {
|
||||||
|
|
||||||
protected double evaluate(double[] xArray, double[] yArray) {
|
private static final Accumulator XMinusYSquaredAccumulator = new Accumulator() {
|
||||||
return MathX.sumxmy2(xArray, yArray);
|
public double accumulate(double x, double y) {
|
||||||
}
|
double xmy = x - y;
|
||||||
|
return xmy * xmy;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
protected Accumulator createAccumulator() {
|
||||||
|
return XMinusYSquaredAccumulator;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
/*
|
/* ====================================================================
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
* this work for additional information regarding copyright ownership.
|
this work for additional information regarding copyright ownership.
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
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 not use this file except in compliance with
|
||||||
* the License. You may obtain a copy of the License at
|
the License. You may obtain a copy of the License at
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
limitations under the License.
|
||||||
*/
|
==================================================================== */
|
||||||
|
|
||||||
package org.apache.poi.hssf.record.formula.functions;
|
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.NumberEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.RefEval;
|
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.eval.ValueEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.functions.LookupUtils.ValueVector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public abstract class XYNumericFunction implements Function {
|
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 static abstract class ValueArray implements ValueVector {
|
||||||
private final double[] _yArray;
|
private final int _size;
|
||||||
|
protected ValueArray(int size) {
|
||||||
public DoubleArrayPair(double[] xArray, double[] yArray) {
|
_size = size;
|
||||||
_xArray = xArray;
|
|
||||||
_yArray = yArray;
|
|
||||||
}
|
}
|
||||||
public double[] getXArray() {
|
public ValueEval getItem(int index) {
|
||||||
return _xArray;
|
if (index < 0 || index > _size) {
|
||||||
|
throw new IllegalArgumentException("Specified index " + index
|
||||||
|
+ " is outside range (0.." + (_size - 1) + ")");
|
||||||
|
}
|
||||||
|
return getItemInternal(index);
|
||||||
}
|
}
|
||||||
public double[] getYArray() {
|
protected abstract ValueEval getItemInternal(int index);
|
||||||
return _yArray;
|
public final int getSize() {
|
||||||
|
return _size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class SingleCellValueArray extends ValueArray {
|
||||||
|
private final ValueEval _value;
|
||||||
|
public SingleCellValueArray(ValueEval value) {
|
||||||
|
super(1);
|
||||||
|
_value = value;
|
||||||
|
}
|
||||||
|
protected ValueEval getItemInternal(int index) {
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
|
private static final class RefValueArray extends ValueArray {
|
||||||
if(args.length != 2) {
|
private final RefEval _ref;
|
||||||
return ErrorEval.VALUE_INVALID;
|
public RefValueArray(RefEval ref) {
|
||||||
}
|
super(1);
|
||||||
|
_ref = ref;
|
||||||
double[][] values;
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
double result;
|
||||||
try {
|
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) {
|
} catch (EvaluationException e) {
|
||||||
return e.getErrorEval();
|
return e.getErrorEval();
|
||||||
}
|
}
|
||||||
if (values==null
|
if (Double.isNaN(result) || Double.isInfinite(result)) {
|
||||||
|| 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)) {
|
|
||||||
return ErrorEval.NUM_ERROR;
|
return ErrorEval.NUM_ERROR;
|
||||||
}
|
}
|
||||||
return new NumberEval(d);
|
return new NumberEval(result);
|
||||||
}
|
}
|
||||||
protected abstract double evaluate(double[] xArray, double[] yArray);
|
|
||||||
|
|
||||||
/**
|
private double evaluateInternal(ValueVector x, ValueVector y, int size)
|
||||||
* Returns a double array that contains values for the numeric cells
|
throws EvaluationException {
|
||||||
* from among the list of operands. Blanks and Blank equivalent cells
|
Accumulator acc = createAccumulator();
|
||||||
* are ignored. Error operands or cells containing operands of type
|
|
||||||
* that are considered invalid and would result in #VALUE! error in
|
// error handling is as if the x is fully evaluated before y
|
||||||
* excel cause this function to return null.
|
ErrorEval firstXerr = null;
|
||||||
*/
|
ErrorEval firstYerr = null;
|
||||||
private static double[][] getNumberArray(Eval[] xops, Eval[] yops) throws EvaluationException {
|
boolean accumlatedSome = false;
|
||||||
|
double result = 0.0;
|
||||||
// check for errors first: size mismatch, value errors in x, value errors in y
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
int nArrayItems = xops.length;
|
ValueEval vx = x.getItem(i);
|
||||||
if(nArrayItems != yops.length) {
|
ValueEval vy = y.getItem(i);
|
||||||
throw new EvaluationException(ErrorEval.NA);
|
if (vx instanceof ErrorEval) {
|
||||||
}
|
if (firstXerr == null) {
|
||||||
for (int i = 0; i < xops.length; i++) {
|
firstXerr = (ErrorEval) vx;
|
||||||
Eval eval = xops[i];
|
continue;
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < yops.length; i++) {
|
if (firstXerr != null) {
|
||||||
Eval eval = yops[i];
|
throw new EvaluationException(firstXerr);
|
||||||
if (eval instanceof ErrorEval) {
|
|
||||||
throw new EvaluationException((ErrorEval) eval);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (firstYerr != null) {
|
||||||
double[] xResult = new double[nArrayItems];
|
throw new EvaluationException(firstYerr);
|
||||||
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++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (!accumlatedSome) {
|
||||||
return new double[][] {
|
throw new EvaluationException(ErrorEval.DIV_ZERO);
|
||||||
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) {
|
return result;
|
||||||
throw new EvaluationException((ErrorEval) argY);
|
}
|
||||||
|
|
||||||
|
private static ValueVector createValueVector(Eval arg) throws EvaluationException {
|
||||||
|
if (arg instanceof ErrorEval) {
|
||||||
|
throw new EvaluationException((ErrorEval) arg);
|
||||||
}
|
}
|
||||||
|
if (arg instanceof AreaEval) {
|
||||||
Eval[] xEvals;
|
return new AreaValueArray((AreaEval) arg);
|
||||||
Eval[] yEvals;
|
|
||||||
if (argX instanceof AreaEval) {
|
|
||||||
AreaEval ae = (AreaEval) argX;
|
|
||||||
xEvals = ae.getValues();
|
|
||||||
} else {
|
|
||||||
xEvals = new Eval[] { argX, };
|
|
||||||
}
|
}
|
||||||
|
if (arg instanceof RefEval) {
|
||||||
if (argY instanceof AreaEval) {
|
return new RefValueArray((RefEval) arg);
|
||||||
AreaEval ae = (AreaEval) argY;
|
|
||||||
yEvals = ae.getValues();
|
|
||||||
} else {
|
|
||||||
yEvals = new Eval[] { argY, };
|
|
||||||
}
|
}
|
||||||
|
if (arg instanceof ValueEval) {
|
||||||
return getNumberArray(xEvals, yEvals);
|
return new SingleCellValueArray((ValueEval) arg);
|
||||||
}
|
}
|
||||||
|
throw new RuntimeException("Unexpected eval class (" + arg.getClass().getName() + ")");
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,6 @@ public final class TestSumproduct extends TestCase {
|
||||||
};
|
};
|
||||||
AreaEval aeA = EvalFactory.createAreaEval("A1:A2", aValues);
|
AreaEval aeA = EvalFactory.createAreaEval("A1:A2", aValues);
|
||||||
AreaEval aeB = EvalFactory.createAreaEval("B1:B2", new ValueEval[2]);
|
AreaEval aeB = EvalFactory.createAreaEval("B1:B2", new ValueEval[2]);
|
||||||
aeB.getValues()[1] = ErrorEval.REF_INVALID;
|
|
||||||
|
|
||||||
Eval[] args = { aeA, aeB, };
|
Eval[] args = { aeA, aeB, };
|
||||||
assertEquals(ErrorEval.REF_INVALID, invokeSumproduct(args));
|
assertEquals(ErrorEval.REF_INVALID, invokeSumproduct(args));
|
||||||
|
|
Loading…
Reference in New Issue