From: Javen O'Neal Date: Sat, 11 Jun 2016 02:10:32 +0000 (+0000) Subject: bug 57840: cache XSSFEvaluationCell and XSSFEvaluationSheet instances (30% evaluation... X-Git-Tag: REL_3_15_BETA2~156 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=e5bc4d22ce9c37782ed9d847c62211cf0fd8d125;p=poi.git 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 --- diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationSheet.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationSheet.java index d0b3f3b1a4..329f78f3ed 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationSheet.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationSheet.java @@ -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 _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; - } - XSSFCell cell = row.getCell(columnIndex); - if (cell == null) { - return null; - } - return new XSSFEvaluationCell(cell, this); + // cache for performance: ~30% speedup due to caching + if (_cellCache == null) { + _cellCache = new HashMap(_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); + } + } + } + + 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; + } } } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java index 46e5a54a6c..413a1fab2b 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java @@ -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