Converted AreEval and RefEval to be lazy (part of fix for bug 45358)

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@690835 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2008-09-01 01:48:45 +00:00
parent f9123d1acf
commit 43db5ea180
30 changed files with 595 additions and 824 deletions

View File

@ -14,30 +14,63 @@
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; package org.apache.poi.hssf.record.formula;
/** /**
* Common interface for AreaPtg and Area3DPtg, and their * Common interface for AreaPtg and Area3DPtg, and their child classes.
* child classes.
*/ */
public interface AreaI { public interface AreaI {
/** /**
* @return the first row in the area * @return the first row in the area
*/ */
public int getFirstRow(); public int getFirstRow();
/** /**
* @return last row in the range (x2 in x1,y1-x2,y2) * @return last row in the range (x2 in x1,y1-x2,y2)
*/ */
public int getLastRow(); public int getLastRow();
/** /**
* @return the first column number in the area. * @return the first column number in the area.
*/ */
public int getFirstColumn(); public int getFirstColumn();
/**
* @return lastcolumn in the area
*/
public int getLastColumn();
class OffsetArea implements AreaI {
private final int _firstColumn;
private final int _firstRow;
private final int _lastColumn;
private final int _lastRow;
public OffsetArea(int baseRow, int baseColumn, int relFirstRowIx, int relLastRowIx,
int relFirstColIx, int relLastColIx) {
_firstRow = baseRow + relFirstRowIx;
_lastRow = baseRow + relLastRowIx;
_firstColumn = baseColumn + relFirstColIx;
_lastColumn = baseColumn + relLastColIx;
}
public int getFirstColumn() {
return _firstColumn;
}
public int getFirstRow() {
return _firstRow;
}
public int getLastColumn() {
return _lastColumn;
}
public int getLastRow() {
return _lastRow;
}
}
/**
* @return lastcolumn in the area
*/
public int getLastColumn();
} }

View File

@ -131,14 +131,6 @@ public abstract class RefPtgBase extends OperandPtg {
field_2_col=colRelative.setBoolean(field_2_col,rel); field_2_col=colRelative.setBoolean(field_2_col,rel);
} }
public final void setColumnRawX(int col) { // TODO
field_2_col = col;
}
public int getColumnRawX() { // TODO
return field_2_col;
}
public final void setColumn(int col) { public final void setColumn(int col) {
if(col < 0 || col >= 0x100) { if(col < 0 || col >= 0x100) {
throw new IllegalArgumentException("Specified colIx (" + col + ") is out of range"); throw new IllegalArgumentException("Specified colIx (" + col + ") is out of range");

View File

@ -1,32 +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.AreaPtg;
import org.apache.poi.hssf.record.formula.Ptg;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*/
public final class Area2DEval extends AreaEvalBase {
public Area2DEval(Ptg ptg, ValueEval[] values) {
super((AreaPtg) ptg, values);
}
}

View File

@ -1,39 +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.Area3DPtg;
import org.apache.poi.hssf.record.formula.Ptg;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*/
public final class Area3DEval extends AreaEvalBase {
private final int _externSheetIndex;
public Area3DEval(Ptg ptg, ValueEval[] values) {
super((Area3DPtg) ptg, values);
_externSheetIndex = ((Area3DPtg) ptg).getExternSheetIndex();
}
public int getExternSheetIndex() {
return _externSheetIndex;
}
}

View File

@ -97,4 +97,10 @@ public interface AreaEval extends ValueEval {
* specified indexes should relative to the top left corner of this area. * specified indexes should relative to the top left corner of this area.
*/ */
ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex); ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex);
/**
* Creates an {@link AreaEval} offset by a relative amount from from the upper left cell
* of this area
*/
AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx);
} }

View File

