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:
Josh Micich 2008-09-11 07:16:20 +00:00
parent 104b2191d4
commit 2e6ca61fe7
7 changed files with 81 additions and 309 deletions

View File

@ -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

View File

@ -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
}
}

View File

@ -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());
}
}

View File

@ -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() {

View File

@ -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;
}
}

View File

@ -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;
}
};
}

View File

@ -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);
}