Refactoring MultiOperandNumericFunction - removed Ref2DEval.
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@694153 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
104b2191d4
commit
2e6ca61fe7
@ -420,8 +420,8 @@ public abstract class FunctionEval implements OperationEval {
|
||||
retval[359] = new Hyperlink(); // HYPERLINK
|
||||
retval[360] = new NotImplementedFunction(); // PHONETIC
|
||||
retval[361] = new Averagea(); // AVERAGEA
|
||||
retval[362] = new Maxa(); // MAXA
|
||||
retval[363] = new Mina(); // MINA
|
||||
retval[362] = MinaMaxa.MAXA;
|
||||
retval[363] = MinaMaxa.MINA;
|
||||
retval[364] = new Stdevpa(); // STDEVPA
|
||||
retval[365] = new Varpa(); // VARPA
|
||||
retval[366] = new Stdeva(); // STDEVA
|
||||
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* 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.eval;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.RefPtg;
|
||||
|
||||
/**
|
||||
* @author adeshmukh
|
||||
*
|
||||
*/
|
||||
public final class Ref2DEval implements RefEval {
|
||||
|
||||
private final ValueEval value;
|
||||
private final RefPtg delegate;
|
||||
|
||||
public Ref2DEval(RefPtg ptg, ValueEval ve) {
|
||||
if(ve == null) {
|
||||
throw new IllegalArgumentException("ve must not be null");
|
||||
}
|
||||
if(false && ptg == null) { // TODO - fix dodgy code in MultiOperandNumericFunction
|
||||
throw new IllegalArgumentException("ptg must not be null");
|
||||
}
|
||||
value = ve;
|
||||
delegate = ptg;
|
||||
}
|
||||
public ValueEval getInnerValueEval() {
|
||||
return value;
|
||||
}
|
||||
public int getRow() {
|
||||
return delegate.getRow();
|
||||
}
|
||||
public int getColumn() {
|
||||
return delegate.getColumn();
|
||||
}
|
||||
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
|
||||
throw new RuntimeException("should not be called"); // TODO - delete this whole class
|
||||
}
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
/* ====================================================================
|
||||
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.eval;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public final class ValueEvalToNumericXlator {
|
||||
|
||||
public static final int BLANK_IS_PARSED = 0x0001; // => blanks are not ignored, converted to 0
|
||||
|
||||
public static final int REF_BOOL_IS_PARSED = 0x0002;
|
||||
|
||||
private final int flags;
|
||||
|
||||
|
||||
public ValueEvalToNumericXlator(int flags) {
|
||||
|
||||
if (false) { // uncomment to see who is using this class
|
||||
System.err.println(new Throwable().getStackTrace()[1].getClassName() + "\t0x"
|
||||
+ Integer.toHexString(flags).toUpperCase());
|
||||
}
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* returned value can be either A NumericValueEval, BlankEval or ErrorEval.
|
||||
* The params can be either NumberEval, BoolEval, StringEval, or
|
||||
* RefEval
|
||||
* @param eval
|
||||
*/
|
||||
public ValueEval attemptXlateToNumeric(ValueEval eval) {
|
||||
|
||||
if (eval == null) {
|
||||
throw new IllegalArgumentException("eval must not be null");
|
||||
}
|
||||
|
||||
// most common case - least worries :)
|
||||
if (eval instanceof NumberEval) {
|
||||
return eval;
|
||||
}
|
||||
|
||||
if (eval instanceof BoolEval) {
|
||||
return eval;
|
||||
}
|
||||
|
||||
if (eval instanceof StringEval) {
|
||||
return xlateStringEval((StringEval) eval);
|
||||
}
|
||||
|
||||
if (eval instanceof RefEval) {
|
||||
return xlateRefEval((RefEval) eval);
|
||||
}
|
||||
|
||||
if (eval instanceof ErrorEval) {
|
||||
return eval;
|
||||
}
|
||||
|
||||
if (eval instanceof BlankEval) {
|
||||
return xlateBlankEval();
|
||||
}
|
||||
|
||||
// probably AreaEval? then not acceptable.
|
||||
throw new RuntimeException("Invalid ValueEval type passed for conversion: " + eval.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* no args are required since BlankEval has only one
|
||||
* instance. If flag is set, a zero
|
||||
* valued numbereval is returned, else BlankEval.INSTANCE
|
||||
* is returned.
|
||||
*/
|
||||
private ValueEval xlateBlankEval() {
|
||||
return ((flags & BLANK_IS_PARSED) > 0)
|
||||
? (ValueEval) NumberEval.ZERO
|
||||
: BlankEval.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* uses the relevant flags to decode the supplied RefVal
|
||||
* @param eval
|
||||
*/
|
||||
private ValueEval xlateRefEval(RefEval reval) {
|
||||
ValueEval eval = reval.getInnerValueEval();
|
||||
|
||||
// most common case - least worries :)
|
||||
if (eval instanceof NumberEval) {
|
||||
return eval;
|
||||
}
|
||||
|
||||
if (eval instanceof BoolEval) {
|
||||
return ((flags & REF_BOOL_IS_PARSED) > 0)
|
||||
? (ValueEval) eval
|
||||
: BlankEval.INSTANCE;
|
||||
}
|
||||
|
||||
if (eval instanceof StringEval) {
|
||||
// all ref strings are blanks
|
||||
return BlankEval.INSTANCE;
|
||||
}
|
||||
|
||||
if (eval instanceof ErrorEval) {
|
||||
return eval;
|
||||
}
|
||||
|
||||
if (eval instanceof BlankEval) {
|
||||
return xlateBlankEval();
|
||||
}
|
||||
|
||||
throw new RuntimeException("Invalid ValueEval type passed for conversion: ("
|
||||
+ eval.getClass().getName() + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* uses the relevant flags to decode the StringEval
|
||||
* @param eval
|
||||
*/
|
||||
private static ValueEval xlateStringEval(StringEval eval) {
|
||||
|
||||
String s = eval.getStringValue();
|
||||
Double d = OperandResolver.parseDouble(s);
|
||||
if(d == null) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
return new NumberEval(d.doubleValue());
|
||||
}
|
||||
}
|
@ -19,22 +19,17 @@ package org.apache.poi.hssf.record.formula.functions;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.EvaluationException;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public abstract class AggregateFunction extends MultiOperandNumericFunction {
|
||||
private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
|
||||
new ValueEvalToNumericXlator(0);
|
||||
|
||||
protected ValueEval attemptXlateToNumeric(ValueEval ve) {
|
||||
return DEFAULT_NUM_XLATOR.attemptXlateToNumeric(ve);
|
||||
protected AggregateFunction() {
|
||||
super(false, false);
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
public static final Function AVEDEV = new AggregateFunction() {
|
||||
|
@ -1,41 +0,0 @@
|
||||
/* ====================================================================
|
||||
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.ValueEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public final class Maxa extends MultiOperandNumericFunction {
|
||||
private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
|
||||
new ValueEvalToNumericXlator((short) (
|
||||
ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
|
||||
| ValueEvalToNumericXlator.BLANK_IS_PARSED
|
||||
));
|
||||
|
||||
protected ValueEval attemptXlateToNumeric(ValueEval ve) {
|
||||
return DEFAULT_NUM_XLATOR.attemptXlateToNumeric(ve);
|
||||
}
|
||||
|
||||
public double evaluate(double[] values) {
|
||||
return values.length > 0 ? MathX.max(values) : 0;
|
||||
}
|
||||
}
|
@ -17,25 +17,24 @@
|
||||
|
||||
package org.apache.poi.hssf.record.formula.functions;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public final class Mina extends MultiOperandNumericFunction {
|
||||
private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR =
|
||||
new ValueEvalToNumericXlator((short) (
|
||||
ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
|
||||
| ValueEvalToNumericXlator.BLANK_IS_PARSED
|
||||
));
|
||||
|
||||
protected ValueEval attemptXlateToNumeric(ValueEval ve) {
|
||||
return DEFAULT_NUM_XLATOR.attemptXlateToNumeric(ve);
|
||||
public abstract class MinaMaxa extends MultiOperandNumericFunction {
|
||||
|
||||
protected MinaMaxa() {
|
||||
super(true, true);
|
||||
}
|
||||
|
||||
public double evaluate(double[] values) {
|
||||
return values.length > 0 ? MathX.min(values) : 0;
|
||||
}
|
||||
public static final Function MAXA = new MinaMaxa() {
|
||||
protected double evaluate(double[] values) {
|
||||
return values.length > 0 ? MathX.max(values) : 0;
|
||||
}
|
||||
};
|
||||
public static final Function MINA = new MinaMaxa() {
|
||||
protected double evaluate(double[] values) {
|
||||
return values.length > 0 ? MathX.min(values) : 0;
|
||||
}
|
||||
};
|
||||
}
|
@ -19,13 +19,14 @@ 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.BlankEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.BoolEval;
|
||||
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.EvaluationException;
|
||||
import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.OperandResolver;
|
||||
import org.apache.poi.hssf.record.formula.eval.RefEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.StringEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
|
||||
/**
|
||||
@ -35,6 +36,16 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
* where the order of operands does not matter
|
||||
*/
|
||||
public abstract class MultiOperandNumericFunction implements Function {
|
||||
|
||||
private final boolean _isReferenceBoolCounted;
|
||||
private final boolean _isBlankCounted;
|
||||
|
||||
protected MultiOperandNumericFunction(boolean isReferenceBoolCounted, boolean isBlankCounted) {
|
||||
_isReferenceBoolCounted = isReferenceBoolCounted;
|
||||
_isBlankCounted = isBlankCounted;
|
||||
}
|
||||
|
||||
|
||||
static final double[] EMPTY_DOUBLE_ARRAY = { };
|
||||
|
||||
private static class DoubleList {
|
||||
@ -74,7 +85,7 @@ public abstract class MultiOperandNumericFunction implements Function {
|
||||
private static final int DEFAULT_MAX_NUM_OPERANDS = 30;
|
||||
|
||||
public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
|
||||
|
||||
|
||||
double d;
|
||||
try {
|
||||
double[] values = getNumberArray(args);
|
||||
@ -82,16 +93,16 @@ public abstract class MultiOperandNumericFunction implements Function {
|
||||
} catch (EvaluationException e) {
|
||||
return e.getErrorEval();
|
||||
}
|
||||
|
||||
|
||||
if (Double.isNaN(d) || Double.isInfinite(d))
|
||||
return ErrorEval.NUM_ERROR;
|
||||
|
||||
|
||||
return new NumberEval(d);
|
||||
}
|
||||
|
||||
protected abstract double evaluate(double[] values) throws EvaluationException;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Maximum number of operands accepted by this function.
|
||||
* Subclasses may override to change default value.
|
||||
@ -132,54 +143,58 @@ public abstract class MultiOperandNumericFunction implements Function {
|
||||
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 = attemptXlateToNumeric(re);
|
||||
if (ve instanceof ErrorEval) {
|
||||
throw new EvaluationException((ErrorEval)ve);
|
||||
}
|
||||
if (ve instanceof BlankEval) {
|
||||
// note - blanks are ignored, so returned array will be smaller.
|
||||
continue;
|
||||
}
|
||||
if (ve instanceof NumericValueEval) {
|
||||
NumericValueEval nve = (NumericValueEval) ve;
|
||||
temp.add(nve.getNumberValue());
|
||||
} else {
|
||||
throw new RuntimeException("Unexpected value class (" + ve.getClass().getName() + ")");
|
||||
}
|
||||
ValueEval ve = ae.getRelativeValue(rrIx, rcIx);
|
||||
collectValue(ve, true, temp);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// for ValueEvals other than AreaEval
|
||||
ValueEval ve = attemptXlateToNumeric((ValueEval) operand);
|
||||
|
||||
if (ve instanceof NumericValueEval) {
|
||||
NumericValueEval nve = (NumericValueEval) ve;
|
||||
temp.add(nve.getNumberValue());
|
||||
if (operand instanceof RefEval) {
|
||||
RefEval re = (RefEval) operand;
|
||||
collectValue(re.getInnerValueEval(), true, temp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ve instanceof BlankEval) {
|
||||
// ignore blanks
|
||||
collectValue((ValueEval)operand, false, temp);
|
||||
}
|
||||
private void collectValue(ValueEval ve, boolean isViaReference, DoubleList temp) throws EvaluationException {
|
||||
if (ve == null) {
|
||||
throw new IllegalArgumentException("ve must not be null");
|
||||
}
|
||||
if (ve instanceof NumberEval) {
|
||||
NumberEval ne = (NumberEval) ve;
|
||||
temp.add(ne.getNumberValue());
|
||||
return;
|
||||
}
|
||||
if (ve instanceof ErrorEval) {
|
||||
throw new EvaluationException((ErrorEval)ve);
|
||||
throw new EvaluationException((ErrorEval) ve);
|
||||
}
|
||||
throw new RuntimeException("Unexpected value class (" + ve.getClass().getName() + ")");
|
||||
if (ve instanceof StringEval) {
|
||||
if (isViaReference) {
|
||||
// ignore all ref strings
|
||||
return;
|
||||
}
|
||||
String s = ((StringEval) ve).getStringValue();
|
||||
Double d = OperandResolver.parseDouble(s);
|
||||
if(d == null) {
|
||||
throw new EvaluationException(ErrorEval.VALUE_INVALID);
|
||||
}
|
||||
temp.add(d.doubleValue());
|
||||
return;
|
||||
}
|
||||
if (ve instanceof BoolEval) {
|
||||
if (!isViaReference || _isReferenceBoolCounted) {
|
||||
BoolEval boolEval = (BoolEval) ve;
|
||||
temp.add(boolEval.getNumberValue());
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (ve == BlankEval.INSTANCE) {
|
||||
if (_isBlankCounted) {
|
||||
temp.add(0.0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
throw new RuntimeException("Invalid ValueEval type passed for conversion: ("
|
||||
+ ve.getClass() + ")");
|
||||
}
|
||||
|
||||
|
||||
protected abstract ValueEval attemptXlateToNumeric(ValueEval ve);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user