Added getRow() and getColumn() functions to TwoDEval to simplify logic in INDEX implementation.

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@893063 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2009-12-22 03:00:21 +00:00
parent 4b14bbc353
commit 5126999358
5 changed files with 85 additions and 35 deletions

View File

@ -17,7 +17,6 @@
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.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.EvaluationException;
@ -53,7 +52,7 @@ public final class Index implements Function2Arg, Function3Arg, Function4Arg {
int columnIx = 0;
try {
int rowIx = resolveIndexArg(arg1, srcRowIndex, srcColumnIndex);
if (!reference.isColumn()) {
if (!reference.isRow()) {
// always an error with 2-D area refs
@ -65,7 +64,7 @@ public final class Index implements Function2Arg, Function3Arg, Function4Arg {
columnIx = rowIx;
rowIx = 0;
}
return getValueFromArea(reference, rowIx, columnIx);
} catch (EvaluationException e) {
return e.getErrorEval();
@ -125,45 +124,27 @@ public final class Index implements Function2Arg, Function3Arg, Function4Arg {
throws EvaluationException {
assert pRowIx >= 0;
assert pColumnIx >= 0;
int width = ae.getWidth();
int height = ae.getHeight();
int relFirstRowIx;
int relLastRowIx;
if ((pRowIx == 0)) {
relFirstRowIx = 0;
relLastRowIx = height-1;
} else {
TwoDEval result = ae;
if (pRowIx != 0) {
// Slightly irregular logic for bounds checking errors
if (pRowIx > height) {
if (pRowIx > ae.getHeight()) {
// high bounds check fail gives #REF! if arg was explicitly passed
throw new EvaluationException(ErrorEval.REF_INVALID);
}
int rowIx = pRowIx-1;
relFirstRowIx = rowIx;
relLastRowIx = rowIx;
result = result.getRow(pRowIx-1);
}
int relFirstColIx;
int relLastColIx;
if ((pColumnIx == 0)) {
relFirstColIx = 0;
relLastColIx = width-1;
} else {
if (pColumnIx != 0) {
// Slightly irregular logic for bounds checking errors
if (pColumnIx > width) {
if (pColumnIx > ae.getWidth()) {
// high bounds check fail gives #REF! if arg was explicitly passed
throw new EvaluationException(ErrorEval.REF_INVALID);
}
int columnIx = pColumnIx-1;
relFirstColIx = columnIx;
relLastColIx = columnIx;
result = result.getColumn(pColumnIx-1);
}
AreaEval x = ((AreaEval) ae);
return x.offset(relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
return result;
}

View File

@ -57,6 +57,23 @@ final class LazyAreaEval extends AreaEvalBase {
return new LazyAreaEval(area, _evaluator);
}
public LazyAreaEval getRow(int rowIndex) {
if (rowIndex >= getHeight()) {
throw new IllegalArgumentException("Invalid rowIndex " + rowIndex
+ ". Allowable range is (0.." + getHeight() + ").");
}
int absRowIx = getFirstRow() + rowIndex;
return new LazyAreaEval(absRowIx, getFirstColumn(), absRowIx, getLastColumn(), _evaluator);
}
public LazyAreaEval getColumn(int columnIndex) {
if (columnIndex >= getWidth()) {
throw new IllegalArgumentException("Invalid columnIndex " + columnIndex
+ ". Allowable range is (0.." + getWidth() + ").");
}
int absColIx = getFirstColumn() + columnIndex;
return new LazyAreaEval(getFirstRow(), absColIx, getLastRow(), absColIx, _evaluator);
}
public String toString() {
CellReference crA = new CellReference(getFirstRow(), getFirstColumn());
CellReference crB = new CellReference(getLastRow(), getLastColumn());

View File

@ -28,11 +28,11 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
public interface TwoDEval extends ValueEval {
/**
* @param row relative row index (zero based)
* @param col relative column index (zero based)
* @return element at the specified row and col position
* @param rowIndex relative row index (zero based)
* @param columnIndex relative column index (zero based)
* @return element at the specified row and column position
*/
public ValueEval getValue(int row, int col);
ValueEval getValue(int rowIndex, int columnIndex);
int getWidth();
int getHeight();
@ -48,4 +48,15 @@ public interface TwoDEval extends ValueEval {
* the trivial case when the area has just a single cell.
*/
boolean isColumn();
/**
* @param rowIndex relative row index (zero based)
* @return a single row {@link TwoDEval}
*/
TwoDEval getRow(int rowIndex);
/**
* @param columnIndex relative column index (zero based)
* @return a single column {@link TwoDEval}
*/
TwoDEval getColumn(int columnIndex);
}

View File

@ -28,6 +28,7 @@ import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.AreaReference;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.ss.formula.TwoDEval;
import org.apache.poi.ss.usermodel.CellValue;
/**
@ -90,6 +91,9 @@ public final class TestRangeEval extends TestCase {
public MockAreaEval(AreaI ptg) {
super(ptg);
}
private MockAreaEval(int firstRow, int firstColumn, int lastRow, int lastColumn) {
super(firstRow, firstColumn, lastRow, lastColumn);
}
public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
throw new RuntimeException("not expected to be called during this test");
}
@ -100,6 +104,20 @@ public final class TestRangeEval extends TestCase {
return new MockAreaEval(area);
}
public TwoDEval getRow(int rowIndex) {
if (rowIndex >= getHeight()) {
throw new IllegalArgumentException("Invalid rowIndex " + rowIndex
+ ". Allowable range is (0.." + getHeight() + ").");
}
return new MockAreaEval(rowIndex, getFirstColumn(), rowIndex, getLastColumn());
}
public TwoDEval getColumn(int columnIndex) {
if (columnIndex >= getWidth()) {
throw new IllegalArgumentException("Invalid columnIndex " + columnIndex
+ ". Allowable range is (0.." + getWidth() + ").");
}
return new MockAreaEval(getFirstRow(), columnIndex, getLastRow(), columnIndex);
}
}
public void testRangeUsingOffsetFunc_bug46948() {

View File

@ -27,6 +27,7 @@ import org.apache.poi.hssf.record.formula.eval.NumberEval;
import org.apache.poi.hssf.record.formula.eval.RefEval;
import org.apache.poi.hssf.record.formula.eval.RefEvalBase;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
import org.apache.poi.ss.formula.TwoDEval;
/**
* Test helper class for creating mock <code>Eval</code> objects
@ -119,7 +120,7 @@ public final class EvalFactory {
int width = relLastColIx - relFirstColIx + 1;
ValueEval[] result = new ValueEval[height * width];
for (int r=0; r<height; r++) {
int srcRowIx = r + relFirstRowIx;
int srcRowIx = r + relFirstRowIx;
for (int c=0; c<width; c++) {
int srcColIx = c + relFirstColIx;
int destIx = r * width + c;
@ -129,6 +130,28 @@ public final class EvalFactory {
}
return result;
}
public TwoDEval getRow(int rowIndex) {
if (rowIndex >= getHeight()) {
throw new IllegalArgumentException("Invalid rowIndex " + rowIndex
+ ". Allowable range is (0.." + getHeight() + ").");
}
ValueEval[] values = new ValueEval[getWidth()];
for (int i = 0; i < values.length; i++) {
values[i] = getRelativeValue(rowIndex, i);
}
return new MockAreaEval(rowIndex, getFirstColumn(), rowIndex, getLastColumn(), values);
}
public TwoDEval getColumn(int columnIndex) {
if (columnIndex >= getWidth()) {
throw new IllegalArgumentException("Invalid columnIndex " + columnIndex
+ ". Allowable range is (0.." + getWidth() + ").");
}
ValueEval[] values = new ValueEval[getHeight()];
for (int i = 0; i < values.length; i++) {
values[i] = getRelativeValue(i, columnIndex);
}
return new MockAreaEval(getFirstRow(), columnIndex, getLastRow(), columnIndex, values);
}
}
private static final class MockRefEval extends RefEvalBase {