Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Numeric Array Formula and Matrix Function Patch Applied #69

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .classpath
Expand Up @@ -34,5 +34,6 @@
<classpathentry exported="true" kind="lib" path="lib/commons-codec-1.10.jar"/>
<classpathentry exported="true" kind="lib" path="lib/commons-logging-1.2.jar"/>
<classpathentry exported="true" kind="lib" path="lib/commons-collections4-4.1.jar"/>
<classpathentry kind="lib" path="lib/commons-math3-3.6.1.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
6 changes: 4 additions & 2 deletions build.gradle
Expand Up @@ -73,7 +73,7 @@ subprojects {
// See https://github.com/melix/japicmp-gradle-plugin
apply plugin: 'me.champeau.gradle.japicmp'

version = '3.16-beta3'
version = '3.18-beta1'
ext {
japicmpversion = '3.15'
}
Expand Down Expand Up @@ -150,7 +150,8 @@ project('main') {
compile 'commons-codec:commons-codec:1.10'
compile 'commons-logging:commons-logging:1.2'
compile 'org.apache.commons:commons-collections4:4.1'

compile 'org.apache.commons:commons-math3:3.6.1'

testCompile 'junit:junit:4.12'
}

Expand Down Expand Up @@ -196,6 +197,7 @@ project('ooxml') {
dependencies {
compile 'org.apache.xmlbeans:xmlbeans:2.6.0'
compile 'org.apache.commons:commons-collections4:4.1'
compile 'org.apache.commons:commons-math3:3.6.1'
compile 'org.apache.santuario:xmlsec:2.0.6'
compile 'org.bouncycastle:bcpkix-jdk15on:1.54'
compile 'com.github.virtuald:curvesapi:1.04'
Expand Down
8 changes: 8 additions & 0 deletions build.xml
Expand Up @@ -178,6 +178,9 @@ under the License.
<property name="main.commons-collections4.jar" location="${main.lib}/commons-collections4-4.1.jar"/>
<property name="main.commons-collections4.url"
value="${repository.m2}/maven2/org/apache/commons/commons-collections4/4.1/commons-collections4-4.1.jar"/>
<property name="main.commons-math3.jar" location="${main.lib}/commons-math3-3.6.1.jar"/>
<property name="main.commons-math3.url"
value="${repository.m2}/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar"/>

<!-- xml signature libs -->
<property name="dsig.xmlsec.jar" location="${compile.lib}/xmlsec-2.0.6.jar"/>
Expand Down Expand Up @@ -326,6 +329,7 @@ under the License.
<pathelement location="${main.commons-logging.jar}"/>
<pathelement location="${main.commons-codec.jar}"/>
<pathelement location="${main.commons-collections4.jar}"/>
<pathelement location="${main.commons-math3.jar}"/>
</path>

<!-- some libraries should only be required for compiling/running tests -->
Expand Down Expand Up @@ -631,6 +635,7 @@ under the License.
<available file="${dsig.xmlsec.jar}"/>
<available file="${dsig.sl4j-api.jar}"/>
<available file="${main.commons-collections4.jar}"/>
<available file="${main.commons-math3.jar}"/>
</and>
<isset property="disconnected"/>
</or>
Expand All @@ -652,6 +657,7 @@ under the License.
<downloadfile src="${asm.url}" dest="${asm.jar}"/>
<downloadfile src="${jacoco.url}" dest="${jacoco.zip}"/>
<downloadfile src="${main.commons-collections4.url}" dest="${main.commons-collections4.jar}"/>
<downloadfile src="${main.commons-math3.url}" dest="${main.commons-math3.jar}"/>
<unzip src="${jacoco.zip}" dest=".">
<patternset>
<include name="lib/*.jar"/>
Expand Down Expand Up @@ -2043,6 +2049,7 @@ under the License.
<include name="commons-codec-*.jar"/>
<include name="commons-logging-*.jar"/>
<include name="commons-collections4-*.jar"/>
<include name="commons-math3-*.jar"/>
<include name="junit-*.jar"/>
<include name="log4j-*.jar"/>
</fileset>
Expand Down Expand Up @@ -2305,6 +2312,7 @@ under the License.
<auxClasspath path="${ooxml.curvesapi.jar}" />
<auxClasspath path="${ooxml.xmlbeans26.jar}" />
<auxClasspath path="${main.commons-collections4.jar}" />
<auxClasspath path="${main.commons-math3.jar}" />
<auxClasspath path="${main.commons-codec.jar}" />
<auxClasspath path="${main.commons-logging.jar}" />
<auxClasspath path="${main.junit.jar}" />
Expand Down
5 changes: 5 additions & 0 deletions sonar/main/pom.xml
Expand Up @@ -115,6 +115,11 @@
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.6.1</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
Expand Down
13 changes: 13 additions & 0 deletions src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationCell.java
Expand Up @@ -20,6 +20,8 @@ Licensed to the Apache Software Foundation (ASF) under one or more
import org.apache.poi.ss.formula.EvaluationCell;
import org.apache.poi.ss.formula.EvaluationSheet;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.util.CellRangeAddress;

/**
* HSSF wrapper for a cell under evaluation
*/
Expand Down Expand Up @@ -93,6 +95,17 @@ public EvaluationSheet getSheet() {
public String getStringCellValue() {
return _cell.getRichStringCellValue().getString();
}

@Override
public CellRangeAddress getArrayFormulaRange() {
return _cell.getArrayFormulaRange();
}

@Override
public boolean isPartOfArrayFormulaGroup() {
return _cell.isPartOfArrayFormulaGroup();
}

/**
* Will return {@link CellType} in a future version of POI.
* For forwards compatibility, do not hard-code cell type literals in your code.
Expand Down
131 changes: 131 additions & 0 deletions src/java/org/apache/poi/ss/formula/CacheAreaEval.java
@@ -0,0 +1,131 @@
/* ====================================================================
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.ss.formula;

import org.apache.poi.ss.formula.TwoDEval;
import org.apache.poi.ss.formula.eval.AreaEval;
import org.apache.poi.ss.formula.eval.AreaEvalBase;
import org.apache.poi.ss.formula.eval.BlankEval;
import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.ptg.AreaI;
import org.apache.poi.ss.formula.ptg.AreaI.OffsetArea;
import org.apache.poi.ss.util.CellReference;

/**
* @author Robert Hulbert
* Provides holding structure for temporary values in arrays during the evaluation process.
* As such, Row/Column references do not actually correspond to data in the file.
*/

public final class CacheAreaEval extends AreaEvalBase {

/* Value Containter */
private final ValueEval[] _values;

public CacheAreaEval(AreaI ptg, ValueEval[] values) {
super(ptg);
_values = values;
}

public CacheAreaEval(int firstRow, int firstColumn, int lastRow, int lastColumn, ValueEval[] values) {
super(firstRow, firstColumn, lastRow, lastColumn);
_values = values;
}

public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
return getRelativeValue(-1, relativeRowIndex, relativeColumnIndex);
}

public ValueEval getRelativeValue(int sheetIndex, int relativeRowIndex, int relativeColumnIndex) {
int oneDimensionalIndex = relativeRowIndex * getWidth() + relativeColumnIndex;
return _values[oneDimensionalIndex];
}

public AreaEval offset(int relFirstRowIx, int relLastRowIx,
int relFirstColIx, int relLastColIx) {

AreaI area = new OffsetArea(getFirstRow(), getFirstColumn(),
relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);

int height = area.getLastRow() - area.getFirstRow() + 1;
int width = area.getLastColumn() - area.getFirstColumn() + 1;

ValueEval newVals[] = new ValueEval[height * width];

int startRow = area.getFirstRow() - getFirstRow();
int startCol = area.getFirstColumn() - getFirstColumn();

for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
ValueEval temp;

/* CacheAreaEval is only temporary value representation, does not equal sheet selection
* so any attempts going beyond the selection results in BlankEval
*/
if (startRow + j > getLastRow() || startCol + i > getLastColumn()) {
temp = BlankEval.instance;
}
else {
temp = _values[(startRow + j) * getWidth() + (startCol + i)];
}
newVals[j * width + i] = temp;
}
}

return new CacheAreaEval(area, newVals);
}

public TwoDEval getRow(int rowIndex) {
if (rowIndex >= getHeight()) {
throw new IllegalArgumentException("Invalid rowIndex " + rowIndex
+ ". Allowable range is (0.." + getHeight() + ").");
}
int absRowIndex = getFirstRow() + rowIndex;
ValueEval[] values = new ValueEval[getWidth()];

for (int i = 0; i < values.length; i++) {
values[i] = getRelativeValue(rowIndex, i);
}
return new CacheAreaEval(absRowIndex, getFirstColumn() , absRowIndex, getLastColumn(), values);
}

public TwoDEval getColumn(int columnIndex) {
if (columnIndex >= getWidth()) {
throw new IllegalArgumentException("Invalid columnIndex " + columnIndex
+ ". Allowable range is (0.." + getWidth() + ").");
}
int absColIndex = getFirstColumn() + columnIndex;
ValueEval[] values = new ValueEval[getHeight()];

for (int i = 0; i < values.length; i++) {
values[i] = getRelativeValue(i, columnIndex);
}

return new CacheAreaEval(getFirstRow(), absColIndex, getLastRow(), absColIndex, values);
}

public String toString() {
CellReference crA = new CellReference(getFirstRow(), getFirstColumn());
CellReference crB = new CellReference(getLastRow(), getLastColumn());
return getClass().getName() + "[" +
crA.formatAsString() +
':' +
crB.formatAsString() +
"]";
}
}
3 changes: 3 additions & 0 deletions src/java/org/apache/poi/ss/formula/EvaluationCell.java
Expand Up @@ -18,6 +18,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more
package org.apache.poi.ss.formula;

import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.util.CellRangeAddress;

/**
* Abstracts a cell for the purpose of formula evaluation. This interface represents both formula
Expand Down Expand Up @@ -56,6 +57,8 @@ public interface EvaluationCell {
String getStringCellValue();
boolean getBooleanCellValue();
int getErrorCellValue();
CellRangeAddress getArrayFormulaRange();
boolean isPartOfArrayFormulaGroup();

/**
* Will return {@link CellType} in a future version of POI.
Expand Down
40 changes: 40 additions & 0 deletions src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java
Expand Up @@ -22,11 +22,15 @@ Licensed to the Apache Software Foundation (ASF) under one or more
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheetRange;
import org.apache.poi.ss.formula.constant.ErrorConstant;
import org.apache.poi.ss.formula.eval.AreaEval;
import org.apache.poi.ss.formula.eval.BoolEval;
import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.ExternalNameEval;
import org.apache.poi.ss.formula.eval.FunctionNameEval;
import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.RefEval;
import org.apache.poi.ss.formula.eval.StringEval;
import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.functions.FreeRefFunction;
import org.apache.poi.ss.formula.ptg.Area3DPtg;
Expand Down Expand Up @@ -338,6 +342,42 @@ public ValueEval getArea3DEval(Area3DPxg aptg) {
return new LazyAreaEval(aptg.getFirstRow(), aptg.getFirstColumn(),
aptg.getLastRow(), aptg.getLastColumn(), sre);
}

public ValueEval getAreaValueEval(int firstRowIndex, int firstColumnIndex,
int lastRowIndex, int lastColumnIndex, Object[][] tokens) {

ValueEval values[] = new ValueEval[tokens.length * tokens[0].length];

int index = 0;
for (int jdx = 0; jdx < tokens.length; jdx++) {
for (int idx = 0; idx < tokens[0].length; idx++) {
values[index++] = convertObjectEval(tokens[jdx][idx]);
}
}

return new CacheAreaEval(firstRowIndex, firstColumnIndex, lastRowIndex,
lastColumnIndex, values);
}

private ValueEval convertObjectEval(Object token) {
if (token == null) {
throw new RuntimeException("Array item cannot be null");
}
if (token instanceof String) {
return new StringEval((String)token);
}
if (token instanceof Double) {
return new NumberEval(((Double)token).doubleValue());
}
if (token instanceof Boolean) {
return BoolEval.valueOf(((Boolean)token).booleanValue());
}
if (token instanceof ErrorConstant) {
return ErrorEval.valueOf(((ErrorConstant)token).getErrorCode());
}
throw new IllegalArgumentException("Unexpected constant class (" + token.getClass().getName() + ")");
}


public ValueEval getNameXEval(NameXPtg nameXPtg) {
// Is the name actually on our workbook?
Expand Down
Expand Up @@ -52,6 +52,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more
import org.apache.poi.ss.formula.eval.UnaryPlusEval;
import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.function.FunctionMetadataRegistry;
import org.apache.poi.ss.formula.functions.ArrayFunction;
import org.apache.poi.ss.formula.functions.Function;
import org.apache.poi.ss.formula.functions.Indirect;

Expand Down Expand Up @@ -116,6 +117,12 @@ public static ValueEval evaluate(OperationPtg ptg, ValueEval[] args,
Function result = _instancesByPtgClass.get(ptg);

if (result != null) {
EvaluationSheet evalSheet = ec.getWorkbook().getSheet(ec.getSheetIndex());
EvaluationCell evalCell = evalSheet.getCell(ec.getRowIndex(), ec.getColumnIndex());

if (evalCell.isPartOfArrayFormulaGroup() && result instanceof ArrayFunction)
return ((ArrayFunction) result).evaluateArray(args, ec.getRowIndex(), ec.getColumnIndex());

return result.evaluate(args, ec.getRowIndex(), (short) ec.getColumnIndex());
}

Expand Down