Removing calls to AreaEval.getValues()
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@690094 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
adff0508bb
commit
adc8469ebc
@ -30,46 +30,46 @@ public interface AreaEval extends ValueEval {
|
|||||||
* returns the 0-based index of the first row in
|
* returns the 0-based index of the first row in
|
||||||
* this area.
|
* this area.
|
||||||
*/
|
*/
|
||||||
public int getFirstRow();
|
int getFirstRow();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the 0-based index of the last row in
|
* returns the 0-based index of the last row in
|
||||||
* this area.
|
* this area.
|
||||||
*/
|
*/
|
||||||
public int getLastRow();
|
int getLastRow();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the 0-based index of the first col in
|
* returns the 0-based index of the first col in
|
||||||
* this area.
|
* this area.
|
||||||
*/
|
*/
|
||||||
public int getFirstColumn();
|
int getFirstColumn();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the 0-based index of the last col in
|
* returns the 0-based index of the last col in
|
||||||
* this area.
|
* this area.
|
||||||
*/
|
*/
|
||||||
public int getLastColumn();
|
int getLastColumn();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns true if the Area's start and end row indexes
|
* returns true if the Area's start and end row indexes
|
||||||
* are same. This result of this method should agree
|
* are same. This result of this method should agree
|
||||||
* with getFirstRow() == getLastRow().
|
* with getFirstRow() == getLastRow().
|
||||||
*/
|
*/
|
||||||
public boolean isRow();
|
boolean isRow();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns true if the Area's start and end col indexes
|
* returns true if the Area's start and end col indexes
|
||||||
* are same. This result of this method should agree
|
* are same. This result of this method should agree
|
||||||
* with getFirstColumn() == getLastColumn().
|
* with getFirstColumn() == getLastColumn().
|
||||||
*/
|
*/
|
||||||
public boolean isColumn();
|
boolean isColumn();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The array of values in this area. Although the area
|
* The array of values in this area. Although the area
|
||||||
* maybe 1D (ie. isRow() or isColumn() returns true) or 2D
|
* maybe 1D (ie. isRow() or isColumn() returns true) or 2D
|
||||||
* the returned array is 1D.
|
* the returned array is 1D.
|
||||||
*/
|
*/
|
||||||
public ValueEval[] getValues();
|
ValueEval[] getValues();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the ValueEval from the values array at the specified
|
* returns the ValueEval from the values array at the specified
|
||||||
@ -80,7 +80,7 @@ public interface AreaEval extends ValueEval {
|
|||||||
* @param row
|
* @param row
|
||||||
* @param col
|
* @param col
|
||||||
*/
|
*/
|
||||||
public ValueEval getValueAt(int row, int col);
|
ValueEval getValueAt(int row, int col);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns true if the cell at row and col specified
|
* returns true if the cell at row and col specified
|
||||||
@ -89,17 +89,21 @@ public interface AreaEval extends ValueEval {
|
|||||||
* @param row
|
* @param row
|
||||||
* @param col
|
* @param col
|
||||||
*/
|
*/
|
||||||
public boolean contains(int row, int col);
|
boolean contains(int row, int col);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns true if the specified col is in range
|
* returns true if the specified col is in range
|
||||||
* @param col
|
* @param col
|
||||||
*/
|
*/
|
||||||
public boolean containsColumn(short col);
|
boolean containsColumn(short col);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns true if the specified row is in range
|
* returns true if the specified row is in range
|
||||||
* @param row
|
* @param row
|
||||||
*/
|
*/
|
||||||
public boolean containsRow(int row);
|
boolean containsRow(int row);
|
||||||
|
|
||||||
|
int getWidth();
|
||||||
|
int getHeight();
|
||||||
|
ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex);
|
||||||
}
|
}
|
||||||
|
@ -94,9 +94,7 @@ abstract class AreaEvalBase implements AreaEval {
|
|||||||
throw new IllegalArgumentException("Specified column index (" + col
|
throw new IllegalArgumentException("Specified column index (" + col
|
||||||
+ ") is outside the allowed range (" + _firstColumn + ".." + col + ")");
|
+ ") is outside the allowed range (" + _firstColumn + ".." + col + ")");
|
||||||
}
|
}
|
||||||
|
return getRelativeValue(rowOffsetIx, colOffsetIx);
|
||||||
int index = rowOffsetIx * _nColumns + colOffsetIx;
|
|
||||||
return _values[index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean contains(int row, int col) {
|
public final boolean contains(int row, int col) {
|
||||||
@ -119,4 +117,16 @@ abstract class AreaEvalBase implements AreaEval {
|
|||||||
public final boolean isRow() {
|
public final boolean isRow() {
|
||||||
return _firstRow == _lastRow;
|
return _firstRow == _lastRow;
|
||||||
}
|
}
|
||||||
|
public int getHeight() {
|
||||||
|
return _lastRow-_firstRow+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
|
||||||
|
int index = relativeRowIndex * _nColumns + relativeColumnIndex;
|
||||||
|
return _values[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWidth() {
|
||||||
|
return _lastColumn-_firstColumn+1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,7 @@ public final class OperandResolver {
|
|||||||
|
|
||||||
if (ae.isColumn()) {
|
if (ae.isColumn()) {
|
||||||
if(ae.isRow()) {
|
if(ae.isRow()) {
|
||||||
return ae.getValues()[0];
|
return ae.getRelativeValue(0, 0);
|
||||||
}
|
}
|
||||||
if(!ae.containsRow(srcCellRow)) {
|
if(!ae.containsRow(srcCellRow)) {
|
||||||
throw EvaluationException.invalidValue();
|
throw EvaluationException.invalidValue();
|
||||||
@ -274,4 +274,51 @@ public final class OperandResolver {
|
|||||||
}
|
}
|
||||||
throw new IllegalArgumentException("Unexpected eval class (" + ve.getClass().getName() + ")");
|
throw new IllegalArgumentException("Unexpected eval class (" + ve.getClass().getName() + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return <code>null</code> to represent blank values
|
||||||
|
* @throws EvaluationException if ve is an ErrorEval, or if a string value cannot be converted
|
||||||
|
*/
|
||||||
|
public static Boolean coerceValueToBoolean(ValueEval ve, boolean stringsAreBlanks) throws EvaluationException {
|
||||||
|
|
||||||
|
if (ve == null || ve instanceof BlankEval) {
|
||||||
|
// TODO - remove 've == null' condition once AreaEval is fixed
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (ve instanceof BoolEval) {
|
||||||
|
return Boolean.valueOf(((BoolEval) ve).getBooleanValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ve instanceof BlankEval) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ve instanceof StringEval) {
|
||||||
|
if (stringsAreBlanks) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String str = ((StringEval) ve).getStringValue();
|
||||||
|
if (str.equalsIgnoreCase("true")) {
|
||||||
|
return Boolean.TRUE;
|
||||||
|
}
|
||||||
|
if (str.equalsIgnoreCase("false")) {
|
||||||
|
return Boolean.FALSE;
|
||||||
|
}
|
||||||
|
// else - string cannot be converted to boolean
|
||||||
|
throw new EvaluationException(ErrorEval.VALUE_INVALID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ve instanceof NumericValueEval) {
|
||||||
|
NumericValueEval ne = (NumericValueEval) ve;
|
||||||
|
double d = ne.getNumberValue();
|
||||||
|
if (Double.isNaN(d)) {
|
||||||
|
throw new EvaluationException(ErrorEval.VALUE_INVALID);
|
||||||
|
}
|
||||||
|
return Boolean.valueOf(d != 0);
|
||||||
|
}
|
||||||
|
if (ve instanceof ErrorEval) {
|
||||||
|
throw new EvaluationException((ErrorEval) ve);
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Unexpected eval (" + ve.getClass().getName() + ")");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,85 +1,32 @@
|
|||||||
/*
|
/* ====================================================================
|
||||||
* 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.
|
||||||
*/
|
==================================================================== */
|
||||||
/*
|
|
||||||
* Created on May 9, 2005
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
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.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.StringEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
|
||||||
|
|
||||||
public class And extends BooleanFunction {
|
|
||||||
|
|
||||||
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
|
|
||||||
ValueEval retval = null;
|
|
||||||
boolean b = true;
|
|
||||||
boolean atleastOneNonBlank = false;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Note: do not abort the loop if b is false, since we could be
|
|
||||||
* dealing with errorevals later.
|
|
||||||
*/
|
*/
|
||||||
outer:
|
public final class And extends BooleanFunction {
|
||||||
for (int i=0, iSize=operands.length; i<iSize; i++) {
|
|
||||||
if (operands[i] instanceof AreaEval) {
|
protected boolean getInitialResultValue() {
|
||||||
AreaEval ae = (AreaEval) operands[i];
|
return true;
|
||||||
ValueEval[] values = ae.getValues();
|
|
||||||
for (int j=0, jSize=values.length; j<jSize; j++) {
|
|
||||||
ValueEval tempVe = singleOperandEvaluate(values[j], srcRow, srcCol, true);
|
|
||||||
if (tempVe instanceof BoolEval) {
|
|
||||||
b = b && ((BoolEval) tempVe).getBooleanValue();
|
|
||||||
atleastOneNonBlank = true;
|
|
||||||
}
|
|
||||||
else if (tempVe instanceof ErrorEval) {
|
|
||||||
retval = tempVe;
|
|
||||||
break outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ValueEval tempVe = singleOperandEvaluate(operands[i], srcRow, srcCol, false);
|
|
||||||
if (tempVe instanceof BoolEval) {
|
|
||||||
b = b && ((BoolEval) tempVe).getBooleanValue();
|
|
||||||
atleastOneNonBlank = true;
|
|
||||||
}
|
|
||||||
else if (tempVe instanceof StringEval) {
|
|
||||||
retval = ErrorEval.VALUE_INVALID;
|
|
||||||
}
|
|
||||||
else if (tempVe instanceof ErrorEval) {
|
|
||||||
retval = tempVe;
|
|
||||||
break outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!atleastOneNonBlank) {
|
protected boolean partialEvaluate(boolean cumulativeResult, boolean currentValue) {
|
||||||
retval = ErrorEval.VALUE_INVALID;
|
return cumulativeResult && currentValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retval == null) { // if no error
|
|
||||||
retval = b ? BoolEval.TRUE : BoolEval.FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,100 +1,108 @@
|
|||||||
/*
|
/* ====================================================================
|
||||||
* 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.
|
||||||
*/
|
==================================================================== */
|
||||||
/*
|
|
||||||
* Created on May 15, 2005
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package org.apache.poi.hssf.record.formula.functions;
|
package org.apache.poi.hssf.record.formula.functions;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.BlankEval;
|
import org.apache.poi.hssf.record.formula.eval.AreaEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.BoolEval;
|
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.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.NumericValueEval;
|
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.RefEval;
|
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;
|
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
|
||||||
* Here are the general rules concerning Boolean functions:
|
* Here are the general rules concerning Boolean functions:
|
||||||
* <ol>
|
* <ol>
|
||||||
* <li> Blanks are not either true or false
|
* <li> Blanks are ignored (not either true or false) </li>
|
||||||
* <li> Strings are not either true or false (even strings "true"
|
* <li> Strings are ignored if part of an area ref or cell ref, otherwise they must be 'true' or 'false'</li>
|
||||||
* or "TRUE" or "0" etc.)
|
* <li> Numbers: 0 is false. Any other number is TRUE </li>
|
||||||
* <li> Numbers: 0 is false. Any other number is TRUE.
|
* <li> Areas: *all* cells in area are evaluated according to the above rules</li>
|
||||||
* <li> References are evaluated and above rules apply.
|
|
||||||
* <li> Areas: Individual cells in area are evaluated and checked to
|
|
||||||
* see if they are blanks, strings etc.
|
|
||||||
* </ol>
|
* </ol>
|
||||||
|
*
|
||||||
|
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||||
*/
|
*/
|
||||||
public abstract class BooleanFunction implements Function {
|
public abstract class BooleanFunction implements Function {
|
||||||
|
|
||||||
protected ValueEval singleOperandEvaluate(Eval eval, int srcRow, short srcCol, boolean stringsAreBlanks) {
|
public final Eval evaluate(Eval[] args, int srcRow, short srcCol) {
|
||||||
ValueEval retval;
|
if (args.length < 1) {
|
||||||
|
return ErrorEval.VALUE_INVALID;
|
||||||
if (eval instanceof RefEval) {
|
|
||||||
RefEval re = (RefEval) eval;
|
|
||||||
ValueEval ve = re.getInnerValueEval();
|
|
||||||
retval = internalResolve(ve, true);
|
|
||||||
}
|
}
|
||||||
else {
|
boolean boolResult;
|
||||||
retval = internalResolve(eval, stringsAreBlanks);
|
try {
|
||||||
|
boolResult = calculate(args);
|
||||||
|
} catch (EvaluationException e) {
|
||||||
|
return e.getErrorEval();
|
||||||
|
}
|
||||||
|
return BoolEval.valueOf(boolResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
private boolean calculate(Eval[] args) throws EvaluationException {
|
||||||
|
|
||||||
|
boolean result = getInitialResultValue();
|
||||||
|
boolean atleastOneNonBlank = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: no short-circuit boolean loop exit because any ErrorEvals will override the result
|
||||||
|
*/
|
||||||
|
for (int i=0, iSize=args.length; i<iSize; i++) {
|
||||||
|
Eval arg = args[i];
|
||||||
|
if (arg instanceof AreaEval) {
|
||||||
|
AreaEval ae = (AreaEval) arg;
|
||||||
|
int height = ae.getHeight();
|
||||||
|
int width = ae.getWidth();
|
||||||
|
for (int rrIx=0; rrIx<height; rrIx++) {
|
||||||
|
for (int rcIx=0; rcIx<width; rcIx++) {
|
||||||
|
ValueEval ve = ae.getRelativeValue(rrIx, rcIx);
|
||||||
|
Boolean tempVe = OperandResolver.coerceValueToBoolean(ve, true);
|
||||||
|
if (tempVe != null) {
|
||||||
|
result = partialEvaluate(result, tempVe.booleanValue());
|
||||||
|
atleastOneNonBlank = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Boolean tempVe;
|
||||||
|
if (arg instanceof RefEval) {
|
||||||
|
ValueEval ve = ((RefEval) arg).getInnerValueEval();
|
||||||
|
tempVe = OperandResolver.coerceValueToBoolean(ve, true);
|
||||||
|
} else if (arg instanceof ValueEval) {
|
||||||
|
ValueEval ve = (ValueEval) arg;
|
||||||
|
tempVe = OperandResolver.coerceValueToBoolean(ve, false);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Unexpected eval (" + arg.getClass().getName() + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueEval internalResolve(Eval ve, boolean stringsAreBlanks) {
|
|
||||||
ValueEval retval = null;
|
|
||||||
|
|
||||||
// blankeval is returned as is
|
if (tempVe != null) {
|
||||||
if (ve instanceof BlankEval) {
|
result = partialEvaluate(result, tempVe.booleanValue());
|
||||||
retval = BlankEval.INSTANCE;
|
atleastOneNonBlank = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stringeval
|
if (!atleastOneNonBlank) {
|
||||||
else if (ve instanceof StringEval) {
|
throw new EvaluationException(ErrorEval.VALUE_INVALID);
|
||||||
retval = stringsAreBlanks ? (ValueEval) BlankEval.INSTANCE : (StringEval) ve;
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bools are bools :)
|
|
||||||
else if (ve instanceof BoolEval) {
|
|
||||||
retval = (BoolEval) ve;
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert numbers to bool
|
protected abstract boolean getInitialResultValue();
|
||||||
else if (ve instanceof NumericValueEval) {
|
protected abstract boolean partialEvaluate(boolean cumulativeResult, boolean currentValue);
|
||||||
NumericValueEval ne = (NumericValueEval) ve;
|
|
||||||
double d = ne.getNumberValue();
|
|
||||||
retval = Double.isNaN(d)
|
|
||||||
? (ValueEval) ErrorEval.VALUE_INVALID
|
|
||||||
: (d != 0)
|
|
||||||
? BoolEval.TRUE
|
|
||||||
: BoolEval.FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// since refevals
|
|
||||||
else {
|
|
||||||
retval = ErrorEval.VALUE_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,27 @@
|
|||||||
/*
|
/* ====================================================================
|
||||||
* 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.
|
||||||
*/
|
==================================================================== */
|
||||||
/*
|
|
||||||
* Created on May 9, 2005
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
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.BlankEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.BoolEval;
|
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.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.StringEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||||
|
|
||||||
|
|
||||||
@ -37,87 +31,21 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
|||||||
* (treated as a boolean). If the specified arg is a number,
|
* (treated as a boolean). If the specified arg is a number,
|
||||||
* then it is true <=> 'number is non-zero'
|
* then it is true <=> 'number is non-zero'
|
||||||
*/
|
*/
|
||||||
public class Not extends BooleanFunction {
|
public final class Not implements Function {
|
||||||
|
|
||||||
|
public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
|
||||||
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
|
if (args.length != 1) {
|
||||||
ValueEval retval = null;
|
return ErrorEval.VALUE_INVALID;
|
||||||
boolean b = true;
|
|
||||||
ValueEval tempVe = null;
|
|
||||||
|
|
||||||
switch (operands.length) {
|
|
||||||
default:
|
|
||||||
retval = ErrorEval.VALUE_INVALID;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (operands[0] instanceof AreaEval) {
|
|
||||||
AreaEval ae = (AreaEval) operands[0];
|
|
||||||
if (ae.isRow() && ae.containsColumn(srcCol)) {
|
|
||||||
ValueEval ve = ae.getValueAt(ae.getFirstRow(), srcCol);
|
|
||||||
tempVe = singleOperandEvaluate(ve);
|
|
||||||
} else if (ae.isColumn() && ae.containsRow(srcRow)) {
|
|
||||||
ValueEval ve = ae.getValueAt(srcRow, ae.getFirstColumn());
|
|
||||||
tempVe = singleOperandEvaluate(ve);
|
|
||||||
} else {
|
|
||||||
retval = ErrorEval.VALUE_INVALID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
tempVe = singleOperandEvaluate(operands[0]);
|
|
||||||
if (tempVe instanceof StringEval) {
|
|
||||||
retval = ErrorEval.VALUE_INVALID;
|
|
||||||
}
|
|
||||||
else if (tempVe instanceof ErrorEval) {
|
|
||||||
retval = tempVe;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
boolean boolArgVal;
|
||||||
|
try {
|
||||||
|
ValueEval ve = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
|
||||||
|
Boolean b = OperandResolver.coerceValueToBoolean(ve, false);
|
||||||
|
boolArgVal = b == null ? false : b.booleanValue();
|
||||||
|
} catch (EvaluationException e) {
|
||||||
|
return e.getErrorEval();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retval == null) { // if no error
|
return BoolEval.valueOf(!boolArgVal);
|
||||||
if (tempVe instanceof BoolEval) {
|
|
||||||
b = b && ((BoolEval) tempVe).getBooleanValue();
|
|
||||||
}
|
|
||||||
else if (tempVe instanceof StringEval) {
|
|
||||||
retval = ErrorEval.VALUE_INVALID;
|
|
||||||
}
|
|
||||||
else if (tempVe instanceof ErrorEval) {
|
|
||||||
retval = tempVe;
|
|
||||||
}
|
|
||||||
retval = b ? BoolEval.FALSE : BoolEval.TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected ValueEval singleOperandEvaluate(Eval ve) {
|
|
||||||
ValueEval retval = ErrorEval.VALUE_INVALID;
|
|
||||||
if (ve instanceof RefEval) {
|
|
||||||
RefEval re = (RefEval) ve;
|
|
||||||
retval = singleOperandEvaluate(re.getInnerValueEval());
|
|
||||||
}
|
|
||||||
else if (ve instanceof BoolEval) {
|
|
||||||
retval = (BoolEval) ve;
|
|
||||||
}
|
|
||||||
else if (ve instanceof NumberEval) {
|
|
||||||
NumberEval ne = (NumberEval) ve;
|
|
||||||
retval = ne.getNumberValue() != 0 ? BoolEval.TRUE : BoolEval.FALSE;
|
|
||||||
}
|
|
||||||
else if (ve instanceof StringEval) {
|
|
||||||
StringEval se = (StringEval) ve;
|
|
||||||
String str = se.getStringValue();
|
|
||||||
retval = str.equalsIgnoreCase("true")
|
|
||||||
? BoolEval.TRUE
|
|
||||||
: str.equalsIgnoreCase("false")
|
|
||||||
? BoolEval.FALSE
|
|
||||||
: (ValueEval) ErrorEval.VALUE_INVALID;
|
|
||||||
}
|
|
||||||
else if (ve instanceof BlankEval) {
|
|
||||||
retval = BoolEval.FALSE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
retval = ErrorEval.VALUE_INVALID;
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,81 +1,32 @@
|
|||||||
/*
|
/* ====================================================================
|
||||||
* 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.
|
||||||
*/
|
==================================================================== */
|
||||||
/*
|
|
||||||
* Created on May 9, 2005
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
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.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.ValueEval;
|
|
||||||
|
|
||||||
public class Or extends BooleanFunction {
|
|
||||||
|
|
||||||
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
|
|
||||||
ValueEval retval = null;
|
|
||||||
boolean b = false;
|
|
||||||
boolean atleastOneNonBlank = false;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Note: do not abort the loop if b is true, since we could be
|
|
||||||
* dealing with errorevals later.
|
|
||||||
*/
|
*/
|
||||||
outer:
|
public final class Or extends BooleanFunction {
|
||||||
for (int i=0, iSize=operands.length; i<iSize; i++) {
|
|
||||||
if (operands[i] instanceof AreaEval) {
|
protected boolean getInitialResultValue() {
|
||||||
AreaEval ae = (AreaEval) operands[i];
|
return false;
|
||||||
ValueEval[] values = ae.getValues();
|
|
||||||
for (int j=0, jSize=values.length; j<jSize; j++) {
|
|
||||||
ValueEval tempVe = singleOperandEvaluate(values[j], srcRow, srcCol, true);
|
|
||||||
if (tempVe instanceof BoolEval) {
|
|
||||||
b = b || ((BoolEval) tempVe).getBooleanValue();
|
|
||||||
atleastOneNonBlank = true;
|
|
||||||
}
|
|
||||||
else if (tempVe instanceof ErrorEval) {
|
|
||||||
retval = tempVe;
|
|
||||||
break outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ValueEval tempVe = singleOperandEvaluate(operands[i], srcRow, srcCol, false);
|
|
||||||
if (tempVe instanceof BoolEval) {
|
|
||||||
b = b || ((BoolEval) tempVe).getBooleanValue();
|
|
||||||
atleastOneNonBlank = true;
|
|
||||||
}
|
|
||||||
else if (tempVe instanceof ErrorEval) {
|
|
||||||
retval = tempVe;
|
|
||||||
break outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!atleastOneNonBlank) {
|
protected boolean partialEvaluate(boolean cumulativeResult, boolean currentValue) {
|
||||||
retval = ErrorEval.VALUE_INVALID;
|
return cumulativeResult || currentValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retval == null) { // if no error
|
|
||||||
retval = b ? BoolEval.TRUE : BoolEval.FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ 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.BlankEval;
|
||||||
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.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.NumericValueEval;
|
import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.RefEval;
|
import org.apache.poi.hssf.record.formula.eval.RefEval;
|
||||||
@ -53,16 +54,6 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
|||||||
*/
|
*/
|
||||||
public final class Sumproduct implements Function {
|
public final class Sumproduct implements Function {
|
||||||
|
|
||||||
private static final class EvalEx extends Exception {
|
|
||||||
private final ErrorEval _error;
|
|
||||||
|
|
||||||
public EvalEx(ErrorEval error) {
|
|
||||||
_error = error;
|
|
||||||
}
|
|
||||||
public ErrorEval getError() {
|
|
||||||
return _error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
|
public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
|
||||||
|
|
||||||
@ -86,14 +77,14 @@ public final class Sumproduct implements Function {
|
|||||||
}
|
}
|
||||||
return evaluateAreaSumProduct(args);
|
return evaluateAreaSumProduct(args);
|
||||||
}
|
}
|
||||||
} catch (EvalEx e) {
|
} catch (EvaluationException e) {
|
||||||
return e.getError();
|
return e.getErrorEval();
|
||||||
}
|
}
|
||||||
throw new RuntimeException("Invalid arg type for SUMPRODUCT: ("
|
throw new RuntimeException("Invalid arg type for SUMPRODUCT: ("
|
||||||
+ firstArg.getClass().getName() + ")");
|
+ firstArg.getClass().getName() + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Eval evaluateSingleProduct(Eval[] evalArgs) throws EvalEx {
|
private static Eval evaluateSingleProduct(Eval[] evalArgs) throws EvaluationException {
|
||||||
int maxN = evalArgs.length;
|
int maxN = evalArgs.length;
|
||||||
|
|
||||||
double term = 1D;
|
double term = 1D;
|
||||||
@ -104,7 +95,7 @@ public final class Sumproduct implements Function {
|
|||||||
return new NumberEval(term);
|
return new NumberEval(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
private double getScalarValue(Eval arg) throws EvalEx {
|
private static double getScalarValue(Eval arg) throws EvaluationException {
|
||||||
|
|
||||||
Eval eval;
|
Eval eval;
|
||||||
if (arg instanceof RefEval) {
|
if (arg instanceof RefEval) {
|
||||||
@ -121,9 +112,9 @@ public final class Sumproduct implements Function {
|
|||||||
AreaEval ae = (AreaEval) eval;
|
AreaEval ae = (AreaEval) eval;
|
||||||
// an area ref can work as a scalar value if it is 1x1
|
// an area ref can work as a scalar value if it is 1x1
|
||||||
if(!ae.isColumn() || !ae.isRow()) {
|
if(!ae.isColumn() || !ae.isRow()) {
|
||||||
throw new EvalEx(ErrorEval.VALUE_INVALID);
|
throw new EvaluationException(ErrorEval.VALUE_INVALID);
|
||||||
}
|
}
|
||||||
eval = ae.getValues()[0];
|
eval = ae.getRelativeValue(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(eval instanceof ValueEval)) {
|
if (!(eval instanceof ValueEval)) {
|
||||||
@ -134,7 +125,7 @@ public final class Sumproduct implements Function {
|
|||||||
return getProductTerm((ValueEval) eval, true);
|
return getProductTerm((ValueEval) eval, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Eval evaluateAreaSumProduct(Eval[] evalArgs) throws EvalEx {
|
private static Eval evaluateAreaSumProduct(Eval[] evalArgs) throws EvaluationException {
|
||||||
int maxN = evalArgs.length;
|
int maxN = evalArgs.length;
|
||||||
AreaEval[] args = new AreaEval[maxN];
|
AreaEval[] args = new AreaEval[maxN];
|
||||||
try {
|
try {
|
||||||
@ -147,23 +138,27 @@ public final class Sumproduct implements Function {
|
|||||||
|
|
||||||
AreaEval firstArg = args[0];
|
AreaEval firstArg = args[0];
|
||||||
|
|
||||||
int height = firstArg.getLastRow() - firstArg.getFirstRow() + 1;
|
int height = firstArg.getHeight();
|
||||||
int width = firstArg.getLastColumn() - firstArg.getFirstColumn() + 1; // TODO - junit
|
int width = firstArg.getWidth(); // TODO - junit
|
||||||
|
|
||||||
|
// first check dimensions
|
||||||
|
if (!areasAllSameSize(args, height, width)) {
|
||||||
double[][][] elements = new double[maxN][][];
|
// normally this results in #VALUE!,
|
||||||
|
// but errors in individual cells take precedence
|
||||||
for (int n = 0; n < maxN; n++) {
|
for (int i = 1; i < args.length; i++) {
|
||||||
elements[n] = evaluateArea(args[n], height, width);
|
throwFirstError(args[i]);
|
||||||
}
|
}
|
||||||
|
return ErrorEval.VALUE_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
double acc = 0;
|
double acc = 0;
|
||||||
|
|
||||||
for(int r=0; r<height; r++) {
|
for (int rrIx=0; rrIx<height; rrIx++) {
|
||||||
for(int c=0; c<width; c++) {
|
for (int rcIx=0; rcIx<width; rcIx++) {
|
||||||
double term = 1D;
|
double term = 1D;
|
||||||
for(int n=0; n<maxN; n++) {
|
for(int n=0; n<maxN; n++) {
|
||||||
term *= elements[n][r][c];
|
double val = getProductTerm(args[n].getRelativeValue(rrIx, rcIx), false);
|
||||||
|
term *= val;
|
||||||
}
|
}
|
||||||
acc += term;
|
acc += term;
|
||||||
}
|
}
|
||||||
@ -172,60 +167,61 @@ public final class Sumproduct implements Function {
|
|||||||
return new NumberEval(acc);
|
return new NumberEval(acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static void throwFirstError(AreaEval areaEval) throws EvaluationException {
|
||||||
* @return a 2-D array of the specified height and width corresponding to the evaluated cell
|
int height = areaEval.getHeight();
|
||||||
* values of the specified areaEval
|
int width = areaEval.getWidth();
|
||||||
* @throws EvalEx if any ErrorEval value was encountered while evaluating the area
|
for (int rrIx=0; rrIx<height; rrIx++) {
|
||||||
*/
|
for (int rcIx=0; rcIx<width; rcIx++) {
|
||||||
private static double[][] evaluateArea(AreaEval areaEval, int height, int width) throws EvalEx {
|
ValueEval ve = areaEval.getRelativeValue(rrIx, rcIx);
|
||||||
int fr =areaEval.getFirstRow();
|
if (ve instanceof ErrorEval) {
|
||||||
int fc =areaEval.getFirstColumn();
|
throw new EvaluationException((ErrorEval) ve);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean areasAllSameSize(AreaEval[] args, int height, int width) {
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
AreaEval areaEval = args[i];
|
||||||
// check that height and width match
|
// check that height and width match
|
||||||
if(areaEval.getLastRow() - fr + 1 != height) {
|
if(areaEval.getHeight() != height) {
|
||||||
throw new EvalEx(ErrorEval.VALUE_INVALID);
|
return false;
|
||||||
}
|
}
|
||||||
if(areaEval.getLastColumn() - fc + 1 != width) {
|
if(areaEval.getWidth() != width) {
|
||||||
throw new EvalEx(ErrorEval.VALUE_INVALID);
|
return false;
|
||||||
}
|
|
||||||
ValueEval[] values = areaEval.getValues();
|
|
||||||
double[][] result = new double[height][width];
|
|
||||||
for(int r=0; r<height; r++) {
|
|
||||||
for(int c=0; c<width; c++) {
|
|
||||||
ValueEval ve = values[r*width + c];
|
|
||||||
result[r][c] = getProductTerm(ve, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines a <code>double</code> value for the specified <code>ValueEval</code>.
|
* Determines a <code>double</code> value for the specified <code>ValueEval</code>.
|
||||||
* @param isScalarProduct <code>false</code> for SUMPRODUCTs over area refs.
|
* @param isScalarProduct <code>false</code> for SUMPRODUCTs over area refs.
|
||||||
* @throws EvalEx if <code>ve</code> represents an error value.
|
* @throws EvaluationException if <code>ve</code> represents an error value.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Note - string values and empty cells are interpreted differently depending on
|
* Note - string values and empty cells are interpreted differently depending on
|
||||||
* <code>isScalarProduct</code>. For scalar products, if any term is blank or a string, the
|
* <code>isScalarProduct</code>. For scalar products, if any term is blank or a string, the
|
||||||
* error (#VALUE!) is raised. For area (sum)products, if any term is blank or a string, the
|
* error (#VALUE!) is raised. For area (sum)products, if any term is blank or a string, the
|
||||||
* result is zero.
|
* result is zero.
|
||||||
*/
|
*/
|
||||||
private static double getProductTerm(ValueEval ve, boolean isScalarProduct) throws EvalEx {
|
private static double getProductTerm(ValueEval ve, boolean isScalarProduct) throws EvaluationException {
|
||||||
|
|
||||||
if(ve instanceof BlankEval || ve == null) {
|
if(ve instanceof BlankEval || ve == null) {
|
||||||
// TODO - shouldn't BlankEval.INSTANCE be used always instead of null?
|
// TODO - shouldn't BlankEval.INSTANCE be used always instead of null?
|
||||||
// null seems to occur when the blank cell is part of an area ref (but not reliably)
|
// null seems to occur when the blank cell is part of an area ref (but not reliably)
|
||||||
if(isScalarProduct) {
|
if(isScalarProduct) {
|
||||||
throw new EvalEx(ErrorEval.VALUE_INVALID);
|
throw new EvaluationException(ErrorEval.VALUE_INVALID);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ve instanceof ErrorEval) {
|
if(ve instanceof ErrorEval) {
|
||||||
throw new EvalEx((ErrorEval)ve);
|
throw new EvaluationException((ErrorEval)ve);
|
||||||
}
|
}
|
||||||
if(ve instanceof StringEval) {
|
if(ve instanceof StringEval) {
|
||||||
if(isScalarProduct) {
|
if(isScalarProduct) {
|
||||||
throw new EvalEx(ErrorEval.VALUE_INVALID);
|
throw new EvaluationException(ErrorEval.VALUE_INVALID);
|
||||||
}
|
}
|
||||||
// Note for area SUMPRODUCTs, string values are interpreted as zero
|
// Note for area SUMPRODUCTs, string values are interpreted as zero
|
||||||
// even if they would parse as valid numeric values
|
// even if they would parse as valid numeric values
|
||||||
|
@ -102,7 +102,7 @@ public class HSSFFormulaEvaluator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Does nothing
|
* Does nothing
|
||||||
* @deprecated - not needed, since the current row can be derived from the cell
|
* @deprecated (Aug 2008) - not needed, since the current row can be derived from the cell
|
||||||
*/
|
*/
|
||||||
public void setCurrentRow(HSSFRow row) {
|
public void setCurrentRow(HSSFRow row) {
|
||||||
// do nothing
|
// do nothing
|
||||||
@ -451,7 +451,7 @@ public class HSSFFormulaEvaluator {
|
|||||||
AreaEval ae = (AreaEval) evaluationResult;
|
AreaEval ae = (AreaEval) evaluationResult;
|
||||||
if (ae.isRow()) {
|
if (ae.isRow()) {
|
||||||
if(ae.isColumn()) {
|
if(ae.isColumn()) {
|
||||||
return ae.getValues()[0];
|
return ae.getRelativeValue(0, 0);
|
||||||
}
|
}
|
||||||
return ae.getValueAt(ae.getFirstRow(), srcColNum);
|
return ae.getValueAt(ae.getFirstRow(), srcColNum);
|
||||||
}
|
}
|
||||||
|
@ -33,31 +33,35 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
|||||||
* @author Josh Micich
|
* @author Josh Micich
|
||||||
*/
|
*/
|
||||||
final class EvalFactory {
|
final class EvalFactory {
|
||||||
private static final NumberEval ZERO = new NumberEval(0);
|
|
||||||
|
|
||||||
private EvalFactory() {
|
private EvalFactory() {
|
||||||
// no instances of this class
|
// no instances of this class
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a dummy AreaEval (filled with zeros)
|
* Creates a dummy AreaEval
|
||||||
* <p/>
|
* @param values empty (<code>null</code>) entries in this array will be converted to NumberEval.ZERO
|
||||||
* nCols and nRows could have been derived
|
|
||||||
*/
|
*/
|
||||||
public static AreaEval createAreaEval(String areaRefStr, int nCols, int nRows) {
|
public static AreaEval createAreaEval(String areaRefStr, ValueEval[] values) {
|
||||||
int nValues = nCols * nRows;
|
AreaPtg areaPtg = new AreaPtg(areaRefStr);
|
||||||
ValueEval[] values = new ValueEval[nValues];
|
int nCols = areaPtg.getLastColumn() - areaPtg.getFirstColumn() + 1;
|
||||||
for (int i = 0; i < nValues; i++) {
|
int nRows = areaPtg.getLastRow() - areaPtg.getFirstRow() + 1;
|
||||||
values[i] = ZERO;
|
int nExpected = nRows * nCols;
|
||||||
|
if (values.length != nExpected) {
|
||||||
|
throw new RuntimeException("Expected " + nExpected + " values but got " + values.length);
|
||||||
}
|
}
|
||||||
|
for (int i = 0; i < nExpected; i++) {
|
||||||
return new Area2DEval(new AreaPtg(areaRefStr), values);
|
if (values[i] == null) {
|
||||||
|
values[i] = NumberEval.ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Area2DEval(areaPtg, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a single RefEval (with value zero)
|
* Creates a single RefEval (with value zero)
|
||||||
*/
|
*/
|
||||||
public static RefEval createRefEval(String refStr) {
|
public static RefEval createRefEval(String refStr) {
|
||||||
return new Ref2DEval(new RefPtg(refStr), ZERO);
|
return new Ref2DEval(new RefPtg(refStr), NumberEval.ZERO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.hssf.record.formula.functions;
|
package org.apache.poi.hssf.record.formula.functions;
|
||||||
|
|
||||||
import junit.framework.AssertionFailedError;
|
import junit.framework.AssertionFailedError;
|
||||||
@ -48,10 +47,6 @@ import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue;
|
|||||||
*/
|
*/
|
||||||
public final class TestCountFuncs extends TestCase {
|
public final class TestCountFuncs extends TestCase {
|
||||||
|
|
||||||
public TestCountFuncs(String testName) {
|
|
||||||
super(testName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testCountA() {
|
public void testCountA() {
|
||||||
|
|
||||||
Eval[] args;
|
Eval[] args;
|
||||||
@ -69,14 +64,14 @@ public final class TestCountFuncs extends TestCase {
|
|||||||
confirmCountA(3, args);
|
confirmCountA(3, args);
|
||||||
|
|
||||||
args = new Eval[] {
|
args = new Eval[] {
|
||||||
EvalFactory.createAreaEval("D2:F5", 3, 4),
|
EvalFactory.createAreaEval("D2:F5", new ValueEval[12]),
|
||||||
};
|
};
|
||||||
confirmCountA(12, args);
|
confirmCountA(12, args);
|
||||||
|
|
||||||
args = new Eval[] {
|
args = new Eval[] {
|
||||||
EvalFactory.createAreaEval("D1:F5", 3, 5), // 15
|
EvalFactory.createAreaEval("D1:F5", new ValueEval[15]),
|
||||||
EvalFactory.createRefEval("A1"),
|
EvalFactory.createRefEval("A1"),
|
||||||
EvalFactory.createAreaEval("A1:G6", 7, 6), // 42
|
EvalFactory.createAreaEval("A1:G6", new ValueEval[42]),
|
||||||
new NumberEval(0),
|
new NumberEval(0),
|
||||||
};
|
};
|
||||||
confirmCountA(59, args);
|
confirmCountA(59, args);
|
||||||
|
@ -15,12 +15,12 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.hssf.record.formula.functions;
|
package org.apache.poi.hssf.record.formula.functions;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
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.ValueEval;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for ROW(), ROWS(), COLUMN(), COLUMNS()
|
* Tests for ROW(), ROWS(), COLUMN(), COLUMNS()
|
||||||
@ -29,10 +29,6 @@ import org.apache.poi.hssf.record.formula.eval.Eval;
|
|||||||
*/
|
*/
|
||||||
public final class TestRowCol extends TestCase {
|
public final class TestRowCol extends TestCase {
|
||||||
|
|
||||||
public TestRowCol(String testName) {
|
|
||||||
super(testName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testCol() {
|
public void testCol() {
|
||||||
Function target = new Column();
|
Function target = new Column();
|
||||||
{
|
{
|
||||||
@ -41,7 +37,7 @@ public final class TestRowCol extends TestCase {
|
|||||||
assertEquals(3, actual, 0D);
|
assertEquals(3, actual, 0D);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Eval[] args = { EvalFactory.createAreaEval("E2:H12", 4, 11), };
|
Eval[] args = { EvalFactory.createAreaEval("E2:H12", new ValueEval[44]), };
|
||||||
double actual = NumericFunctionInvoker.invoke(target, args);
|
double actual = NumericFunctionInvoker.invoke(target, args);
|
||||||
assertEquals(5, actual, 0D);
|
assertEquals(5, actual, 0D);
|
||||||
}
|
}
|
||||||
@ -55,7 +51,7 @@ public final class TestRowCol extends TestCase {
|
|||||||
assertEquals(5, actual, 0D);
|
assertEquals(5, actual, 0D);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Eval[] args = { EvalFactory.createAreaEval("E2:H12", 4, 11), };
|
Eval[] args = { EvalFactory.createAreaEval("E2:H12", new ValueEval[44]), };
|
||||||
double actual = NumericFunctionInvoker.invoke(target, args);
|
double actual = NumericFunctionInvoker.invoke(target, args);
|
||||||
assertEquals(2, actual, 0D);
|
assertEquals(2, actual, 0D);
|
||||||
}
|
}
|
||||||
@ -86,7 +82,7 @@ public final class TestRowCol extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void confirmRowsFunc(String areaRefStr, int nCols, int nRows) {
|
private static void confirmRowsFunc(String areaRefStr, int nCols, int nRows) {
|
||||||
Eval[] args = { EvalFactory.createAreaEval(areaRefStr, nCols, nRows), };
|
Eval[] args = { EvalFactory.createAreaEval(areaRefStr, new ValueEval[nCols * nRows]), };
|
||||||
|
|
||||||
double actual = NumericFunctionInvoker.invoke(new Rows(), args);
|
double actual = NumericFunctionInvoker.invoke(new Rows(), args);
|
||||||
assertEquals(nRows, actual, 0D);
|
assertEquals(nRows, actual, 0D);
|
||||||
@ -94,7 +90,7 @@ public final class TestRowCol extends TestCase {
|
|||||||
|
|
||||||
|
|
||||||
private static void confirmColumnsFunc(String areaRefStr, int nCols, int nRows) {
|
private static void confirmColumnsFunc(String areaRefStr, int nCols, int nRows) {
|
||||||
Eval[] args = { EvalFactory.createAreaEval(areaRefStr, nCols, nRows), };
|
Eval[] args = { EvalFactory.createAreaEval(areaRefStr, new ValueEval[nCols * nRows]), };
|
||||||
|
|
||||||
double actual = NumericFunctionInvoker.invoke(new Columns(), args);
|
double actual = NumericFunctionInvoker.invoke(new Columns(), args);
|
||||||
assertEquals(nCols, actual, 0D);
|
assertEquals(nCols, actual, 0D);
|
||||||
|
@ -59,19 +59,19 @@ public final class TestSumproduct extends TestCase {
|
|||||||
confirmDouble(6D, result);
|
confirmDouble(6D, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void testAreaSimple() {
|
public void testAreaSimple() {
|
||||||
|
ValueEval[] aValues = {
|
||||||
AreaEval aeA = EvalFactory.createAreaEval("A1:A3", 1, 3);
|
new NumberEval(2),
|
||||||
AreaEval aeB = EvalFactory.createAreaEval("B1:B3", 1, 3);
|
new NumberEval(4),
|
||||||
ValueEval[] aValues = aeA.getValues();
|
new NumberEval(5),
|
||||||
ValueEval[] bValues = aeB.getValues();
|
};
|
||||||
aValues[0] = new NumberEval(2);
|
ValueEval[] bValues = {
|
||||||
aValues[1] = new NumberEval(4);
|
new NumberEval(3),
|
||||||
aValues[2] = new NumberEval(5);
|
new NumberEval(6),
|
||||||
bValues[0] = new NumberEval(3);
|
new NumberEval(7),
|
||||||
bValues[1] = new NumberEval(6);
|
};
|
||||||
bValues[2] = new NumberEval(7);
|
AreaEval aeA = EvalFactory.createAreaEval("A1:A3", aValues);
|
||||||
|
AreaEval aeB = EvalFactory.createAreaEval("B1:B3", bValues);
|
||||||
|
|
||||||
Eval[] args = { aeA, aeB, };
|
Eval[] args = { aeA, aeB, };
|
||||||
Eval result = invokeSumproduct(args);
|
Eval result = invokeSumproduct(args);
|
||||||
@ -83,8 +83,7 @@ public final class TestSumproduct extends TestCase {
|
|||||||
*/
|
*/
|
||||||
public void testOneByOneArea() {
|
public void testOneByOneArea() {
|
||||||
|
|
||||||
AreaEval ae = EvalFactory.createAreaEval("A1:A1", 1, 1);
|
AreaEval ae = EvalFactory.createAreaEval("A1:A1", new ValueEval[] { new NumberEval(7), });
|
||||||
ae.getValues()[0] = new NumberEval(7);
|
|
||||||
|
|
||||||
Eval[] args = {
|
Eval[] args = {
|
||||||
ae,
|
ae,
|
||||||
@ -94,11 +93,10 @@ public final class TestSumproduct extends TestCase {
|
|||||||
confirmDouble(14D, result);
|
confirmDouble(14D, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void testMismatchAreaDimensions() {
|
public void testMismatchAreaDimensions() {
|
||||||
|
|
||||||
AreaEval aeA = EvalFactory.createAreaEval("A1:A3", 1, 3);
|
AreaEval aeA = EvalFactory.createAreaEval("A1:A3", new ValueEval[3]);
|
||||||
AreaEval aeB = EvalFactory.createAreaEval("B1:D1", 3, 1);
|
AreaEval aeB = EvalFactory.createAreaEval("B1:D1", new ValueEval[3]);
|
||||||
|
|
||||||
Eval[] args;
|
Eval[] args;
|
||||||
args = new Eval[] { aeA, aeB, };
|
args = new Eval[] { aeA, aeB, };
|
||||||
@ -109,12 +107,15 @@ public final class TestSumproduct extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testAreaWithErrorCell() {
|
public void testAreaWithErrorCell() {
|
||||||
AreaEval aeA = EvalFactory.createAreaEval("A1:A2", 1, 2);
|
ValueEval[] aValues = {
|
||||||
AreaEval aeB = EvalFactory.createAreaEval("B1:B2", 1, 2);
|
ErrorEval.REF_INVALID,
|
||||||
|
null,
|
||||||
|
};
|
||||||
|
AreaEval aeA = EvalFactory.createAreaEval("A1:A2", aValues);
|
||||||
|
AreaEval aeB = EvalFactory.createAreaEval("B1:B2", new ValueEval[2]);
|
||||||
aeB.getValues()[1] = ErrorEval.REF_INVALID;
|
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
Block a user