From e3beb3abdd844cf18e58f39de07724dd3137a506 Mon Sep 17 00:00:00 2001 From: Javen O'Neal Date: Sat, 11 Jun 2016 02:10:32 +0000 Subject: [PATCH] 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 --- .../xssf/usermodel/XSSFEvaluationSheet.java | 56 ++++++++++++++++--- .../usermodel/XSSFEvaluationWorkbook.java | 18 +++++- 2 files changed, 64 insertions(+), 10 deletions(-) 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 d0b3f3b1a..329f78f3e 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 46e5a54a6..413a1fab2 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