*/
public final class BlankEval implements ValueEval {
- public static BlankEval INSTANCE = new BlankEval();
+ public static final BlankEval instance = new BlankEval();
+ /**
+ * @deprecated (Nov 2009) use {@link #instance}
+ */
+ public static final BlankEval INSTANCE = instance;
private BlankEval() {
// enforce singleton
StringValueEval sve = (StringValueEval) ve;
return sve.getStringValue();
}
- if (ve == BlankEval.INSTANCE) {
+ if (ve == BlankEval.instance) {
return "";
}
throw new IllegalAccessError("Unexpected value type ("
if(result == null) {
// This seems to be required because AreaEval.values() array may contain nulls.
// perhaps that should not be allowed.
- result = BlankEval.INSTANCE;
+ result = BlankEval.instance;
}
if (result instanceof ErrorEval) {
throw new EvaluationException((ErrorEval) result);
*
*/
public static int coerceValueToInt(ValueEval ev) throws EvaluationException {
- if (ev == BlankEval.INSTANCE) {
+ if (ev == BlankEval.instance) {
return 0;
}
double d = coerceValueToDouble(ev);
*/
public static double coerceValueToDouble(ValueEval ev) throws EvaluationException {
- if (ev == BlankEval.INSTANCE) {
+ if (ev == BlankEval.instance) {
return 0.0;
}
if (ev instanceof NumericValueEval) {
StringValueEval sve = (StringValueEval) ve;
return sve.getStringValue();
}
- if (ve == BlankEval.INSTANCE) {
+ if (ve == BlankEval.instance) {
return "";
}
throw new IllegalArgumentException("Unexpected eval class (" + ve.getClass().getName() + ")");
*/
public static Boolean coerceValueToBoolean(ValueEval ve, boolean stringsAreBlanks) throws EvaluationException {
- if (ve == null || ve == BlankEval.INSTANCE) {
+ if (ve == null || ve == BlankEval.instance) {
// TODO - remove 've == null' condition once AreaEval is fixed
return null;
}
return Boolean.valueOf(((BoolEval) ve).getBooleanValue());
}
- if (ve == BlankEval.INSTANCE) {
+ if (ve == BlankEval.instance) {
return null;
}
private static int doCompare(ValueEval va, ValueEval vb) {
// special cases when one operand is blank
- if (va == BlankEval.INSTANCE) {
+ if (va == BlankEval.instance) {
return compareBlank(vb);
}
- if (vb == BlankEval.INSTANCE) {
+ if (vb == BlankEval.instance) {
return -compareBlank(va);
}
}
private static int compareBlank(ValueEval v) {
- if (v == BlankEval.INSTANCE) {
+ if (v == BlankEval.instance) {
return 0;
}
if (v instanceof BoolEval) {
}
ValueEval result = OperandResolver.getSingleValue(args[ix], srcRowIndex, srcColumnIndex);
if (result == MissingArgEval.instance) {
- return BlankEval.INSTANCE;
+ return BlankEval.instance;
}
return result;
} catch (EvaluationException e) {
// Error values like #VALUE!, #REF!, #DIV/0!, #NAME? etc don't cause this COUNTA to return an error
// in fact, they seem to get counted
- if(valueEval == BlankEval.INSTANCE) {
+ if(valueEval == BlankEval.instance) {
return false;
}
// Note - everything but BlankEval counts
public boolean matches(ValueEval valueEval) {
// Note - only BlankEval counts
- return valueEval == BlankEval.INSTANCE;
+ return valueEval == BlankEval.instance;
}
};
}
if(evaluatedCriteriaArg instanceof ErrorEval) {
return new ErrorMatcher(((ErrorEval)evaluatedCriteriaArg).getErrorCode(), CmpOp.OP_NONE);
}
- if(evaluatedCriteriaArg == BlankEval.INSTANCE) {
+ if(evaluatedCriteriaArg == BlankEval.instance) {
return null;
}
throw new RuntimeException("Unexpected type for criteria ("
}
if (b) {
if (arg1 == MissingArgEval.instance) {
- return BlankEval.INSTANCE;
+ return BlankEval.instance;
}
return arg1;
}
}
if (b) {
if (arg1 == MissingArgEval.instance) {
- return BlankEval.INSTANCE;
+ return BlankEval.instance;
}
return arg1;
}
if (arg2 == MissingArgEval.instance) {
- return BlankEval.INSTANCE;
+ return BlankEval.instance;
}
return arg2;
}
if (ev == MissingArgEval.instance) {
return 0;
}
- if (ev == BlankEval.INSTANCE) {
+ if (ev == BlankEval.instance) {
return 0;
}
int result = OperandResolver.coerceValueToInt(ev);
throws EvaluationException {
ValueEval ve = OperandResolver.getSingleValue(arg, ec.getRowIndex(), ec.getColumnIndex());
- if (ve == BlankEval.INSTANCE || ve == MissingArgEval.instance) {
+ if (ve == BlankEval.instance || ve == MissingArgEval.instance) {
return false;
}
// numeric quantities follow standard boolean conversion rules
public static LookupValueComparer createLookupComparer(ValueEval lookupValue) {
- if (lookupValue == BlankEval.INSTANCE) {
+ if (lookupValue == BlankEval.instance) {
// blank eval translates to zero
// Note - a blank eval in the lookup column/row never matches anything
// empty string in the lookup column/row can only be matched by explicit empty string
if (arg instanceof ErrorEval) {
throw new EvaluationException((ErrorEval) arg);
}
- if (arg == BlankEval.INSTANCE || arg instanceof BoolEval || arg instanceof StringEval) {
+ if (arg == BlankEval.instance || arg instanceof BoolEval || arg instanceof StringEval) {
if (mustBeNumber) {
throw EvaluationException.invalidValue();
}
}
return;
}
- if (ve == BlankEval.INSTANCE) {
+ if (ve == BlankEval.instance) {
if (_isBlankCounted) {
temp.add(0.0);
}
*/
abstract class CellCacheEntry implements ICacheEntry {
public static final CellCacheEntry[] EMPTY_ARRAY = { };
-
+
private final FormulaCellCacheEntrySet _consumingCells;
private ValueEval _value;
-
+
protected CellCacheEntry() {
_consumingCells = new FormulaCellCacheEntrySet();
public final ValueEval getValue() {
return _value;
}
-
+
private static boolean areValuesEqual(ValueEval a, ValueEval b) {
if (a == null) {
return false;
// value type is changing
return false;
}
- if (a == BlankEval.INSTANCE) {
+ if (a == BlankEval.instance) {
return b == a;
}
if (cls == NumberEval.class) {
public final void addConsumingCell(FormulaCellCacheEntry cellLoc) {
_consumingCells.add(cellLoc);
-
+
}
public final FormulaCellCacheEntry[] getConsumingCells() {
return _consumingCells.toArray();
recurseClearCachedFormulaResults(listener, 1);
}
}
-
+
/**
- * Calls formulaCell.setFormulaResult(null, null) recursively all the way up the tree of
+ * Calls formulaCell.setFormulaResult(null, null) recursively all the way up the tree of
* dependencies. Calls usedCell.clearConsumingCell(fc) for each child of a cell that is
* cleared along the way.
* @param formulaCells
*/
protected final void recurseClearCachedFormulaResults() {
FormulaCellCacheEntry[] formulaCells = getConsumingCells();
-
+
for (int i = 0; i < formulaCells.length; i++) {
FormulaCellCacheEntry fc = formulaCells[i];
fc.clearFormulaEntry();
fc.recurseClearCachedFormulaResults();
}
}
-
+
/**
* Identical to {@link #recurseClearCachedFormulaResults()} except for the listener call-backs
*/
fc.recurseClearCachedFormulaResults(listener, depth+1);
}
}
-
-}
\ No newline at end of file
+}
/**
* Performance optimisation for {@link HSSFFormulaEvaluator}. This class stores previously
- * calculated values of already visited cells, to avoid unnecessary re-calculation when the
+ * calculated values of already visited cells, to avoid unnecessary re-calculation when the
* same cells are referenced multiple times
- *
- *
+ *
* @author Josh Micich
*/
final class EvaluationCache {
} else {
ValueEval value = WorkbookEvaluator.getValueFromNonFormulaCell(cell);
if (pcce == null) {
- if (value != BlankEval.INSTANCE) {
+ if (value != BlankEval.instance) {
// only cache non-blank values in the plain cell cache
// (dependencies on blank cells are managed by
// FormulaCellCacheEntry._usedBlankCellGroup)
if (pcce.updateValue(value)) {
pcce.recurseClearCachedFormulaResults(_evaluationListener);
}
- if (value == BlankEval.INSTANCE) {
+ if (value == BlankEval.instance) {
_plainCellCache.remove(loc);
}
}
}
}
- private void updateAnyBlankReferencingFormulas(int bookIndex, int sheetIndex,
+ private void updateAnyBlankReferencingFormulas(int bookIndex, int sheetIndex,
final int rowIndex, final int columnIndex) {
final BookSheetKey bsk = new BookSheetKey(bookIndex, sheetIndex);
_formulaCellCache.applyOperation(new IEntryOperation() {
public PlainValueCellCacheEntry getPlainValueEntry(int bookIndex, int sheetIndex,
int rowIndex, int columnIndex, ValueEval value) {
-
+
Loc loc = new Loc(bookIndex, sheetIndex, rowIndex, columnIndex);
PlainValueCellCacheEntry result = _plainCellCache.get(loc);
if (result == null) {
_evaluationListener.onReadPlainValue(sheetIndex, rowIndex, columnIndex, result);
}
} else {
- // TODO - if we are confident that this sanity check is not required, we can remove 'value' from plain value cache entry
+ // TODO - if we are confident that this sanity check is not required, we can remove 'value' from plain value cache entry
if (!areValuesEqual(result.getValue(), value)) {
throw new IllegalStateException("value changed");
}
// value type is changing
return false;
}
- if (a == BlankEval.INSTANCE) {
+ if (a == BlankEval.instance) {
return b == a;
}
if (cls == NumberEval.class) {
}
throw new IllegalStateException("Unexpected value class (" + cls.getName() + ")");
}
-
+
public FormulaCellCacheEntry getOrCreateFormulaCellEntry(EvaluationCell cell) {
FormulaCellCacheEntry result = _formulaCellCache.get(cell);
if (result == null) {
-
+
result = new FormulaCellCacheEntry();
_formulaCellCache.put(cell, result);
}
_formulaCellCache.clear();
}
public void notifyDeleteCell(int bookIndex, int sheetIndex, EvaluationCell cell) {
-
+
if (cell.getCellType() == HSSFCell.CELL_TYPE_FORMULA) {
FormulaCellCacheEntry fcce = _formulaCellCache.remove(cell);
if (fcce == null) {
- // formula cell has not been evaluated yet
+ // formula cell has not been evaluated yet
} else {
fcce.setSensitiveInputCells(null);
fcce.recurseClearCachedFormulaResults(_evaluationListener);
} else {
Loc loc = new Loc(bookIndex, sheetIndex, cell.getRowIndex(), cell.getColumnIndex());
PlainValueCellCacheEntry pcce = _plainCellCache.get(loc);
-
+
if (pcce == null) {
// cache entry doesn't exist. nothing to do
} else {
if (result == ErrorEval.CIRCULAR_REF_ERROR && nFrames > 1) {
// Don't cache a circular ref error result if this cell is not the top evaluated cell.
// A true circular ref error will propagate all the way around the loop. However, it's
- // possible to have parts of the formula tree (/ parts of the loop) to evaluate to
+ // possible to have parts of the formula tree (/ parts of the loop) to evaluate to
// CIRCULAR_REF_ERROR, and that value not get used in the final cell result (see the
// unit tests for a simple example). Thus, the only CIRCULAR_REF_ERROR result that can
// safely be cached is that of the top evaluated cell.
// Top level frame, there is no 'cell' above this frame that is using the current cell
} else {
CellEvaluationFrame consumingFrame = _evaluationFrames.get(prevFrameIndex);
- if (value == BlankEval.INSTANCE) {
+ if (value == BlankEval.instance) {
consumingFrame.addUsedBlankCell(bookIndex, sheetIndex, rowIndex, columnIndex);
} else {
PlainValueCellCacheEntry cce = _cache.getPlainValueEntry(bookIndex, sheetIndex,
*/
/* package */ static ValueEval getValueFromNonFormulaCell(EvaluationCell cell) {
if (cell == null) {
- return BlankEval.INSTANCE;
+ return BlankEval.instance;
}
int cellType = cell.getCellType();
switch (cellType) {
case Cell.CELL_TYPE_BOOLEAN:
return BoolEval.valueOf(cell.getBooleanCellValue());
case Cell.CELL_TYPE_BLANK:
- return BlankEval.INSTANCE;
+ return BlankEval.instance;
case Cell.CELL_TYPE_ERROR:
return ErrorEval.valueOf(cell.getErrorCellValue());
}
i+= countTokensToBeSkipped(ptgs, i, dist);
if (stack.peek() == MissingArgEval.instance) {
stack.pop();
- stack.push(BlankEval.INSTANCE);
+ stack.push(BlankEval.instance);
}
continue;
}
throw new IllegalStateException("evaluation stack not empty");
}
value = dereferenceValue(value, ec.getRowIndex(), ec.getColumnIndex());
- if (value == BlankEval.INSTANCE) {
+ if (value == BlankEval.instance) {
// Note Excel behaviour here. A blank final final value is converted to zero.
return NumberEval.ZERO;
// Formulas _never_ evaluate to blank. If a formula appears to have evaluated to
_sheet = sheet;
_masterCell = masterCell;
// start with value blank, but expect construction to be immediately
- setValue(BlankEval.INSTANCE); // followed by a proper call to setValue()
+ setValue(BlankEval.instance); // followed by a proper call to setValue()
}
public Object getIdentityKey() {
ValueEval[] args = {
new StringEval(""),
- BlankEval.INSTANCE,
+ BlankEval.instance,
};
ValueEval result = evaluate(EI.Equal, args, 10, 10);
assertEquals(BoolEval.class, result.getClass());
values = new ValueEval[] {
new NumberEval(1),
new NumberEval(2),
- BlankEval.INSTANCE,
+ BlankEval.instance,
new NumberEval(3),
- BlankEval.INSTANCE,
+ BlankEval.instance,
new NumberEval(4),
- BlankEval.INSTANCE,
+ BlankEval.instance,
};
confirmAverage(values, 2.5);
BoolEval.TRUE,
BoolEval.FALSE,
ErrorEval.DIV_ZERO,
- BlankEval.INSTANCE,
+ BlankEval.instance,
};
range = EvalFactory.createAreaEval("A1:B3", values);
confirmCountBlank(1, range);
values = new ValueEval[] {
new NumberEval(0),
new StringEval(""), // note - does not match blank
- BlankEval.INSTANCE,
+ BlankEval.instance,
BoolEval.FALSE,
BoolEval.TRUE,
- BlankEval.INSTANCE,
+ BlankEval.instance,
};
range = EvalFactory.createAreaEval("A1:B3", values);
confirmCountBlank(2, range);
BoolEval.TRUE,
BoolEval.FALSE,
BoolEval.TRUE,
- BlankEval.INSTANCE,
+ BlankEval.instance,
};
range = EvalFactory.createAreaEval("A1:B3", values);
confirmCountIf(2, range, BoolEval.TRUE);
assertEquals(expectedResult, matchPredicate.matches(new NumberEval(value)));
}
private static void confirmPredicate(boolean expectedResult, I_MatchPredicate matchPredicate, String value) {
- ValueEval ev = value == null ? BlankEval.INSTANCE : new StringEval(value);
+ ValueEval ev = value == null ? BlankEval.instance : new StringEval(value);
assertEquals(expectedResult, matchPredicate.matches(ev));
}
private static void confirmPredicate(boolean expectedResult, I_MatchPredicate matchPredicate, ErrorEval value) {
confirmLen(new NumberEval(123456), 6);
confirmLen(BoolEval.FALSE, 5);
confirmLen(BoolEval.TRUE, 4);
- confirmLen(BlankEval.INSTANCE, 0);
+ confirmLen(BlankEval.instance, 0);
}
public void testErrors() {
RefEval reNumChars = EvalFactory.createRefEval("B1", new NumberEval(3));
confirmMid(new StringEval("galactic"), aeStart, reNumChars, "ala");
- confirmMid(new StringEval("galactic"), new NumberEval(3.1), BlankEval.INSTANCE, "");
+ confirmMid(new StringEval("galactic"), new NumberEval(3.1), BlankEval.instance, "");
confirmMid(new StringEval("galactic"), new NumberEval(3), BoolEval.FALSE, "");
confirmMid(new StringEval("galactic"), new NumberEval(3), BoolEval.TRUE, "l");
- confirmMid(BlankEval.INSTANCE, new NumberEval(3), BoolEval.TRUE, "");
+ confirmMid(BlankEval.instance, new NumberEval(3), BoolEval.TRUE, "");
}
confirmMid(new StringEval("galactic"), new NumberEval(3), ErrorEval.NAME_INVALID, ErrorEval.NAME_INVALID);
confirmMid(new StringEval("galactic"), ErrorEval.DIV_ZERO, ErrorEval.NAME_INVALID, ErrorEval.DIV_ZERO);
- confirmMid(new StringEval("galactic"), BlankEval.INSTANCE, new NumberEval(3.1), ErrorEval.VALUE_INVALID);
+ confirmMid(new StringEval("galactic"), BlankEval.instance, new NumberEval(3.1), ErrorEval.VALUE_INVALID);
confirmMid(new StringEval("galactic"), new NumberEval(0), new NumberEval(4), ErrorEval.VALUE_INVALID);
confirmMid(new StringEval("galactic"), new NumberEval(1), new NumberEval(-1), ErrorEval.VALUE_INVALID);
public void testOtherValues() {
confirmOther(new NumberEval(2));
confirmOther(BoolEval.FALSE);
- confirmOther(BlankEval.INSTANCE); // can this particular case be verified?
+ confirmOther(BlankEval.instance); // can this particular case be verified?
}
public void testRefValues() {
confirmTrim(new NumberEval(123456), "123456");
confirmTrim(BoolEval.FALSE, "FALSE");
confirmTrim(BoolEval.TRUE, "TRUE");
- confirmTrim(BlankEval.INSTANCE, "");
+ confirmTrim(BlankEval.instance, "");
}
public void testErrors() {
BoolEval be = (BoolEval) value;
return be.getStringValue();
}
- if (value == BlankEval.INSTANCE) {
+ if (value == BlankEval.instance) {
return "#BLANK#";
}
if (value instanceof ErrorEval) {