@ -22,20 +22,16 @@ import org.apache.poi.hssf.record.formula.AreaI;
/** /**
* @author Josh Micich * @author Josh Micich
*/ */
abstract class AreaEvalBase implements AreaEval { public abstract class AreaEvalBase implements AreaEval {
private final int _firstColumn; private final int _firstColumn;
private final int _firstRow; private final int _firstRow;
private final int _lastColumn; private final int _lastColumn;
private final int _lastRow; private final int _lastRow;
private final ValueEval[] _values;
private final int _nColumns; private final int _nColumns;
private final int _nRows; private final int _nRows;
protected AreaEvalBase(AreaI ptg, ValueEval[] values) { protected AreaEvalBase(AreaI ptg) {
if (values == null) {
throw new IllegalArgumentException("values must not be null");
}
_firstRow = ptg.getFirstRow(); _firstRow = ptg.getFirstRow();
_firstColumn = ptg.getFirstColumn(); _firstColumn = ptg.getFirstColumn();
_lastRow = ptg.getLastRow(); _lastRow = ptg.getLastRow();
@ -43,22 +39,6 @@ abstract class AreaEvalBase implements AreaEval {
_nColumns = _lastColumn - _firstColumn + 1; _nColumns = _lastColumn - _firstColumn + 1;
_nRows = _lastRow - _firstRow + 1; _nRows = _lastRow - _firstRow + 1;
int expectedItemCount = _nRows * _nColumns;
if ((values.length != expectedItemCount)) {
// Note - this math may need alteration when POI starts to support full column or full row refs
throw new IllegalArgumentException("Array size should be (" + expectedItemCount
+ ") but was (" + values.length + ")");
}
for (int i = values.length - 1; i >= 0; i--) {
if (values[i] == null) {
throw new IllegalArgumentException("value array elements must not be null");
}
}
_values = values;
} }
public final int getFirstColumn() { public final int getFirstColumn() {
@ -116,14 +96,7 @@ abstract class AreaEvalBase implements AreaEval {
return _lastRow-_firstRow+1; return _lastRow-_firstRow+1;
} }
public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) { public abstract ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex);
int index = relativeRowIndex * _nColumns + relativeColumnIndex;
ValueEval result = _values[index];
if (result == null) {
return BlankEval.INSTANCE;
}
return result;
}
public int getWidth() { public int getWidth() {
return _lastColumn-_firstColumn+1; return _lastColumn-_firstColumn+1;

View File

@ -50,7 +50,6 @@ public abstract class FunctionEval implements OperationEval {
static { static {
Map m = new HashMap(); Map m = new HashMap();
addMapping(m, ID.OFFSET, new Offset());
addMapping(m, ID.INDIRECT, new Indirect()); addMapping(m, ID.INDIRECT, new Indirect());
addMapping(m, ID.EXTERNAL_FUNC, new ExternalFunction()); addMapping(m, ID.EXTERNAL_FUNC, new ExternalFunction());
freeRefFunctionsByIdMap = m; freeRefFunctionsByIdMap = m;
@ -155,7 +154,7 @@ public abstract class FunctionEval implements OperationEval {
retval[75] = new Areas(); // AREAS retval[75] = new Areas(); // AREAS
retval[76] = new Rows(); // ROWS retval[76] = new Rows(); // ROWS
retval[77] = new Columns(); // COLUMNS retval[77] = new Columns(); // COLUMNS
retval[ID.OFFSET] = null; // Offset.evaluate has a different signature retval[ID.OFFSET] = new Offset(); // OFFSET
retval[79] = new Absref(); // ABSREF retval[79] = new Absref(); // ABSREF
retval[80] = new Relref(); // RELREF retval[80] = new Relref(); // RELREF
retval[81] = new Argument(); // ARGUMENT retval[81] = new Argument(); // ARGUMENT

View File

@ -0,0 +1,65 @@
/*
* 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.AreaI;
import org.apache.poi.hssf.record.formula.AreaI.OffsetArea;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*/
public final class LazyAreaEval extends AreaEvalBase {
private final HSSFSheet _sheet;
private HSSFWorkbook _workbook;
public LazyAreaEval(AreaI ptg, HSSFSheet sheet, HSSFWorkbook workbook) {
super(ptg);
_sheet = sheet;
_workbook = workbook;
}
public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
int rowIx = (relativeRowIndex + getFirstRow() ) & 0xFFFF;
int colIx = (relativeColumnIndex + getFirstColumn() ) & 0x00FF;
HSSFRow row = _sheet.getRow(rowIx);
if (row == null) {
return BlankEval.INSTANCE;
}
HSSFCell cell = row.getCell(colIx);
if (cell == null) {
return BlankEval.INSTANCE;
}
return HSSFFormulaEvaluator.getEvalForCell(cell, _sheet, _workbook);
}
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
AreaI area = new OffsetArea(getFirstRow(), getFirstColumn(),
relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
return new LazyAreaEval(area, _sheet, _workbook);
}
}

View File

@ -0,0 +1,52 @@
package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.AreaI;
import org.apache.poi.hssf.record.formula.AreaI.OffsetArea;
import org.apache.poi.hssf.record.formula.Ref3DPtg;
import org.apache.poi.hssf.record.formula.RefPtg;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
public final class LazyRefEval extends RefEvalBase {
private final HSSFSheet _sheet;
private final HSSFWorkbook _workbook;
public LazyRefEval(RefPtg ptg, HSSFSheet sheet, HSSFWorkbook workbook) {
super(ptg.getRow(), ptg.getColumn());
_sheet = sheet;
_workbook = workbook;
}
public LazyRefEval(Ref3DPtg ptg, HSSFSheet sheet, HSSFWorkbook workbook) {
super(ptg.getRow(), ptg.getColumn());
_sheet = sheet;
_workbook = workbook;
}
public ValueEval getInnerValueEval() {
int rowIx = getRow();
int colIx = getColumn();
HSSFRow row = _sheet.getRow(rowIx);
if (row == null) {
return BlankEval.INSTANCE;
}
HSSFCell cell = row.getCell(colIx);
if (cell == null) {
return BlankEval.INSTANCE;
}
return HSSFFormulaEvaluator.getEvalForCell(cell, _sheet, _workbook);
}
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
AreaI area = new OffsetArea(getRow(), getColumn(),
relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
return new LazyAreaEval(area, _sheet, _workbook);
}
}

View File

@ -47,4 +47,7 @@ public final class Ref2DEval implements RefEval {
public int getColumn() { public int getColumn() {
return delegate.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,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.Ref3DPtg;
/**
* @author Amol S. Deshmukh
*
*/
public final class Ref3DEval implements RefEval {
private final ValueEval value;
private final Ref3DPtg delegate;
public Ref3DEval(Ref3DPtg ptg, ValueEval ve) {
if(ve == null) {
throw new IllegalArgumentException("ve must not be null");
}
if(ptg == null) {
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 int getExternSheetIndex() {
return delegate.getExternSheetIndex();
}
}

View File

@ -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.eval; package org.apache.poi.hssf.record.formula.eval;
@ -30,22 +30,22 @@ package org.apache.poi.hssf.record.formula.eval;
public interface RefEval extends ValueEval { public interface RefEval extends ValueEval {
/** /**
* The (possibly evaluated) ValueEval contained * @return the evaluated value of the cell referred to by this RefEval.
* in this RefEval. eg. if cell A1 contains "test"
* then in a formula referring to cell A1
* the RefEval representing
* A1 will return as the getInnerValueEval() the
* object of concrete type StringEval
*/ */
public ValueEval getInnerValueEval(); ValueEval getInnerValueEval();
/** /**
* returns the zero based column index. * returns the zero based column index.
*/ */
public int getColumn(); int getColumn();
/** /**
* returns the zero based row index. * returns the zero based row index.
*/ */
public int getRow(); int getRow();
/**
* Creates an {@link AreaEval} offset by a relative amount from this RefEval
*/
AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx);
} }

View File

@ -0,0 +1,18 @@
package org.apache.poi.hssf.record.formula.eval;
public abstract class RefEvalBase implements RefEval {
private final int _rowIndex;
private final int _columnIndex;
protected RefEvalBase(int rowIndex, int columnIndex) {
_rowIndex = rowIndex;
_columnIndex = columnIndex;
}
public final int getRow() {
return _rowIndex;
}
public final int getColumn() {
return _columnIndex;
}
}

View File

@ -50,9 +50,9 @@ final class CountUtils {
for (int rrIx=0; rrIx<height; rrIx++) { for (int rrIx=0; rrIx<height; rrIx++) {
for (int rcIx=0; rcIx<width; rcIx++) { for (int rcIx=0; rcIx<width; rcIx++) {
ValueEval ve = areaEval.getRelativeValue(rrIx, rcIx); ValueEval ve = areaEval.getRelativeValue(rrIx, rcIx);
if(criteriaPredicate.matches(ve)) { if(criteriaPredicate.matches(ve)) {
result++; result++;
} }
} }
} }
return result; return result;
@ -67,6 +67,9 @@ final class CountUtils {
return 0; return 0;
} }
public static int countArg(Eval eval, I_MatchPredicate criteriaPredicate) { public static int countArg(Eval eval, I_MatchPredicate criteriaPredicate) {
if (eval == null) {
throw new IllegalArgumentException("eval must not be null");
}
if (eval instanceof AreaEval) { if (eval instanceof AreaEval) {
return CountUtils.countMatchingCellsInArea((AreaEval) eval, criteriaPredicate); return CountUtils.countMatchingCellsInArea((AreaEval) eval, criteriaPredicate);
} }

View File

@ -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 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 Nov 25, 2006
*
*/
package org.apache.poi.hssf.record.formula.functions; package org.apache.poi.hssf.record.formula.functions;
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.EvaluationException;
import org.apache.poi.hssf.record.formula.eval.OperandResolver;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
/** /**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt; * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
@ -34,16 +34,30 @@ public final class If implements Function {
Eval evalWhenFalse = BoolEval.FALSE; Eval evalWhenFalse = BoolEval.FALSE;
switch (args.length) { switch (args.length) {
case 3: case 3:
evalWhenFalse = args[2]; evalWhenFalse = args[2];
case 2: case 2:
BoolEval beval = (BoolEval) args[0]; // TODO - class cast exception boolean b;
if (beval.getBooleanValue()) { try {
return args[1]; b = evaluateFirstArg(args[0], srcCellRow, srcCellCol);
} } catch (EvaluationException e) {
return evalWhenFalse; return e.getErrorEval();
default: }
return ErrorEval.VALUE_INVALID; if (b) {
return args[1];
}
return evalWhenFalse;
default:
return ErrorEval.VALUE_INVALID;
} }
} }
private static boolean evaluateFirstArg(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
Boolean b = OperandResolver.coerceValueToBoolean(ve, false);
if (b == null) {
return false;
}
return b.booleanValue();
}
} }

View File

@ -17,8 +17,6 @@
package org.apache.poi.hssf.record.formula.functions; package org.apache.poi.hssf.record.formula.functions;
import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.eval.Area2DEval;
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.BlankEval; 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;
@ -366,13 +364,7 @@ final class LookupUtils {
// Make this cell ref look like a 1x1 area ref. // Make this cell ref look like a 1x1 area ref.
// It doesn't matter if eval is a 2D or 3D ref, because that detail is never asked of AreaEval. // It doesn't matter if eval is a 2D or 3D ref, because that detail is never asked of AreaEval.
// This code only requires the value array item. return refEval.offset(0, 0, 0, 0);
// anything would be ok for rowIx and colIx, but may as well get it right.
int rowIx = refEval.getRow();
int colIx = refEval.getColumn();
AreaPtg ap = new AreaPtg(rowIx, rowIx, colIx, colIx, false, false, false, false);
ValueEval value = refEval.getInnerValueEval();
return new Area2DEval(ap, new ValueEval[] { value, });
} }
throw EvaluationException.invalidValue(); throw EvaluationException.invalidValue();
} }

View File

@ -455,85 +455,6 @@ public final class MathX {
return d; return d;
} }
/**
* returns the sum of difference of squares of corresponding double
* value in each subarray: ie. sigma (xarr[i]^2-yarr[i]^2)
* <br/>
* It is the responsibility of the caller
* to ensure that the two subarrays are of equal length. If the
* subarrays are not of equal length, the return value can be
* unpredictable.
* @param xarr
* @param yarr
*/
public static double sumx2my2(double[] xarr, double[] yarr) {
double d = 0;
try {
for (int i=0, iSize=xarr.length; i<iSize; i++) {
d += (xarr[i] + yarr[i]) * (xarr[i] - yarr[i]);
}
}
catch (ArrayIndexOutOfBoundsException ae) {
d = Double.NaN;
}
return d;
}
/**
* returns the sum of sum of squares of corresponding double
* value in each subarray: ie. sigma (xarr[i]^2 + yarr[i]^2)
* <br/>
* It is the responsibility of the caller
* to ensure that the two subarrays are of equal length. If the
* subarrays are not of equal length, the return value can be
* unpredictable.
* @param xarr
* @param yarr
*/
public static double sumx2py2(double[] xarr, double[] yarr) {
double d = 0;
try {
for (int i=0, iSize=xarr.length; i<iSize; i++) {
d += (xarr[i] * xarr[i]) + (yarr[i] * yarr[i]);
}
}
catch (ArrayIndexOutOfBoundsException ae) {
d = Double.NaN;
}
return d;
}
/**
* returns the sum of squares of difference of corresponding double
* value in each subarray: ie. sigma ( (xarr[i]-yarr[i])^2 )
* <br/>
* It is the responsibility of the caller
* to ensure that the two subarrays are of equal length. If the
* subarrays are not of equal length, the return value can be
* unpredictable.
* @param xarr
* @param yarr
*/
public static double sumxmy2(double[] xarr, double[] yarr) {
double d = 0;
try {
for (int i=0, iSize=xarr.length; i<iSize; i++) {
double t = (xarr[i] - yarr[i]);
d += t * t;
}
}
catch (ArrayIndexOutOfBoundsException ae) {
d = Double.NaN;
}
return d;
}
/** /**
* returns the total number of combinations possible when * returns the total number of combinations possible when

View File

@ -1,26 +1,22 @@
/* /* ====================================================================
* 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.Area3DPtg;
import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.eval.Area3DEval;
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.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;
@ -28,13 +24,9 @@ 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.EvaluationException;
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.OperandResolver; import org.apache.poi.hssf.record.formula.eval.OperandResolver;
import org.apache.poi.hssf.record.formula.eval.Ref3DEval;
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.StringEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/** /**
* Implementation for Excel function OFFSET()<p/> * Implementation for Excel function OFFSET()<p/>
* *
@ -51,7 +43,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
* *
* @author Josh Micich * @author Josh Micich
*/ */
public final class Offset implements FreeRefFunction { public final class Offset implements Function {
// These values are specific to BIFF8 // These values are specific to BIFF8
private static final int LAST_VALID_ROW_INDEX = 0xFFFF; private static final int LAST_VALID_ROW_INDEX = 0xFFFF;
private static final int LAST_VALID_COLUMN_INDEX = 0xFF; private static final int LAST_VALID_COLUMN_INDEX = 0xFF;
@ -125,37 +117,29 @@ public final class Offset implements FreeRefFunction {
* Encapsulates either an area or cell reference which may be 2d or 3d. * Encapsulates either an area or cell reference which may be 2d or 3d.
*/ */
private static final class BaseRef { private static final class BaseRef {
private static final int INVALID_SHEET_INDEX = -1;
private final int _firstRowIndex; private final int _firstRowIndex;
private final int _firstColumnIndex; private final int _firstColumnIndex;
private final int _width; private final int _width;
private final int _height; private final int _height;
private final int _externalSheetIndex; private final RefEval _refEval;
private final AreaEval _areaEval;
public BaseRef(RefEval re) { public BaseRef(RefEval re) {
_refEval = re;
_areaEval = null;
_firstRowIndex = re.getRow(); _firstRowIndex = re.getRow();
_firstColumnIndex = re.getColumn(); _firstColumnIndex = re.getColumn();
_height = 1; _height = 1;
_width = 1; _width = 1;
if (re instanceof Ref3DEval) {
Ref3DEval r3e = (Ref3DEval) re;
_externalSheetIndex = r3e.getExternSheetIndex();
} else {
_externalSheetIndex = INVALID_SHEET_INDEX;
}
} }
public BaseRef(AreaEval ae) { public BaseRef(AreaEval ae) {
_refEval = null;
_areaEval = ae;
_firstRowIndex = ae.getFirstRow(); _firstRowIndex = ae.getFirstRow();
_firstColumnIndex = ae.getFirstColumn(); _firstColumnIndex = ae.getFirstColumn();
_height = ae.getLastRow() - ae.getFirstRow() + 1; _height = ae.getLastRow() - ae.getFirstRow() + 1;
_width = ae.getLastColumn() - ae.getFirstColumn() + 1; _width = ae.getLastColumn() - ae.getFirstColumn() + 1;
if (ae instanceof Area3DEval) {
Area3DEval a3e = (Area3DEval) ae;
_externalSheetIndex = a3e.getExternSheetIndex();
} else {
_externalSheetIndex = INVALID_SHEET_INDEX;
}
} }
public int getWidth() { public int getWidth() {
@ -170,19 +154,17 @@ public final class Offset implements FreeRefFunction {
public int getFirstColumnIndex() { public int getFirstColumnIndex() {
return _firstColumnIndex; return _firstColumnIndex;
} }
public boolean isIs3d() {
return _externalSheetIndex > 0;
}
public short getExternalSheetIndex() { public AreaEval offset(int relFirstRowIx, int relLastRowIx,
if(_externalSheetIndex < 0) { int relFirstColIx, int relLastColIx) {
throw new IllegalStateException("external sheet index only available for 3d refs"); if (_refEval == null) {
return _areaEval.offset(relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
} }
return (short) _externalSheetIndex; return _refEval.offset(relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
} }
} }
public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, HSSFWorkbook workbook, HSSFSheet sheet) { public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
if(args.length < 3 || args.length > 5) { if(args.length < 3 || args.length > 5) {
return ErrorEval.VALUE_INVALID; return ErrorEval.VALUE_INVALID;
@ -206,37 +188,25 @@ public final class Offset implements FreeRefFunction {
} }
LinearOffsetRange rowOffsetRange = new LinearOffsetRange(rowOffset, height); LinearOffsetRange rowOffsetRange = new LinearOffsetRange(rowOffset, height);
LinearOffsetRange colOffsetRange = new LinearOffsetRange(columnOffset, width); LinearOffsetRange colOffsetRange = new LinearOffsetRange(columnOffset, width);
return createOffset(baseRef, rowOffsetRange, colOffsetRange, workbook, sheet); return createOffset(baseRef, rowOffsetRange, colOffsetRange);
} catch (EvaluationException e) { } catch (EvaluationException e) {
return e.getErrorEval(); return e.getErrorEval();
} }
} }
private static AreaEval createOffset(BaseRef baseRef, private static AreaEval createOffset(BaseRef baseRef,
LinearOffsetRange rowOffsetRange, LinearOffsetRange colOffsetRange, LinearOffsetRange orRow, LinearOffsetRange orCol) throws EvaluationException {
HSSFWorkbook workbook, HSSFSheet sheet) throws EvaluationException {
LinearOffsetRange rows = rowOffsetRange.normaliseAndTranslate(baseRef.getFirstRowIndex()); LinearOffsetRange absRows = orRow.normaliseAndTranslate(baseRef.getFirstRowIndex());
LinearOffsetRange cols = colOffsetRange.normaliseAndTranslate(baseRef.getFirstColumnIndex()); LinearOffsetRange absCols = orCol.normaliseAndTranslate(baseRef.getFirstColumnIndex());
if(rows.isOutOfBounds(0, LAST_VALID_ROW_INDEX)) { if(absRows.isOutOfBounds(0, LAST_VALID_ROW_INDEX)) {
throw new EvaluationException(ErrorEval.REF_INVALID); throw new EvaluationException(ErrorEval.REF_INVALID);
} }
if(cols.isOutOfBounds(0, LAST_VALID_COLUMN_INDEX)) { if(absCols.isOutOfBounds(0, LAST_VALID_COLUMN_INDEX)) {
throw new EvaluationException(ErrorEval.REF_INVALID); throw new EvaluationException(ErrorEval.REF_INVALID);
} }
if(baseRef.isIs3d()) { return baseRef.offset(orRow.getFirstIndex(), orRow.getLastIndex(), orCol.getFirstIndex(), orCol.getLastIndex());
Area3DPtg a3dp = new Area3DPtg(rows.getFirstIndex(), rows.getLastIndex(),
cols.getFirstIndex(), cols.getLastIndex(),
false, false, false, false,
baseRef.getExternalSheetIndex());
return HSSFFormulaEvaluator.evaluateArea3dPtg(workbook, a3dp);
}
AreaPtg ap = new AreaPtg(rows.getFirstIndex(), rows.getLastIndex(),
cols.getFirstIndex(), cols.getLastIndex(),
false, false, false, false);
return HSSFFormulaEvaluator.evaluateAreaPtg(sheet, workbook, ap);
} }
private static BaseRef evaluateBaseRef(Eval eval) throws EvaluationException { private static BaseRef evaluateBaseRef(Eval eval) throws EvaluationException {

View File

@ -17,10 +17,7 @@
package org.apache.poi.hssf.usermodel; package org.apache.poi.hssf.usermodel;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map;
import java.util.Stack; import java.util.Stack;
import org.apache.poi.hssf.model.FormulaParser; import org.apache.poi.hssf.model.FormulaParser;
@ -29,6 +26,7 @@ import org.apache.poi.hssf.record.formula.Area3DPtg;
import org.apache.poi.hssf.record.formula.AreaPtg; import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.BoolPtg; import org.apache.poi.hssf.record.formula.BoolPtg;
import org.apache.poi.hssf.record.formula.ControlPtg; import org.apache.poi.hssf.record.formula.ControlPtg;
import org.apache.poi.hssf.record.formula.ErrPtg;
import org.apache.poi.hssf.record.formula.IntPtg; import org.apache.poi.hssf.record.formula.IntPtg;
import org.apache.poi.hssf.record.formula.MemErrPtg; import org.apache.poi.hssf.record.formula.MemErrPtg;
import org.apache.poi.hssf.record.formula.MissingArgPtg; import org.apache.poi.hssf.record.formula.MissingArgPtg;
@ -42,20 +40,18 @@ import org.apache.poi.hssf.record.formula.RefPtg;
import org.apache.poi.hssf.record.formula.StringPtg; import org.apache.poi.hssf.record.formula.StringPtg;
import org.apache.poi.hssf.record.formula.UnionPtg; import org.apache.poi.hssf.record.formula.UnionPtg;
import org.apache.poi.hssf.record.formula.UnknownPtg; import org.apache.poi.hssf.record.formula.UnknownPtg;
import org.apache.poi.hssf.record.formula.eval.Area2DEval;
import org.apache.poi.hssf.record.formula.eval.Area3DEval;
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.BlankEval; 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.FunctionEval; import org.apache.poi.hssf.record.formula.eval.FunctionEval;
import org.apache.poi.hssf.record.formula.eval.LazyAreaEval;
import org.apache.poi.hssf.record.formula.eval.LazyRefEval;
import org.apache.poi.hssf.record.formula.eval.NameEval; import org.apache.poi.hssf.record.formula.eval.NameEval;
import org.apache.poi.hssf.record.formula.eval.NameXEval; import org.apache.poi.hssf.record.formula.eval.NameXEval;
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.OperationEval; import org.apache.poi.hssf.record.formula.eval.OperationEval;
import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
import org.apache.poi.hssf.record.formula.eval.Ref3DEval;
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.StringEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval;
@ -66,32 +62,6 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
*/ */
public class HSSFFormulaEvaluator { public class HSSFFormulaEvaluator {
// params to lookup the right constructor using reflection
private static final Class[] VALUE_CONTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class };
private static final Class[] AREA3D_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval[].class };
private static final Class[] REFERENCE_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval.class };
private static final Class[] REF3D_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval.class };
// Maps for mapping *Eval to *Ptg
private static final Map VALUE_EVALS_MAP = new HashMap();
/*
* Following is the mapping between the Ptg tokens returned
* by the FormulaParser and the *Eval classes that are used
* by the FormulaEvaluator
*/
static {
VALUE_EVALS_MAP.put(BoolPtg.class, BoolEval.class);
VALUE_EVALS_MAP.put(IntPtg.class, NumberEval.class);
VALUE_EVALS_MAP.put(NumberPtg.class, NumberEval.class);
VALUE_EVALS_MAP.put(StringPtg.class, StringEval.class);
}
protected HSSFSheet _sheet; protected HSSFSheet _sheet;
protected HSSFWorkbook _workbook; protected HSSFWorkbook _workbook;
@ -265,29 +235,29 @@ public class HSSFFormulaEvaluator {
* This is a helpful wrapper around looping over all * This is a helpful wrapper around looping over all
* cells, and calling evaluateFormulaCell on each one. * cells, and calling evaluateFormulaCell on each one.
*/ */
public static void evaluateAllFormulaCells(HSSFWorkbook wb) { public static void evaluateAllFormulaCells(HSSFWorkbook wb) {
for(int i=0; i<wb.getNumberOfSheets(); i++) { for(int i=0; i<wb.getNumberOfSheets(); i++) {
HSSFSheet sheet = wb.getSheetAt(i); HSSFSheet sheet = wb.getSheetAt(i);
HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb); HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
for (Iterator rit = sheet.rowIterator(); rit.hasNext();) { for (Iterator rit = sheet.rowIterator(); rit.hasNext();) {
HSSFRow r = (HSSFRow)rit.next(); HSSFRow r = (HSSFRow)rit.next();
for (Iterator cit = r.cellIterator(); cit.hasNext();) { for (Iterator cit = r.cellIterator(); cit.hasNext();) {
HSSFCell c = (HSSFCell)cit.next(); HSSFCell c = (HSSFCell)cit.next();
if (c.getCellType() == HSSFCell.CELL_TYPE_FORMULA) if (c.getCellType() == HSSFCell.CELL_TYPE_FORMULA)
evaluator.evaluateFormulaCell(c); evaluator.evaluateFormulaCell(c);
} }
} }
} }
} }
/** /**
* Returns a CellValue wrapper around the supplied ValueEval instance. * Returns a CellValue wrapper around the supplied ValueEval instance.
* @param eval * @param eval
*/ */
protected static CellValue getCellValueForEval(ValueEval eval) { private static CellValue getCellValueForEval(ValueEval eval) {
CellValue retval = null; CellValue retval = null;
if (eval != null) { if (eval != null) {
if (eval instanceof NumberEval) { if (eval instanceof NumberEval) {
@ -344,7 +314,7 @@ public class HSSFFormulaEvaluator {
private static ValueEval evaluateCell(HSSFWorkbook workbook, HSSFSheet sheet, private static ValueEval evaluateCell(HSSFWorkbook workbook, HSSFSheet sheet,
int srcRowNum, short srcColNum, String cellFormulaText) { int srcRowNum, short srcColNum, String cellFormulaText) {
Ptg[] ptgs = FormulaParser.parse(cellFormulaText, workbook); Ptg[] ptgs = FormulaParser.parse(cellFormulaText, workbook);
Stack stack = new Stack(); Stack stack = new Stack();
for (int i = 0, iSize = ptgs.length; i < iSize; i++) { for (int i = 0, iSize = ptgs.length; i < iSize; i++) {
@ -369,7 +339,7 @@ public class HSSFFormulaEvaluator {
continue; continue;
} }
if (ptg instanceof UnknownPtg) { continue; } if (ptg instanceof UnknownPtg) { continue; }
Eval opResult;
if (ptg instanceof OperationPtg) { if (ptg instanceof OperationPtg) {
OperationPtg optg = (OperationPtg) ptg; OperationPtg optg = (OperationPtg) ptg;
@ -385,41 +355,11 @@ public class HSSFFormulaEvaluator {
Eval p = (Eval) stack.pop(); Eval p = (Eval) stack.pop();
ops[j] = p; ops[j] = p;
} }
Eval opresult = invokeOperation(operation, ops, srcRowNum, srcColNum, workbook, sheet); opResult = invokeOperation(operation, ops, srcRowNum, srcColNum, workbook, sheet);
stack.push(opresult); } else {
} opResult = getEvalForPtg(ptg, sheet, workbook);
else if (ptg instanceof RefPtg) {
RefPtg refPtg = (RefPtg) ptg;
int colIx = refPtg.getColumn();
int rowIx = refPtg.getRow();
HSSFRow row = sheet.getRow(rowIx);
HSSFCell cell = (row != null) ? row.getCell(colIx) : null;
stack.push(createRef2DEval(refPtg, cell, sheet, workbook));
}
else if (ptg instanceof Ref3DPtg) {
Ref3DPtg refPtg = (Ref3DPtg) ptg;
int colIx = refPtg.getColumn();
int rowIx = refPtg.getRow();
Workbook wb = workbook.getWorkbook();
HSSFSheet xsheet = workbook.getSheetAt(wb.getSheetIndexFromExternSheetIndex(refPtg.getExternSheetIndex()));
HSSFRow row = xsheet.getRow(rowIx);
HSSFCell cell = (row != null) ? row.getCell(colIx) : null;
stack.push(createRef3DEval(refPtg, cell, xsheet, workbook));
}
else if (ptg instanceof AreaPtg) {
AreaPtg ap = (AreaPtg) ptg;
AreaEval ae = evaluateAreaPtg(sheet, workbook, ap);
stack.push(ae);
}
else if (ptg instanceof Area3DPtg) {
Area3DPtg a3dp = (Area3DPtg) ptg;
AreaEval ae = evaluateArea3dPtg(workbook, a3dp);
stack.push(ae);
}
else {
Eval ptgEval = getEvalForPtg(ptg);
stack.push(ptgEval);
} }
stack.push(opResult);
} }
ValueEval value = ((ValueEval) stack.pop()); ValueEval value = ((ValueEval) stack.pop());
@ -428,7 +368,7 @@ public class HSSFFormulaEvaluator {
} }
value = dereferenceValue(value, srcRowNum, srcColNum); value = dereferenceValue(value, srcRowNum, srcColNum);
if (value instanceof BlankEval) { if (value instanceof BlankEval) {
// Note Excel behaviour here. A blank final final value is converted to zero. // Note Excel behaviour here. A blank final final value is converted to zero.
return NumberEval.ZERO; return NumberEval.ZERO;
// Formulas _never_ evaluate to blank. If a formula appears to have evaluated to // Formulas _never_ evaluate to blank. If a formula appears to have evaluated to
// blank, the actual value is empty string. This can be verified with ISBLANK(). // blank, the actual value is empty string. This can be verified with ISBLANK().
@ -439,8 +379,8 @@ public class HSSFFormulaEvaluator {
/** /**
* Dereferences a single value from any AreaEval or RefEval evaluation result. * Dereferences a single value from any AreaEval or RefEval evaluation result.
* If the supplied evaluationResult is just a plain value, it is returned as-is. * If the supplied evaluationResult is just a plain value, it is returned as-is.
* @return a <tt>NumberEval</tt>, <tt>StringEval</tt>, <tt>BoolEval</tt>, * @return a <tt>NumberEval</tt>, <tt>StringEval</tt>, <tt>BoolEval</tt>,
* <tt>BlankEval</tt> or <tt>ErrorEval</tt>. Never <code>null</code>. * <tt>BlankEval</tt> or <tt>ErrorEval</tt>. Never <code>null</code>.
*/ */
private static ValueEval dereferenceValue(ValueEval evaluationResult, int srcRowNum, short srcColNum) { private static ValueEval dereferenceValue(ValueEval evaluationResult, int srcRowNum, short srcColNum) {
if (evaluationResult instanceof RefEval) { if (evaluationResult instanceof RefEval) {
@ -475,105 +415,49 @@ public class HSSFFormulaEvaluator {
return operation.evaluate(ops, srcRowNum, srcColNum); return operation.evaluate(ops, srcRowNum, srcColNum);
} }
public static AreaEval evaluateAreaPtg(HSSFSheet sheet, HSSFWorkbook workbook, AreaPtg ap) {
int row0 = ap.getFirstRow();
int col0 = ap.getFirstColumn();
int row1 = ap.getLastRow();
int col1 = ap.getLastColumn();
// If the last row is -1, then the
// reference is for the rest of the column
// (eg C:C)
// TODO: Handle whole column ranges properly
if(row1 == -1 && row0 >= 0) {
row1 = (short)sheet.getLastRowNum();
}
ValueEval[] values = evalArea(workbook, sheet, row0, col0, row1, col1);
return new Area2DEval(ap, values);
}
public static AreaEval evaluateArea3dPtg(HSSFWorkbook workbook, Area3DPtg a3dp) {
int row0 = a3dp.getFirstRow();
int col0 = a3dp.getFirstColumn();
int row1 = a3dp.getLastRow();
int col1 = a3dp.getLastColumn();
Workbook wb = workbook.getWorkbook();
HSSFSheet xsheet = workbook.getSheetAt(wb.getSheetIndexFromExternSheetIndex(a3dp.getExternSheetIndex()));
// If the last row is -1, then the
// reference is for the rest of the column
// (eg C:C)
// TODO: Handle whole column ranges properly
if(row1 == -1 && row0 >= 0) {
row1 = (short)xsheet.getLastRowNum();
}
ValueEval[] values = evalArea(workbook, xsheet, row0, col0, row1, col1);
return new Area3DEval(a3dp, values);
}
private static ValueEval[] evalArea(HSSFWorkbook workbook, HSSFSheet sheet,
int row0, int col0, int row1, int col1) {
ValueEval[] values = new ValueEval[(row1 - row0 + 1) * (col1 - col0 + 1)];
for (int x = row0; sheet != null && x < row1 + 1; x++) {
HSSFRow row = sheet.getRow(x);
for (int y = col0; y < col1 + 1; y++) {
ValueEval cellEval;
if(row == null) {
cellEval = BlankEval.INSTANCE;
} else {
cellEval = getEvalForCell(row.getCell(y), row, sheet, workbook);
}
values[(x - row0) * (col1 - col0 + 1) + (y - col0)] = cellEval;
}
}
return values;
}
/** /**
* returns an appropriate Eval impl instance for the Ptg. The Ptg must be * returns an appropriate Eval impl instance for the Ptg. The Ptg must be
* one of: Area3DPtg, AreaPtg, ReferencePtg, Ref3DPtg, IntPtg, NumberPtg, * one of: Area3DPtg, AreaPtg, ReferencePtg, Ref3DPtg, IntPtg, NumberPtg,
* StringPtg, BoolPtg <br/>special Note: OperationPtg subtypes cannot be * StringPtg, BoolPtg <br/>special Note: OperationPtg subtypes cannot be
* passed here! * passed here!
*
* @param ptg
*/ */
protected static Eval getEvalForPtg(Ptg ptg) { private static Eval getEvalForPtg(Ptg ptg, HSSFSheet sheet, HSSFWorkbook workbook) {
Eval retval = null; if (ptg instanceof RefPtg) {
return new LazyRefEval(((RefPtg) ptg), sheet, workbook);
Class clazz = (Class) VALUE_EVALS_MAP.get(ptg.getClass());
try {
if (ptg instanceof Area3DPtg) {
Constructor constructor = clazz.getConstructor(AREA3D_CONSTRUCTOR_CLASS_ARRAY);
retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
}
else if (ptg instanceof AreaPtg) {
Constructor constructor = clazz.getConstructor(AREA3D_CONSTRUCTOR_CLASS_ARRAY);
retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
}
else if (ptg instanceof RefPtg) {
Constructor constructor = clazz.getConstructor(REFERENCE_CONSTRUCTOR_CLASS_ARRAY);
retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
}
else if (ptg instanceof Ref3DPtg) {
Constructor constructor = clazz.getConstructor(REF3D_CONSTRUCTOR_CLASS_ARRAY);
retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
}
else {
if (ptg instanceof IntPtg || ptg instanceof NumberPtg || ptg instanceof StringPtg
|| ptg instanceof BoolPtg) {
Constructor constructor = clazz.getConstructor(VALUE_CONTRUCTOR_CLASS_ARRAY);
retval = (ValueEval) constructor.newInstance(new Ptg[] { ptg });
}
}
} }
catch (Exception e) { if (ptg instanceof Ref3DPtg) {
throw new RuntimeException("Fatal Error: ", e); Ref3DPtg refPtg = (Ref3DPtg) ptg;
Workbook wb = workbook.getWorkbook();
HSSFSheet xsheet = workbook.getSheetAt(wb.getSheetIndexFromExternSheetIndex(refPtg.getExternSheetIndex()));
return new LazyRefEval(refPtg, xsheet, workbook);
}
if (ptg instanceof AreaPtg) {
return new LazyAreaEval(((AreaPtg) ptg), sheet, workbook);
}
if (ptg instanceof Area3DPtg) {
Area3DPtg a3dp = (Area3DPtg) ptg;
Workbook wb = workbook.getWorkbook();
HSSFSheet xsheet = workbook.getSheetAt(wb.getSheetIndexFromExternSheetIndex(a3dp.getExternSheetIndex()));
return new LazyAreaEval(a3dp, xsheet, workbook);
} }
return retval;
if (ptg instanceof IntPtg) {
return new NumberEval(((IntPtg)ptg).getValue());
}
if (ptg instanceof NumberPtg) {
return new NumberEval(((NumberPtg)ptg).getValue());
}
if (ptg instanceof StringPtg) {
return new StringEval(((StringPtg) ptg).getValue());
}
if (ptg instanceof BoolPtg) {
return BoolEval.valueOf(((BoolPtg) ptg).getValue());
}
if (ptg instanceof ErrPtg) {
return ErrorEval.valueOf(((ErrPtg) ptg).getErrorCode());
}
throw new RuntimeException("Unexpected ptg class (" + ptg.getClass().getName() + ")");
} }
/** /**
* Given a cell, find its type and from that create an appropriate ValueEval * Given a cell, find its type and from that create an appropriate ValueEval
* impl instance and return that. Since the cell could be an external * impl instance and return that. Since the cell could be an external
@ -583,7 +467,7 @@ public class HSSFFormulaEvaluator {
* @param sheet * @param sheet
* @param workbook * @param workbook
*/ */
protected static ValueEval getEvalForCell(HSSFCell cell, HSSFRow row, HSSFSheet sheet, HSSFWorkbook workbook) { public static ValueEval getEvalForCell(HSSFCell cell, HSSFSheet sheet, HSSFWorkbook workbook) {
if (cell == null) { if (cell == null) {
return BlankEval.INSTANCE; return BlankEval.INSTANCE;
@ -605,58 +489,6 @@ public class HSSFFormulaEvaluator {
throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")"); throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")");
} }
/**
* Creates a Ref2DEval for ReferencePtg.
* Non existent cells are treated as RefEvals containing BlankEval.
*/
private static Ref2DEval createRef2DEval(RefPtg ptg, HSSFCell cell,
HSSFSheet sheet, HSSFWorkbook workbook) {
if (cell == null) {
return new Ref2DEval(ptg, BlankEval.INSTANCE);
}
switch (cell.getCellType()) {
case HSSFCell.CELL_TYPE_NUMERIC:
return new Ref2DEval(ptg, new NumberEval(cell.getNumericCellValue()));
case HSSFCell.CELL_TYPE_STRING:
return new Ref2DEval(ptg, new StringEval(cell.getRichStringCellValue().getString()));
case HSSFCell.CELL_TYPE_FORMULA:
return new Ref2DEval(ptg, internalEvaluate(cell, sheet, workbook));
case HSSFCell.CELL_TYPE_BOOLEAN:
return new Ref2DEval(ptg, BoolEval.valueOf(cell.getBooleanCellValue()));
case HSSFCell.CELL_TYPE_BLANK:
return new Ref2DEval(ptg, BlankEval.INSTANCE);
case HSSFCell.CELL_TYPE_ERROR:
return new Ref2DEval(ptg, ErrorEval.valueOf(cell.getErrorCellValue()));
}
throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")");
}
/**
* create a Ref3DEval for Ref3DPtg.
*/
private static Ref3DEval createRef3DEval(Ref3DPtg ptg, HSSFCell cell,
HSSFSheet sheet, HSSFWorkbook workbook) {
if (cell == null) {
return new Ref3DEval(ptg, BlankEval.INSTANCE);
}
switch (cell.getCellType()) {
case HSSFCell.CELL_TYPE_NUMERIC:
return new Ref3DEval(ptg, new NumberEval(cell.getNumericCellValue()));
case HSSFCell.CELL_TYPE_STRING:
return new Ref3DEval(ptg, new StringEval(cell.getRichStringCellValue().getString()));
case HSSFCell.CELL_TYPE_FORMULA:
return new Ref3DEval(ptg, internalEvaluate(cell, sheet, workbook));
case HSSFCell.CELL_TYPE_BOOLEAN:
return new Ref3DEval(ptg, BoolEval.valueOf(cell.getBooleanCellValue()));
case HSSFCell.CELL_TYPE_BLANK:
return new Ref3DEval(ptg, BlankEval.INSTANCE);
case HSSFCell.CELL_TYPE_ERROR:
return new Ref3DEval(ptg, ErrorEval.valueOf(cell.getErrorCellValue()));
}
throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")");
}
/** /**
* Mimics the 'data view' of a cell. This allows formula evaluator * Mimics the 'data view' of a cell. This allows formula evaluator
* to return a CellValue instead of precasting the value to String * to return a CellValue instead of precasting the value to String
@ -752,15 +584,9 @@ public class HSSFFormulaEvaluator {
/** /**
* debug method * debug method
*
* @param formula
* @param sheet
* @param workbook
*/ */
void inspectPtgs(String formula) { void inspectPtgs(String formula) {
FormulaParser fp = new FormulaParser(formula, _workbook); Ptg[] ptgs = FormulaParser.parse(formula, _workbook);
fp.parse();
Ptg[] ptgs = fp.getRPNPtg();
System.out.println("<ptg-group>"); System.out.println("<ptg-group>");
for (int i = 0, iSize = ptgs.length; i < iSize; i++) { for (int i = 0, iSize = ptgs.length; i < iSize; i++) {
System.out.println("<ptg>"); System.out.println("<ptg>");

View File

@ -20,7 +20,8 @@ package org.apache.poi.hssf.record.formula.eval;
import junit.framework.AssertionFailedError; import junit.framework.AssertionFailedError;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.hssf.record.formula.Area3DPtg; import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.functions.EvalFactory;
/** /**
* Tests for <tt>AreaEval</tt> * Tests for <tt>AreaEval</tt>
@ -30,8 +31,8 @@ import org.apache.poi.hssf.record.formula.Area3DPtg;
public final class TestAreaEval extends TestCase { public final class TestAreaEval extends TestCase {
public void testGetValue_bug44950() { public void testGetValue_bug44950() {
// TODO - this test probably isn't testing much anymore
Area3DPtg ptg = new Area3DPtg("B2:D3", (short)0); AreaPtg ptg = new AreaPtg("B2:D3");
NumberEval one = new NumberEval(1); NumberEval one = new NumberEval(1);
ValueEval[] values = { ValueEval[] values = {
one, one,
@ -41,7 +42,7 @@ public final class TestAreaEval extends TestCase {
new NumberEval(5), new NumberEval(5),
new NumberEval(6), new NumberEval(6),
}; };
AreaEval ae = new Area3DEval(ptg, values); AreaEval ae = EvalFactory.createAreaEval(ptg, values);
if (one == ae.getValueAt(1, 2)) { if (one == ae.getValueAt(1, 2)) {
throw new AssertionFailedError("Identified bug 44950 a"); throw new AssertionFailedError("Identified bug 44950 a");
} }

View File

@ -18,12 +18,13 @@
package org.apache.poi.hssf.record.formula.eval; package org.apache.poi.hssf.record.formula.eval;
import junit.framework.TestCase;
import org.apache.poi.hssf.record.formula.AreaPtg; import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.UnaryPlusPtg; import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
import org.apache.poi.hssf.record.formula.functions.EvalFactory;
import org.apache.poi.hssf.record.formula.functions.NumericFunctionInvoker; import org.apache.poi.hssf.record.formula.functions.NumericFunctionInvoker;
import junit.framework.TestCase;
/** /**
* Test for unary plus operator evaluator. * Test for unary plus operator evaluator.
* *
@ -48,9 +49,8 @@ public final class TestUnaryPlusEval extends TestCase {
new NumberEval(37), new NumberEval(37),
new NumberEval(38), new NumberEval(38),
}; };
Eval areaEval = new Area2DEval(areaPtg, values);
Eval[] args = { Eval[] args = {
areaEval, EvalFactory.createAreaEval(areaPtg, values),
}; };
double result = NumericFunctionInvoker.invoke(new UnaryPlusEval(UnaryPlusPtg.instance), args, 10, (short)20); double result = NumericFunctionInvoker.invoke(new UnaryPlusEval(UnaryPlusPtg.instance), args, 10, (short)20);

View File

@ -15,16 +15,16 @@
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 org.apache.poi.hssf.record.formula.AreaPtg; import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.Ref3DPtg;
import org.apache.poi.hssf.record.formula.RefPtg; import org.apache.poi.hssf.record.formula.RefPtg;
import org.apache.poi.hssf.record.formula.eval.Area2DEval;
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.AreaEvalBase;
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.Ref2DEval;
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.RefEvalBase;
import org.apache.poi.hssf.record.formula.eval.ValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval;
/** /**
@ -32,7 +32,7 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
* *
* @author Josh Micich * @author Josh Micich
*/ */
final class EvalFactory { public final class EvalFactory {
private EvalFactory() { private EvalFactory() {
// no instances of this class // no instances of this class
@ -44,6 +44,14 @@ final class EvalFactory {
*/ */
public static AreaEval createAreaEval(String areaRefStr, ValueEval[] values) { public static AreaEval createAreaEval(String areaRefStr, ValueEval[] values) {
AreaPtg areaPtg = new AreaPtg(areaRefStr); AreaPtg areaPtg = new AreaPtg(areaRefStr);
return createAreaEval(areaPtg, values);
}
/**
* Creates a dummy AreaEval
* @param values empty (<code>null</code>) entries in this array will be converted to NumberEval.ZERO
*/
public static AreaEval createAreaEval(AreaPtg areaPtg, ValueEval[] values) {
int nCols = areaPtg.getLastColumn() - areaPtg.getFirstColumn() + 1; int nCols = areaPtg.getLastColumn() - areaPtg.getFirstColumn() + 1;
int nRows = areaPtg.getLastRow() - areaPtg.getFirstRow() + 1; int nRows = areaPtg.getLastRow() - areaPtg.getFirstRow() + 1;
int nExpected = nRows * nCols; int nExpected = nRows * nCols;
@ -55,13 +63,57 @@ final class EvalFactory {
values[i] = NumberEval.ZERO; values[i] = NumberEval.ZERO;
} }
} }
return new Area2DEval(areaPtg, values); return new MockAreaEval(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), NumberEval.ZERO); return createRefEval(refStr, NumberEval.ZERO);
} }
public static RefEval createRefEval(String refStr, ValueEval value) {
return new MockRefEval(new RefPtg(refStr), value);
}
private static final class MockAreaEval extends AreaEvalBase {
private final ValueEval[] _values;
public MockAreaEval(AreaPtg areaPtg, ValueEval[] values) {
super(areaPtg);
_values = values;
}
public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
if (relativeRowIndex < 0 || relativeRowIndex >=getHeight()) {
throw new IllegalArgumentException("row index out of range");
}
int width = getWidth();
if (relativeColumnIndex < 0 || relativeColumnIndex >=width) {
throw new IllegalArgumentException("column index out of range");
}
int oneDimensionalIndex = relativeRowIndex * width + relativeColumnIndex;
return _values[oneDimensionalIndex];
}
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
throw new RuntimeException("Operation not implemented on this mock object");
}
}
private static final class MockRefEval extends RefEvalBase {
private final ValueEval _value;
public MockRefEval(RefPtg ptg, ValueEval value) {
super(ptg.getRow(), ptg.getColumn());
_value = value;
}
public MockRefEval(Ref3DPtg ptg, ValueEval value) {
super(ptg.getRow(), ptg.getColumn());
_value = value;
}
public ValueEval getInnerValueEval() {
return _value;
}
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
throw new RuntimeException("Operation not implemented on this mock object");
}
}
} }

View File

@ -21,9 +21,7 @@ import junit.framework.AssertionFailedError;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.RefPtg; import org.apache.poi.hssf.record.formula.RefPtg;
import org.apache.poi.hssf.record.formula.eval.Area2DEval;
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.BlankEval; 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;
@ -91,7 +89,7 @@ public final class TestCountFuncs extends TestCase {
BoolEval.TRUE, BoolEval.TRUE,
BlankEval.INSTANCE, BlankEval.INSTANCE,
}; };
range = createAreaEval("A1:B3", values); range = EvalFactory.createAreaEval("A1:B3", values);
confirmCountIf(2, range, BoolEval.TRUE); confirmCountIf(2, range, BoolEval.TRUE);
// when criteria is numeric // when criteria is numeric
@ -103,7 +101,7 @@ public final class TestCountFuncs extends TestCase {
new NumberEval(2), new NumberEval(2),
BoolEval.TRUE, BoolEval.TRUE,
}; };
range = createAreaEval("A1:B3", values); range = EvalFactory.createAreaEval("A1:B3", values);
confirmCountIf(3, range, new NumberEval(2)); confirmCountIf(3, range, new NumberEval(2));
// note - same results when criteria is a string that parses as the number with the same value // note - same results when criteria is a string that parses as the number with the same value
confirmCountIf(3, range, new StringEval("2.00")); confirmCountIf(3, range, new StringEval("2.00"));
@ -126,20 +124,15 @@ public final class TestCountFuncs extends TestCase {
new NumberEval(25), new NumberEval(25),
new NumberEval(25), new NumberEval(25),
}; };
Area2DEval arg0 = new Area2DEval(new AreaPtg("C1:C6"), values); AreaEval arg0 = EvalFactory.createAreaEval("C1:C6", values);
Ref2DEval criteriaArg = new Ref2DEval(new RefPtg("A1"), new NumberEval(25)); ValueEval criteriaArg = EvalFactory.createRefEval("A1", new NumberEval(25));
Eval[] args= { arg0, criteriaArg, }; Eval[] args= { arg0, criteriaArg, };
double actual = NumericFunctionInvoker.invoke(new Countif(), args); double actual = NumericFunctionInvoker.invoke(new Countif(), args);
assertEquals(4, actual, 0D); assertEquals(4, actual, 0D);
} }
private static AreaEval createAreaEval(String areaRefStr, ValueEval[] values) {
return new Area2DEval(new AreaPtg(areaRefStr), values);
}
private static void confirmCountA(int expected, Eval[] args) { private static void confirmCountA(int expected, Eval[] args) {
double result = NumericFunctionInvoker.invoke(new Counta(), args); double result = NumericFunctionInvoker.invoke(new Counta(), args);
assertEquals(expected, result, 0); assertEquals(expected, result, 0);

View File

@ -19,8 +19,7 @@ package org.apache.poi.hssf.record.formula.functions;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.hssf.record.formula.AreaPtg; import org.apache.poi.hssf.record.formula.eval.AreaEval;
import org.apache.poi.hssf.record.formula.eval.Area2DEval;
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.NumberEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval;
@ -68,7 +67,7 @@ public final class TestIndex extends TestCase {
for (int i = 0; i < values.length; i++) { for (int i = 0; i < values.length; i++) {
values[i] = new NumberEval(dValues[i]); values[i] = new NumberEval(dValues[i]);
} }
Area2DEval arg0 = new Area2DEval(new AreaPtg(areaRefString), values); AreaEval arg0 = EvalFactory.createAreaEval(areaRefString, values);
Eval[] args; Eval[] args;
if (colNum > 0) { if (colNum > 0) {

View File

@ -19,8 +19,6 @@ package org.apache.poi.hssf.record.formula.functions;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.eval.Area2DEval;
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.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;
@ -54,13 +52,6 @@ public final class TestMatch extends TestCase {
NumericValueEval nve = (NumericValueEval)actualEval; NumericValueEval nve = (NumericValueEval)actualEval;
assertEquals(expected, nve.getNumberValue(), 0); assertEquals(expected, nve.getNumberValue(), 0);
} }
/**
* Convenience method
* @return <code>new Area2DEval(new AreaPtg(ref), values)</code>
*/
private static AreaEval createAreaEval(String ref, ValueEval[] values) {
return new Area2DEval(new AreaPtg(ref), values);
}
public void testSimpleNumber() { public void testSimpleNumber() {
@ -72,7 +63,7 @@ public final class TestMatch extends TestCase {
new NumberEval(25), new NumberEval(25),
}; };
AreaEval ae = createAreaEval("A1:A5", values); AreaEval ae = EvalFactory.createAreaEval("A1:A5", values);
confirmInt(2, invokeMatch(new NumberEval(5), ae, MATCH_LARGEST_LTE)); confirmInt(2, invokeMatch(new NumberEval(5), ae, MATCH_LARGEST_LTE));
confirmInt(2, invokeMatch(new NumberEval(5), ae, MATCH_EXACT)); confirmInt(2, invokeMatch(new NumberEval(5), ae, MATCH_EXACT));
@ -92,7 +83,7 @@ public final class TestMatch extends TestCase {
new NumberEval(4), new NumberEval(4),
}; };
AreaEval ae = createAreaEval("A1:A5", values); AreaEval ae = EvalFactory.createAreaEval("A1:A5", values);
confirmInt(2, invokeMatch(new NumberEval(10), ae, MATCH_SMALLEST_GTE)); confirmInt(2, invokeMatch(new NumberEval(10), ae, MATCH_SMALLEST_GTE));
confirmInt(2, invokeMatch(new NumberEval(10), ae, MATCH_EXACT)); confirmInt(2, invokeMatch(new NumberEval(10), ae, MATCH_EXACT));
@ -112,7 +103,7 @@ public final class TestMatch extends TestCase {
new StringEval("Ian"), new StringEval("Ian"),
}; };
AreaEval ae = createAreaEval("A1:A5", values); AreaEval ae = EvalFactory.createAreaEval("A1:A5", values);
// Note String comparisons are case insensitive // Note String comparisons are case insensitive
confirmInt(3, invokeMatch(new StringEval("Ed"), ae, MATCH_LARGEST_LTE)); confirmInt(3, invokeMatch(new StringEval("Ed"), ae, MATCH_LARGEST_LTE));
@ -132,7 +123,7 @@ public final class TestMatch extends TestCase {
BoolEval.TRUE, BoolEval.TRUE,
}; };
AreaEval ae = createAreaEval("A1:A4", values); AreaEval ae = EvalFactory.createAreaEval("A1:A4", values);
// Note String comparisons are case insensitive // Note String comparisons are case insensitive
confirmInt(2, invokeMatch(BoolEval.FALSE, ae, MATCH_LARGEST_LTE)); confirmInt(2, invokeMatch(BoolEval.FALSE, ae, MATCH_LARGEST_LTE));
@ -159,7 +150,7 @@ public final class TestMatch extends TestCase {
new StringEval("Ed"), new StringEval("Ed"),
}; };
AreaEval ae = createAreaEval("A1:A13", values); AreaEval ae = EvalFactory.createAreaEval("A1:A13", values);
assertEquals(ErrorEval.NA, invokeMatch(new StringEval("Aaron"), ae, MATCH_LARGEST_LTE)); assertEquals(ErrorEval.NA, invokeMatch(new StringEval("Aaron"), ae, MATCH_LARGEST_LTE));
@ -197,9 +188,9 @@ public final class TestMatch extends TestCase {
new NumberEval(25), new NumberEval(25),
}; };
AreaEval ae = createAreaEval("A1:A5", values); AreaEval ae = EvalFactory.createAreaEval("A1:A5", values);
AreaEval matchAE = createAreaEval("C1:C1", new ValueEval[] { MATCH_LARGEST_LTE, }); AreaEval matchAE = EvalFactory.createAreaEval("C1:C1", new ValueEval[] { MATCH_LARGEST_LTE, });
try { try {
confirmInt(4, invokeMatch(new NumberEval(10), ae, matchAE)); confirmInt(4, invokeMatch(new NumberEval(10), ae, matchAE));

View File

@ -20,6 +20,8 @@
*/ */
package org.apache.poi.hssf.record.formula.functions; package org.apache.poi.hssf.record.formula.functions;
import org.apache.poi.hssf.record.formula.functions.XYNumericFunction.Accumulator;
/** /**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt; * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
@ -566,97 +568,97 @@ public class TestMathX extends AbstractNumericTestCase {
} }
public void testSumx2my2() { public void testSumx2my2() {
double d = 0;
double[] xarr = null; double[] xarr = null;
double[] yarr = null; double[] yarr = null;
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
d = MathX.sumx2my2(xarr, yarr); confirmSumx2my2(xarr, yarr, 100);
assertEquals("sumx2my2 ", 100, d);
xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10}; xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
d = MathX.sumx2my2(xarr, yarr); confirmSumx2my2(xarr, yarr, 100);
assertEquals("sumx2my2 ", 100, d);
xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
d = MathX.sumx2my2(xarr, yarr); confirmSumx2my2(xarr, yarr, -100);
assertEquals("sumx2my2 ", -100, d);
xarr = new double[]{10}; xarr = new double[]{10};
yarr = new double[]{9}; yarr = new double[]{9};
d = MathX.sumx2my2(xarr, yarr); confirmSumx2my2(xarr, yarr, 19);
assertEquals("sumx2my2 ", 19, d);
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
d = MathX.sumx2my2(xarr, yarr); confirmSumx2my2(xarr, yarr, 0);
assertEquals("sumx2my2 ", 0, d);
} }
public void testSumx2py2() { public void testSumx2py2() {
double d = 0;
double[] xarr = null; double[] xarr = null;
double[] yarr = null; double[] yarr = null;
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
d = MathX.sumx2py2(xarr, yarr); confirmSumx2py2(xarr, yarr, 670);
assertEquals("sumx2py2 ", 670, d);
xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10}; xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
d = MathX.sumx2py2(xarr, yarr); confirmSumx2py2(xarr, yarr, 670);
assertEquals("sumx2py2 ", 670, d);
xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
d = MathX.sumx2py2(xarr, yarr); confirmSumx2py2(xarr, yarr, 670);
assertEquals("sumx2py2 ", 670, d);
xarr = new double[]{10}; xarr = new double[]{10};
yarr = new double[]{9}; yarr = new double[]{9};
d = MathX.sumx2py2(xarr, yarr); confirmSumx2py2(xarr, yarr, 181);
assertEquals("sumx2py2 ", 181, d);
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
d = MathX.sumx2py2(xarr, yarr); confirmSumx2py2(xarr, yarr, 770);
assertEquals("sumx2py2 ", 770, d);
} }
public void testSumxmy2() { public void testSumxmy2() {
double d = 0;
double[] xarr = null; double[] xarr = null;
double[] yarr = null; double[] yarr = null;
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
d = MathX.sumxmy2(xarr, yarr); confirmSumxmy2(xarr, yarr, 10);
assertEquals("sumxmy2 ", 10, d);
xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10}; xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
d = MathX.sumxmy2(xarr, yarr); confirmSumxmy2(xarr, yarr, 1330);
assertEquals("sumxmy2 ", 1330, d);
xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
d = MathX.sumxmy2(xarr, yarr); confirmSumxmy2(xarr, yarr, 10);
assertEquals("sumxmy2 ", 10, d);
xarr = new double[]{10}; xarr = new double[]{10};
yarr = new double[]{9}; yarr = new double[]{9};
d = MathX.sumxmy2(xarr, yarr); confirmSumxmy2(xarr, yarr, 1);
assertEquals("sumxmy2 ", 1, d);
xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
d = MathX.sumxmy2(xarr, yarr); confirmSumxmy2(xarr, yarr, 0);
assertEquals("sumxmy2 ", 0, d); }
private static void confirmSumx2my2(double[] xarr, double[] yarr, double expectedResult) {
confirmXY(new Sumx2my2().createAccumulator(), xarr, yarr, expectedResult);
}
private static void confirmSumx2py2(double[] xarr, double[] yarr, double expectedResult) {
confirmXY(new Sumx2py2().createAccumulator(), xarr, yarr, expectedResult);
}
private static void confirmSumxmy2(double[] xarr, double[] yarr, double expectedResult) {
confirmXY(new Sumxmy2().createAccumulator(), xarr, yarr, expectedResult);
}
private static void confirmXY(Accumulator acc, double[] xarr, double[] yarr,
double expectedResult) {
double result = 0.0;
for (int i = 0; i < xarr.length; i++) {
result += acc.accumulate(xarr[i], yarr[i]);
}
assertEquals(expectedResult, result, 0.0);
} }
public void testRound() { public void testRound() {

View File

@ -17,21 +17,17 @@
package org.apache.poi.hssf.record.formula.functions; package org.apache.poi.hssf.record.formula.functions;
import org.apache.poi.hssf.record.formula.AreaPtg; import junit.framework.TestCase;
import org.apache.poi.hssf.record.formula.RefPtg;
import org.apache.poi.hssf.record.formula.eval.Area2DEval;
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.BlankEval; 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.NumberEval;
import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
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.StringEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval;
import junit.framework.TestCase;
/** /**
* Tests for Excel function MID() * Tests for Excel function MID()
* *
@ -76,8 +72,8 @@ public final class TestMid extends TestCase {
confirmMid(new NumberEval(123456), new StringEval("3.1"), new StringEval("2.9"), "34"); confirmMid(new NumberEval(123456), new StringEval("3.1"), new StringEval("2.9"), "34");
// startPos is 1x1 area ref, numChars is cell ref // startPos is 1x1 area ref, numChars is cell ref
AreaEval aeStart = new Area2DEval(new AreaPtg("A1:A1"), new ValueEval[] { new NumberEval(2), } ); AreaEval aeStart = EvalFactory.createAreaEval("A1:A1", new ValueEval[] { new NumberEval(2), } );
RefEval reNumChars = new Ref2DEval(new RefPtg("B1"), new NumberEval(3)); RefEval reNumChars = EvalFactory.createRefEval("B1", new NumberEval(3));
confirmMid(new StringEval("galactic"), aeStart, reNumChars, "ala"); confirmMid(new StringEval("galactic"), aeStart, reNumChars, "ala");
confirmMid(new StringEval("galactic"), new NumberEval(3.1), BlankEval.INSTANCE, ""); confirmMid(new StringEval("galactic"), new NumberEval(3.1), BlankEval.INSTANCE, "");

View File

@ -17,18 +17,16 @@
package org.apache.poi.hssf.record.formula.functions; package org.apache.poi.hssf.record.formula.functions;
import org.apache.poi.hssf.record.formula.RefPtg; import junit.framework.TestCase;
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.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.Ref2DEval;
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 junit.framework.TestCase;
/** /**
* Test cases for SUMPRODUCT() * Test cases for SUMPRODUCT()
* *
@ -50,7 +48,7 @@ public final class TestSumproduct extends TestCase {
public void testScalarSimple() { public void testScalarSimple() {
RefEval refEval = new Ref2DEval(new RefPtg("A1"), new NumberEval(3)); RefEval refEval = EvalFactory.createRefEval("A1", new NumberEval(3));
Eval[] args = { Eval[] args = {
refEval, refEval,
new NumberEval(2), new NumberEval(2),

View File

@ -17,18 +17,16 @@
package org.apache.poi.hssf.record.formula.functions; package org.apache.poi.hssf.record.formula.functions;
import org.apache.poi.hssf.record.formula.RefPtg; import junit.framework.TestCase;
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.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.NumberEval;
import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
import org.apache.poi.hssf.record.formula.eval.StringEval; 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;
import junit.framework.TestCase;
/** /**
* Test cases for Excel function T() * Test cases for Excel function T()
* *
@ -50,7 +48,7 @@ public final class TestTFunc extends TestCase {
* where cell A1 has the specified innerValue * where cell A1 has the specified innerValue
*/ */
private Eval invokeTWithReference(ValueEval innerValue) { private Eval invokeTWithReference(ValueEval innerValue) {
Eval arg = new Ref2DEval(new RefPtg((short)1, (short)1, false, false), innerValue); Eval arg = EvalFactory.createRefEval("$B$2", innerValue);
return invokeT(arg); return invokeT(arg);
} }

View File

@ -19,8 +19,6 @@ package org.apache.poi.hssf.record.formula.functions;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.eval.Area2DEval;
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.NumberEval;
@ -100,7 +98,7 @@ public final class TestXYNumericFunction extends TestCase {
private static ValueEval createAreaEval(ValueEval[] values) { private static ValueEval createAreaEval(ValueEval[] values) {
String refStr = "A1:A" + values.length; String refStr = "A1:A" + values.length;
return new Area2DEval(new AreaPtg(refStr), values); return EvalFactory.createAreaEval(refStr, values);
} }
public void testErrors() { public void testErrors() {