bug 57840: cache XSSFEvaluationCell and XSSFEvaluationSheet instances (30% evaluation speedup due to caching and faster cell lookup); patch from Greg Woolsey

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1747838 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Javen O'Neal 2016-06-11 02:10:32 +00:00
parent 6d03eafcfe
commit e3beb3abdd
2 changed files with 64 additions and 10 deletions

View File

@ -17,8 +17,13 @@
package org.apache.poi.xssf.usermodel;
import java.util.HashMap;
import java.util.Map;
import org.apache.poi.ss.formula.EvaluationCell;
import org.apache.poi.ss.formula.EvaluationSheet;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
/**
* XSSF wrapper for a sheet under evaluation
@ -26,6 +31,7 @@ import org.apache.poi.ss.formula.EvaluationSheet;
final class XSSFEvaluationSheet implements EvaluationSheet {
private final XSSFSheet _xs;
private Map<CellKey, EvaluationCell> _cellCache;
public XSSFEvaluationSheet(XSSFSheet sheet) {
_xs = sheet;
@ -35,14 +41,46 @@ final class XSSFEvaluationSheet implements EvaluationSheet {
return _xs;
}
public EvaluationCell getCell(int rowIndex, int columnIndex) {
XSSFRow row = _xs.getRow(rowIndex);
if (row == null) {
return null;
// cache for performance: ~30% speedup due to caching
if (_cellCache == null) {
_cellCache = new HashMap<CellKey, EvaluationCell>(_xs.getLastRowNum()*3);
for (final Row row : _xs) {
final int rowNum = row.getRowNum();
for (final Cell cell : row) {
// cast is safe, the iterator is just defined using the interface
final CellKey key = new CellKey(rowNum, cell.getColumnIndex());
final EvaluationCell evalcell = new XSSFEvaluationCell((XSSFCell) cell, this);
_cellCache.put(key, evalcell);
}
XSSFCell cell = row.getCell(columnIndex);
if (cell == null) {
return null;
}
return new XSSFEvaluationCell(cell, this);
}
return _cellCache.get(new CellKey(rowIndex, columnIndex));
}
private static class CellKey {
private final int _row;
private final int _col;
private final int _hash;
protected CellKey(int row, int col) {
_row = row;
_col = col;
_hash = (17 * 37 + row) * 37 + col;
}
@Override
public int hashCode() {
return _hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
// assumes other object is one of us, otherwise ClassCastException is thrown
final CellKey oKey = (CellKey) obj;
return _row == oKey._row && _col == oKey._col;
}
}
}

View File

@ -27,6 +27,8 @@ import org.apache.poi.ss.formula.ptg.Ptg;
* Internal POI use only
*/
public final class XSSFEvaluationWorkbook extends BaseXSSFEvaluationWorkbook {
private XSSFEvaluationSheet[] _sheetCache;
public static XSSFEvaluationWorkbook create(XSSFWorkbook book) {
if (book == null) {
return null;
@ -46,7 +48,21 @@ public final class XSSFEvaluationWorkbook extends BaseXSSFEvaluationWorkbook {
@Override
public EvaluationSheet getSheet(int sheetIndex) {
return new XSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex));
// Performance optimization: build sheet cache the first time this is called
// to avoid re-creating the XSSFEvaluationSheet each time a new cell is evaluated
// EvaluationWorkbooks make not guarentee to syncronize changes made to
// the underlying workbook after the EvaluationWorkbook is created.
if (_sheetCache == null) {
_sheetCache = new XSSFEvaluationSheet[_uBook.getNumberOfSheets()];
for (int i=0; i < _uBook.getNumberOfSheets(); i++) {
_sheetCache[i] = new XSSFEvaluationSheet(_uBook.getSheetAt(i));
}
}
if (sheetIndex < 0 || sheetIndex >= _sheetCache.length) {
// do this to reuse the out-of-bounds logic and message from XSSFWorkbook
_uBook.getSheetAt(sheetIndex);
}
return _sheetCache[sheetIndex];
}
@Override