You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by fa...@apache.org on 2021/05/22 20:56:49 UTC

svn commit: r1890120 [20/43] - in /poi/trunk/poi/src: main/java/org/apache/poi/ main/java/org/apache/poi/ddf/ main/java/org/apache/poi/extractor/ main/java/org/apache/poi/hpsf/ main/java/org/apache/poi/hssf/ main/java/org/apache/poi/hssf/dev/ main/java...

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Lookup.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Lookup.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Lookup.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Lookup.java Sat May 22 20:56:44 2021
@@ -37,69 +37,69 @@ import org.apache.poi.ss.formula.TwoDEva
  */
 public final class Lookup extends Var2or3ArgFunction {
 
-	@Override
-	public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
-		// complex rules to choose lookupVector and resultVector from the single area ref
-
-		try {
-			/*
-			The array form of LOOKUP is very similar to the HLOOKUP and VLOOKUP functions. The difference is that HLOOKUP searches for the value of lookup_value in the first row, VLOOKUP searches in the first column, and LOOKUP searches according to the dimensions of array.
-			If array covers an area that is wider than it is tall (more columns than rows), LOOKUP searches for the value of lookup_value in the first row.
-			If an array is square or is taller than it is wide (more rows than columns), LOOKUP searches in the first column.
-			With the HLOOKUP and VLOOKUP functions, you can index down or across, but LOOKUP always selects the last value in the row or column.
-			 */
-			ValueEval lookupValue = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
-			TwoDEval lookupArray = LookupUtils.resolveTableArrayArg(arg1);
-			ValueVector lookupVector;
-			ValueVector resultVector;
-
-			if (lookupArray.getWidth() > lookupArray.getHeight()) {
-				// If array covers an area that is wider than it is tall (more columns than rows), LOOKUP searches for the value of lookup_value in the first row.
-				lookupVector = createVector(lookupArray.getRow(0));
-				resultVector = createVector(lookupArray.getRow(lookupArray.getHeight() - 1));
-			} else {
-				// If an array is square or is taller than it is wide (more rows than columns), LOOKUP searches in the first column.
-				lookupVector = createVector(lookupArray.getColumn(0));
-				resultVector = createVector(lookupArray.getColumn(lookupArray.getWidth() - 1));
-			}
-			// if a rectangular area reference was passed in as arg1, lookupVector and resultVector should be the same size
-			assert (lookupVector.getSize() == resultVector.getSize());
-
-			int index = LookupUtils.lookupIndexOfValue(lookupValue, lookupVector, true);
-			return resultVector.getItem(index);
-		} catch (final EvaluationException e) {
-			return e.getErrorEval();
-		}
-	}
-
-	@Override
-	public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
-			ValueEval arg2) {
-		try {
-			ValueEval lookupValue = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
-			TwoDEval aeLookupVector = LookupUtils.resolveTableArrayArg(arg1);
-			TwoDEval aeResultVector = LookupUtils.resolveTableArrayArg(arg2);
-
-			ValueVector lookupVector = createVector(aeLookupVector);
-			ValueVector resultVector = createVector(aeResultVector);
-			if(lookupVector.getSize() > resultVector.getSize()) {
-				// Excel seems to handle this by accessing past the end of the result vector.
-				throw new RuntimeException("Lookup vector and result vector of differing sizes not supported yet");
-			}
-			int index = LookupUtils.lookupIndexOfValue(lookupValue, lookupVector, true);
-
-			return resultVector.getItem(index);
-		} catch (EvaluationException e) {
-			return e.getErrorEval();
-		}
-	}
-
-	private static ValueVector createVector(TwoDEval ae) {
-		ValueVector result = LookupUtils.createVector(ae);
-		if (result != null) {
-			return result;
-		}
-		// extra complexity required to emulate the way LOOKUP can handles these abnormal cases.
-		throw new RuntimeException("non-vector lookup or result areas not supported yet");
-	}
+    @Override
+    public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
+        // complex rules to choose lookupVector and resultVector from the single area ref
+
+        try {
+            /*
+            The array form of LOOKUP is very similar to the HLOOKUP and VLOOKUP functions. The difference is that HLOOKUP searches for the value of lookup_value in the first row, VLOOKUP searches in the first column, and LOOKUP searches according to the dimensions of array.
+            If array covers an area that is wider than it is tall (more columns than rows), LOOKUP searches for the value of lookup_value in the first row.
+            If an array is square or is taller than it is wide (more rows than columns), LOOKUP searches in the first column.
+            With the HLOOKUP and VLOOKUP functions, you can index down or across, but LOOKUP always selects the last value in the row or column.
+             */
+            ValueEval lookupValue = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
+            TwoDEval lookupArray = LookupUtils.resolveTableArrayArg(arg1);
+            ValueVector lookupVector;
+            ValueVector resultVector;
+
+            if (lookupArray.getWidth() > lookupArray.getHeight()) {
+                // If array covers an area that is wider than it is tall (more columns than rows), LOOKUP searches for the value of lookup_value in the first row.
+                lookupVector = createVector(lookupArray.getRow(0));
+                resultVector = createVector(lookupArray.getRow(lookupArray.getHeight() - 1));
+            } else {
+                // If an array is square or is taller than it is wide (more rows than columns), LOOKUP searches in the first column.
+                lookupVector = createVector(lookupArray.getColumn(0));
+                resultVector = createVector(lookupArray.getColumn(lookupArray.getWidth() - 1));
+            }
+            // if a rectangular area reference was passed in as arg1, lookupVector and resultVector should be the same size
+            assert (lookupVector.getSize() == resultVector.getSize());
+
+            int index = LookupUtils.lookupIndexOfValue(lookupValue, lookupVector, true);
+            return resultVector.getItem(index);
+        } catch (final EvaluationException e) {
+            return e.getErrorEval();
+        }
+    }
+
+    @Override
+    public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+            ValueEval arg2) {
+        try {
+            ValueEval lookupValue = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
+            TwoDEval aeLookupVector = LookupUtils.resolveTableArrayArg(arg1);
+            TwoDEval aeResultVector = LookupUtils.resolveTableArrayArg(arg2);
+
+            ValueVector lookupVector = createVector(aeLookupVector);
+            ValueVector resultVector = createVector(aeResultVector);
+            if(lookupVector.getSize() > resultVector.getSize()) {
+                // Excel seems to handle this by accessing past the end of the result vector.
+                throw new RuntimeException("Lookup vector and result vector of differing sizes not supported yet");
+            }
+            int index = LookupUtils.lookupIndexOfValue(lookupValue, lookupVector, true);
+
+            return resultVector.getItem(index);
+        } catch (EvaluationException e) {
+            return e.getErrorEval();
+        }
+    }
+
+    private static ValueVector createVector(TwoDEval ae) {
+        ValueVector result = LookupUtils.createVector(ae);
+        if (result != null) {
+            return result;
+        }
+        // extra complexity required to emulate the way LOOKUP can handles these abnormal cases.
+        throw new RuntimeException("non-vector lookup or result areas not supported yet");
+    }
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/LookupUtils.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/LookupUtils.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/LookupUtils.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/LookupUtils.java Sat May 22 20:56:44 2021
@@ -38,76 +38,76 @@ import org.apache.poi.ss.formula.eval.Va
  */
 final class LookupUtils {
 
-	/**
-	 * Represents a single row or column within an {@code AreaEval}.
-	 */
-	public interface ValueVector {
-		ValueEval getItem(int index);
-		int getSize();
-	}
-
-
-	private static final class RowVector implements ValueVector {
-
-		private final TwoDEval _tableArray;
-		private final int _size;
-		private final int _rowIndex;
-
-		public RowVector(TwoDEval tableArray, int rowIndex) {
-			_rowIndex = rowIndex;
-			int lastRowIx =  tableArray.getHeight() - 1;
-			if(rowIndex < 0 || rowIndex > lastRowIx) {
-				throw new IllegalArgumentException("Specified row index (" + rowIndex
-						+ ") is outside the allowed range (0.." + lastRowIx + ")");
-			}
-			_tableArray = tableArray;
-			_size = tableArray.getWidth();
-		}
-
-		@Override
-		public ValueEval getItem(int index) {
-			if(index > _size) {
-				throw new ArrayIndexOutOfBoundsException("Specified index (" + index
-						+ ") is outside the allowed range (0.." + (_size-1) + ")");
-			}
-			return _tableArray.getValue(_rowIndex, index);
-		}
-		@Override
-		public int getSize() {
-			return _size;
-		}
-	}
-
-	private static final class ColumnVector implements ValueVector {
-
-		private final TwoDEval _tableArray;
-		private final int _size;
-		private final int _columnIndex;
-
-		public ColumnVector(TwoDEval tableArray, int columnIndex) {
-			_columnIndex = columnIndex;
-			int lastColIx =  tableArray.getWidth()-1;
-			if(columnIndex < 0 || columnIndex > lastColIx) {
-				throw new IllegalArgumentException("Specified column index (" + columnIndex
-						+ ") is outside the allowed range (0.." + lastColIx + ")");
-			}
-			_tableArray = tableArray;
-			_size = _tableArray.getHeight();
-		}
-
-		@Override
-		public ValueEval getItem(int index) {
-			if(index > _size) {
-				throw new ArrayIndexOutOfBoundsException("Specified index (" + index
-						+ ") is outside the allowed range (0.." + (_size-1) + ")");
-			}
-			return _tableArray.getValue(index, _columnIndex);
-		}
-		@Override
-		public int getSize() {
-			return _size;
-		}
-	}
+    /**
+     * Represents a single row or column within an {@code AreaEval}.
+     */
+    public interface ValueVector {
+        ValueEval getItem(int index);
+        int getSize();
+    }
+
+
+    private static final class RowVector implements ValueVector {
+
+        private final TwoDEval _tableArray;
+        private final int _size;
+        private final int _rowIndex;
+
+        public RowVector(TwoDEval tableArray, int rowIndex) {
+            _rowIndex = rowIndex;
+            int lastRowIx =  tableArray.getHeight() - 1;
+            if(rowIndex < 0 || rowIndex > lastRowIx) {
+                throw new IllegalArgumentException("Specified row index (" + rowIndex
+                        + ") is outside the allowed range (0.." + lastRowIx + ")");
+            }
+            _tableArray = tableArray;
+            _size = tableArray.getWidth();
+        }
+
+        @Override
+        public ValueEval getItem(int index) {
+            if(index > _size) {
+                throw new ArrayIndexOutOfBoundsException("Specified index (" + index
+                        + ") is outside the allowed range (0.." + (_size-1) + ")");
+            }
+            return _tableArray.getValue(_rowIndex, index);
+        }
+        @Override
+        public int getSize() {
+            return _size;
+        }
+    }
+
+    private static final class ColumnVector implements ValueVector {
+
+        private final TwoDEval _tableArray;
+        private final int _size;
+        private final int _columnIndex;
+
+        public ColumnVector(TwoDEval tableArray, int columnIndex) {
+            _columnIndex = columnIndex;
+            int lastColIx =  tableArray.getWidth()-1;
+            if(columnIndex < 0 || columnIndex > lastColIx) {
+                throw new IllegalArgumentException("Specified column index (" + columnIndex
+                        + ") is outside the allowed range (0.." + lastColIx + ")");
+            }
+            _tableArray = tableArray;
+            _size = _tableArray.getHeight();
+        }
+
+        @Override
+        public ValueEval getItem(int index) {
+            if(index > _size) {
+                throw new ArrayIndexOutOfBoundsException("Specified index (" + index
+                        + ") is outside the allowed range (0.." + (_size-1) + ")");
+            }
+            return _tableArray.getValue(index, _columnIndex);
+        }
+        @Override
+        public int getSize() {
+            return _size;
+        }
+    }
 
     private static final class SheetVector implements ValueVector {
         private final RefEval _re;
@@ -119,7 +119,7 @@ final class LookupUtils {
         }
 
         @Override
-		public ValueEval getItem(int index) {
+        public ValueEval getItem(int index) {
             if(index >= _size) {
                 throw new ArrayIndexOutOfBoundsException("Specified index (" + index
                         + ") is outside the allowed range (0.." + (_size-1) + ")");
@@ -128,78 +128,78 @@ final class LookupUtils {
             return _re.getInnerValueEval(sheetIndex);
         }
         @Override
-		public int getSize() {
+        public int getSize() {
             return _size;
         }
     }
 
-	public static ValueVector createRowVector(TwoDEval tableArray, int relativeRowIndex) {
-		return new RowVector(tableArray, relativeRowIndex);
-	}
-	public static ValueVector createColumnVector(TwoDEval tableArray, int relativeColumnIndex) {
-		return new ColumnVector(tableArray, relativeColumnIndex);
-	}
-	/**
-	 * @return {@code null} if the supplied area is neither a single row nor a single column
-	 */
-	public static ValueVector createVector(TwoDEval ae) {
-		if (ae.isColumn()) {
-			return createColumnVector(ae, 0);
-		}
-		if (ae.isRow()) {
-			return createRowVector(ae, 0);
-		}
-		return null;
-	}
-
-	public static ValueVector createVector(RefEval re) {
-	    return new SheetVector(re);
-	}
-
-	/**
-	 * Enumeration to support <b>4</b> valued comparison results.<p>
-	 * Excel lookup functions have complex behaviour in the case where the lookup array has mixed
-	 * types, and/or is unordered.  Contrary to suggestions in some Excel documentation, there
-	 * does not appear to be a universal ordering across types.  The binary search algorithm used
-	 * changes behaviour when the evaluated 'mid' value has a different type to the lookup value.<p>
-	 *
-	 * A simple int might have done the same job, but there is risk in confusion with the well
-	 * known {@code Comparable.compareTo()} and {@code Comparator.compare()} which both use
-	 * a ubiquitous 3 value result encoding.
-	 */
-	public static final class CompareResult {
-		private final boolean _isTypeMismatch;
-		private final boolean _isLessThan;
-		private final boolean _isEqual;
-		private final boolean _isGreaterThan;
-
-		private CompareResult(boolean isTypeMismatch, int simpleCompareResult) {
-			if(isTypeMismatch) {
-				_isTypeMismatch = true;
-				_isLessThan = false;
-				_isEqual = false;
-				_isGreaterThan = false;
-			} else {
-				_isTypeMismatch = false;
-				_isLessThan = simpleCompareResult < 0;
-				_isEqual = simpleCompareResult == 0;
-				_isGreaterThan = simpleCompareResult > 0;
-			}
-		}
-		public static final CompareResult TYPE_MISMATCH = new CompareResult(true, 0);
-		public static final CompareResult LESS_THAN = new CompareResult(false, -1);
-		public static final CompareResult EQUAL = new CompareResult(false, 0);
-		public static final CompareResult GREATER_THAN = new CompareResult(false, +1);
-
-		public static CompareResult valueOf(int simpleCompareResult) {
-			if(simpleCompareResult < 0) {
-				return LESS_THAN;
-			}
-			if(simpleCompareResult > 0) {
-				return GREATER_THAN;
-			}
-			return EQUAL;
-		}
+    public static ValueVector createRowVector(TwoDEval tableArray, int relativeRowIndex) {
+        return new RowVector(tableArray, relativeRowIndex);
+    }
+    public static ValueVector createColumnVector(TwoDEval tableArray, int relativeColumnIndex) {
+        return new ColumnVector(tableArray, relativeColumnIndex);
+    }
+    /**
+     * @return {@code null} if the supplied area is neither a single row nor a single column
+     */
+    public static ValueVector createVector(TwoDEval ae) {
+        if (ae.isColumn()) {
+            return createColumnVector(ae, 0);
+        }
+        if (ae.isRow()) {
+            return createRowVector(ae, 0);
+        }
+        return null;
+    }
+
+    public static ValueVector createVector(RefEval re) {
+        return new SheetVector(re);
+    }
+
+    /**
+     * Enumeration to support <b>4</b> valued comparison results.<p>
+     * Excel lookup functions have complex behaviour in the case where the lookup array has mixed
+     * types, and/or is unordered.  Contrary to suggestions in some Excel documentation, there
+     * does not appear to be a universal ordering across types.  The binary search algorithm used
+     * changes behaviour when the evaluated 'mid' value has a different type to the lookup value.<p>
+     *
+     * A simple int might have done the same job, but there is risk in confusion with the well
+     * known {@code Comparable.compareTo()} and {@code Comparator.compare()} which both use
+     * a ubiquitous 3 value result encoding.
+     */
+    public static final class CompareResult {
+        private final boolean _isTypeMismatch;
+        private final boolean _isLessThan;
+        private final boolean _isEqual;
+        private final boolean _isGreaterThan;
+
+        private CompareResult(boolean isTypeMismatch, int simpleCompareResult) {
+            if(isTypeMismatch) {
+                _isTypeMismatch = true;
+                _isLessThan = false;
+                _isEqual = false;
+                _isGreaterThan = false;
+            } else {
+                _isTypeMismatch = false;
+                _isLessThan = simpleCompareResult < 0;
+                _isEqual = simpleCompareResult == 0;
+                _isGreaterThan = simpleCompareResult > 0;
+            }
+        }
+        public static final CompareResult TYPE_MISMATCH = new CompareResult(true, 0);
+        public static final CompareResult LESS_THAN = new CompareResult(false, -1);
+        public static final CompareResult EQUAL = new CompareResult(false, 0);
+        public static final CompareResult GREATER_THAN = new CompareResult(false, +1);
+
+        public static CompareResult valueOf(int simpleCompareResult) {
+            if(simpleCompareResult < 0) {
+                return LESS_THAN;
+            }
+            if(simpleCompareResult > 0) {
+                return GREATER_THAN;
+            }
+            return EQUAL;
+        }
 
         public static CompareResult valueOf(boolean matches) {
             if(matches) {
@@ -209,78 +209,78 @@ final class LookupUtils {
         }
 
 
-		public boolean isTypeMismatch() {
-			return _isTypeMismatch;
-		}
-		public boolean isLessThan() {
-			return _isLessThan;
-		}
-		public boolean isEqual() {
-			return _isEqual;
-		}
-		public boolean isGreaterThan() {
-			return _isGreaterThan;
-		}
-		public String toString() {
-			return getClass().getName() + " [" +
-					formatAsString() +
-					"]";
-		}
-
-		private String formatAsString() {
-			if(_isTypeMismatch) {
-				return "TYPE_MISMATCH";
-			}
-			if(_isLessThan) {
-				return "LESS_THAN";
-			}
-			if(_isEqual) {
-				return "EQUAL";
-			}
-			if(_isGreaterThan) {
-				return "GREATER_THAN";
-			}
-			// toString must be reliable
-			return "??error??";
-		}
-	}
-
-	public interface LookupValueComparer {
-		/**
-		 * @return one of 4 instances or {@code CompareResult}: {@code LESS_THAN}, {@code EQUAL},
-		 * {@code GREATER_THAN} or {@code TYPE_MISMATCH}
-		 */
-		CompareResult compareTo(ValueEval other);
-	}
-
-	private static abstract class LookupValueComparerBase implements LookupValueComparer {
-
-		private final Class<? extends ValueEval> _targetClass;
-		protected LookupValueComparerBase(ValueEval targetValue) {
-			if(targetValue == null) {
-				throw new RuntimeException("targetValue cannot be null");
-			}
-			_targetClass = targetValue.getClass();
-		}
-		@Override
-		public final CompareResult compareTo(ValueEval other) {
-			if (other == null) {
-				throw new RuntimeException("compare to value cannot be null");
-			}
-			if (_targetClass != other.getClass()) {
-				return CompareResult.TYPE_MISMATCH;
-			}
-			return compareSameType(other);
-		}
-		public String toString() {
-			return getClass().getName() + " [" +
-					getValueAsString() +
-					"]";
-		}
-		protected abstract CompareResult compareSameType(ValueEval other);
-		/** used only for debug purposes */
-		protected abstract String getValueAsString();
-	}
+        public boolean isTypeMismatch() {
+            return _isTypeMismatch;
+        }
+        public boolean isLessThan() {
+            return _isLessThan;
+        }
+        public boolean isEqual() {
+            return _isEqual;
+        }
+        public boolean isGreaterThan() {
+            return _isGreaterThan;
+        }
+        public String toString() {
+            return getClass().getName() + " [" +
+                    formatAsString() +
+                    "]";
+        }
+
+        private String formatAsString() {
+            if(_isTypeMismatch) {
+                return "TYPE_MISMATCH";
+            }
+            if(_isLessThan) {
+                return "LESS_THAN";
+            }
+            if(_isEqual) {
+                return "EQUAL";
+            }
+            if(_isGreaterThan) {
+                return "GREATER_THAN";
+            }
+            // toString must be reliable
+            return "??error??";
+        }
+    }
+
+    public interface LookupValueComparer {
+        /**
+         * @return one of 4 instances or {@code CompareResult}: {@code LESS_THAN}, {@code EQUAL},
+         * {@code GREATER_THAN} or {@code TYPE_MISMATCH}
+         */
+        CompareResult compareTo(ValueEval other);
+    }
+
+    private static abstract class LookupValueComparerBase implements LookupValueComparer {
+
+        private final Class<? extends ValueEval> _targetClass;
+        protected LookupValueComparerBase(ValueEval targetValue) {
+            if(targetValue == null) {
+                throw new RuntimeException("targetValue cannot be null");
+            }
+            _targetClass = targetValue.getClass();
+        }
+        @Override
+        public final CompareResult compareTo(ValueEval other) {
+            if (other == null) {
+                throw new RuntimeException("compare to value cannot be null");
+            }
+            if (_targetClass != other.getClass()) {
+                return CompareResult.TYPE_MISMATCH;
+            }
+            return compareSameType(other);
+        }
+        public String toString() {
+            return getClass().getName() + " [" +
+                    getValueAsString() +
+                    "]";
+        }
+        protected abstract CompareResult compareSameType(ValueEval other);
+        /** used only for debug purposes */
+        protected abstract String getValueAsString();
+    }
 
 
     private static final class StringLookupComparer extends LookupValueComparerBase {
@@ -291,15 +291,15 @@ final class LookupUtils {
         private final boolean _isMatchFunction;
 
         protected StringLookupComparer(StringEval se, boolean matchExact, boolean isMatchFunction) {
-			super(se);
-			_value = se.getStringValue();
+            super(se);
+            _value = se.getStringValue();
             _wildCardPattern = Countif.StringMatcher.getWildCardPattern(_value);
             _matchExact = matchExact;
             _isMatchFunction = isMatchFunction;
-		}
+        }
 
-		@Override
-		protected CompareResult compareSameType(ValueEval other) {
+        @Override
+        protected CompareResult compareSameType(ValueEval other) {
             StringEval se = (StringEval) other;
 
             String stringValue = se.getStringValue();
@@ -314,363 +314,363 @@ final class LookupUtils {
             }
 
             return CompareResult.valueOf(_value.compareToIgnoreCase(stringValue));
-		}
-		@Override
-		protected String getValueAsString() {
-			return _value;
-		}
-	}
-	private static final class NumberLookupComparer extends LookupValueComparerBase {
-		private final double _value;
-
-		protected NumberLookupComparer(NumberEval ne) {
-			super(ne);
-			_value = ne.getNumberValue();
-		}
-		@Override
-		protected CompareResult compareSameType(ValueEval other) {
-			NumberEval ne = (NumberEval) other;
-			return CompareResult.valueOf(Double.compare(_value, ne.getNumberValue()));
-		}
-		@Override
-		protected String getValueAsString() {
-			return String.valueOf(_value);
-		}
-	}
-	private static final class BooleanLookupComparer extends LookupValueComparerBase {
-		private final boolean _value;
-
-		protected BooleanLookupComparer(BoolEval be) {
-			super(be);
-			_value = be.getBooleanValue();
-		}
-		@Override
-		protected CompareResult compareSameType(ValueEval other) {
-			BoolEval be = (BoolEval) other;
-			boolean otherVal = be.getBooleanValue();
-			if(_value == otherVal) {
-				return CompareResult.EQUAL;
-			}
-			// TRUE > FALSE
-			if(_value) {
-				return CompareResult.GREATER_THAN;
-			}
-			return CompareResult.LESS_THAN;
-		}
-		@Override
-		protected String getValueAsString() {
-			return String.valueOf(_value);
-		}
-	}
-
-	/**
-	 * Processes the third argument to VLOOKUP, or HLOOKUP (<b>col_index_num</b>
-	 * or <b>row_index_num</b> respectively).<br>
-	 * Sample behaviour:
-	 *    <table>
-	 *      <caption>Sample behaviour</caption>
-	 *      <tr><th>Input&nbsp;&nbsp;&nbsp;Return</th><th>Value&nbsp;&nbsp;</th><th>Thrown Error</th></tr>
-	 *      <tr><td>5</td><td>4</td><td>&nbsp;</td></tr>
-	 *      <tr><td>2.9</td><td>2</td><td>&nbsp;</td></tr>
-	 *      <tr><td>"5"</td><td>4</td><td>&nbsp;</td></tr>
-	 *      <tr><td>"2.18e1"</td><td>21</td><td>&nbsp;</td></tr>
-	 *      <tr><td>"-$2"</td><td>-3</td><td>*</td></tr>
-	 *      <tr><td>FALSE</td><td>-1</td><td>*</td></tr>
-	 *      <tr><td>TRUE</td><td>0</td><td>&nbsp;</td></tr>
-	 *      <tr><td>"TRUE"</td><td>&nbsp;</td><td>#REF!</td></tr>
-	 *      <tr><td>"abc"</td><td>&nbsp;</td><td>#REF!</td></tr>
-	 *      <tr><td>""</td><td>&nbsp;</td><td>#REF!</td></tr>
-	 *      <tr><td>&lt;blank&gt;</td><td>&nbsp;</td><td>#VALUE!</td></tr>
-	 *    </table><br>
-	 *
-	 * Note - out of range errors (result index too high) are handled by the caller.
-	 * @return column or row index as a zero-based value, never negative.
-	 * @throws EvaluationException when the specified arg cannot be coerced to a non-negative integer
-	 */
-	public static int resolveRowOrColIndexArg(ValueEval rowColIndexArg, int srcCellRow, int srcCellCol) throws EvaluationException {
-		if(rowColIndexArg == null) {
-			throw new IllegalArgumentException("argument must not be null");
-		}
-
-		ValueEval veRowColIndexArg;
-		try {
-			veRowColIndexArg = OperandResolver.getSingleValue(rowColIndexArg, srcCellRow, (short)srcCellCol);
-		} catch (EvaluationException e) {
-			// All errors get translated to #REF!
-			throw EvaluationException.invalidRef();
-		}
-		int oneBasedIndex;
-		if(veRowColIndexArg instanceof StringEval) {
-			StringEval se = (StringEval) veRowColIndexArg;
-			String strVal = se.getStringValue();
-			Double dVal = OperandResolver.parseDouble(strVal);
-			if(dVal == null) {
-				// String does not resolve to a number. Raise #REF! error.
-				throw EvaluationException.invalidRef();
-				// This includes text booleans "TRUE" and "FALSE".  They are not valid.
-			}
-			// else - numeric value parses OK
-		}
-		// actual BoolEval values get interpreted as FALSE->0 and TRUE->1
-		oneBasedIndex = OperandResolver.coerceValueToInt(veRowColIndexArg);
-		if (oneBasedIndex < 1) {
-			// note this is asymmetric with the errors when the index is too large (#REF!)
-			throw EvaluationException.invalidValue();
-		}
-		return oneBasedIndex - 1; // convert to zero based
-	}
-
-
-
-	/**
-	 * The second argument (table_array) should be an area ref, but can actually be a cell ref, in
-	 * which case it is interpreted as a 1x1 area ref.  Other scalar values cause #VALUE! error.
-	 */
-	public static TwoDEval resolveTableArrayArg(ValueEval eval) throws EvaluationException {
-		if (eval instanceof TwoDEval) {
-			return (TwoDEval) eval;
-		}
-
-		if(eval instanceof RefEval) {
-			RefEval refEval = (RefEval) eval;
-			// Make this cell ref look like a 1x1 area ref.
-
-			// It doesn't matter if eval is a 2D or 3D ref, because that detail is never asked of AreaEval.
-			return refEval.offset(0, 0, 0, 0);
-		}
-		throw EvaluationException.invalidValue();
-	}
-
-
-	/**
-	 * Resolves the last (optional) parameter (<b>range_lookup</b>) to the VLOOKUP and HLOOKUP functions.
-	 * @param rangeLookupArg must not be {@code null}
-	 */
-	public static boolean resolveRangeLookupArg(ValueEval rangeLookupArg, int srcCellRow, int srcCellCol) throws EvaluationException {
-
-		ValueEval valEval = OperandResolver.getSingleValue(rangeLookupArg, srcCellRow, srcCellCol);
-		if(valEval == MissingArgEval.instance) {
-			// Tricky:
-			// forth arg exists but is not supplied: "=VLOOKUP(A1,A2:A4,2,)"
-			return false;
-		}
-		if(valEval instanceof BlankEval) {
-			// Tricky:
-			// fourth arg supplied but evaluates to blank
-			// this does not get the default value
-			return false;
-		}
-		if(valEval instanceof BoolEval) {
-			// Happy day flow
-			BoolEval boolEval = (BoolEval) valEval;
-			return boolEval.getBooleanValue();
-		}
-
-		if (valEval instanceof StringEval) {
-			String stringValue = ((StringEval) valEval).getStringValue();
-			if(stringValue.length() < 1) {
-				// More trickiness:
-				// Empty string is not the same as BlankEval.  It causes #VALUE! error
-				throw EvaluationException.invalidValue();
-			}
-			// TODO move parseBoolean to OperandResolver
-			Boolean b = Countif.parseBoolean(stringValue);
-			if(b != null) {
-				// string converted to boolean OK
-				return b;
-			}
-			// Even more trickiness:
-			// Note - even if the StringEval represents a number value (for example "1"),
-			// Excel does not resolve it to a boolean.
-			throw EvaluationException.invalidValue();
-			// This is in contrast to the code below,, where NumberEvals values (for
-			// example 0.01) *do* resolve to equivalent boolean values.
-		}
-		if (valEval instanceof NumericValueEval) {
-			NumericValueEval nve = (NumericValueEval) valEval;
-			// zero is FALSE, everything else is TRUE
-			return 0.0 != nve.getNumberValue();
-		}
-		throw new RuntimeException("Unexpected eval type (" + valEval + ")");
-	}
-
-	public static int lookupIndexOfValue(ValueEval lookupValue, ValueVector vector, boolean isRangeLookup) throws EvaluationException {
-		LookupValueComparer lookupComparer = createLookupComparer(lookupValue, isRangeLookup, false);
-		int result;
-		if(isRangeLookup) {
-			result = performBinarySearch(vector, lookupComparer);
-		} else {
-			result = lookupIndexOfExactValue(lookupComparer, vector);
-		}
-		if(result < 0) {
-			throw new EvaluationException(ErrorEval.NA);
-		}
-		return result;
-	}
-
-
-	/**
-	 * Finds first (lowest index) exact occurrence of specified value.
-	 * @param lookupComparer the value to be found in column or row vector
-	 * @param vector the values to be searched. For VLOOKUP this is the first column of the
-	 * 	tableArray. For HLOOKUP this is the first row of the tableArray.
-	 * @return zero based index into the vector, -1 if value cannot be found
-	 */
-	private static int lookupIndexOfExactValue(LookupValueComparer lookupComparer, ValueVector vector) {
-
-		// find first occurrence of lookup value
-		int size = vector.getSize();
-		for (int i = 0; i < size; i++) {
-			if(lookupComparer.compareTo(vector.getItem(i)).isEqual()) {
-				return i;
-			}
-		}
-		return -1;
-	}
-
-
-	/**
-	 * Encapsulates some standard binary search functionality so the unusual Excel behaviour can
-	 * be clearly distinguished.
-	 */
-	private static final class BinarySearchIndexes {
-
-		private int _lowIx;
-		private int _highIx;
-
-		public BinarySearchIndexes(int highIx) {
-			_lowIx = -1;
-			_highIx = highIx;
-		}
-
-		/**
-		 * @return -1 if the search range is empty
-		 */
-		public int getMidIx() {
-			int ixDiff = _highIx - _lowIx;
-			if(ixDiff < 2) {
-				return -1;
-			}
-			return _lowIx + (ixDiff / 2);
-		}
-
-		public int getLowIx() {
-			return _lowIx;
-		}
-		public int getHighIx() {
-			return _highIx;
-		}
-		public void narrowSearch(int midIx, boolean isLessThan) {
-			if(isLessThan) {
-				_highIx = midIx;
-			} else {
-				_lowIx = midIx;
-			}
-		}
-	}
-	/**
-	 * Excel has funny behaviour when the some elements in the search vector are the wrong type.
-	 *
-	 */
-	private static int performBinarySearch(ValueVector vector, LookupValueComparer lookupComparer) {
-		// both low and high indexes point to values assumed too low and too high.
-		BinarySearchIndexes bsi = new BinarySearchIndexes(vector.getSize());
-
-		while(true) {
-			int midIx = bsi.getMidIx();
-
-			if(midIx < 0) {
-				return bsi.getLowIx();
-			}
-			CompareResult cr = lookupComparer.compareTo(vector.getItem(midIx));
-			if(cr.isTypeMismatch()) {
-				int newMidIx = handleMidValueTypeMismatch(lookupComparer, vector, bsi, midIx);
-				if(newMidIx < 0) {
-					continue;
-				}
-				midIx = newMidIx;
-				cr = lookupComparer.compareTo(vector.getItem(midIx));
-			}
-			if(cr.isEqual()) {
-				return findLastIndexInRunOfEqualValues(lookupComparer, vector, midIx, bsi.getHighIx());
-			}
-			bsi.narrowSearch(midIx, cr.isLessThan());
-		}
-	}
-	/**
-	 * Excel seems to handle mismatched types initially by just stepping 'mid' ix forward to the
-	 * first compatible value.
-	 * @param midIx 'mid' index (value which has the wrong type)
-	 * @return usually -1, signifying that the BinarySearchIndex has been narrowed to the new mid
-	 * index.  Zero or greater signifies that an exact match for the lookup value was found
-	 */
-	private static int handleMidValueTypeMismatch(LookupValueComparer lookupComparer, ValueVector vector,
-			BinarySearchIndexes bsi, int midIx) {
-		int newMid = midIx;
-		int highIx = bsi.getHighIx();
-
-		while(true) {
-			newMid++;
-			if(newMid == highIx) {
-				// every element from midIx to highIx was the wrong type
-				// move highIx down to the low end of the mid values
-				bsi.narrowSearch(midIx, true);
-				return -1;
-			}
-			CompareResult cr = lookupComparer.compareTo(vector.getItem(newMid));
-			if(cr.isLessThan() && newMid == highIx-1) {
-				// move highIx down to the low end of the mid values
-				bsi.narrowSearch(midIx, true);
-				return -1;
-				// but only when "newMid == highIx-1"? slightly weird.
-				// It would seem more efficient to always do this.
-			}
-			if(cr.isTypeMismatch()) {
-				// keep stepping over values until the right type is found
-				continue;
-			}
-			if(cr.isEqual()) {
-				return newMid;
-			}
-			// Note - if moving highIx down (due to lookup<vector[newMid]),
-			// this execution path only moves highIx it down as far as newMid, not midIx,
-			// which would be more efficient.
-			bsi.narrowSearch(newMid, cr.isLessThan());
-			return -1;
-		}
-	}
-	/**
-	 * Once the binary search has found a single match, (V/H)LOOKUP steps one by one over subsequent
-	 * values to choose the last matching item.
-	 */
-	private static int findLastIndexInRunOfEqualValues(LookupValueComparer lookupComparer, ValueVector vector,
-				int firstFoundIndex, int maxIx) {
-		for(int i=firstFoundIndex+1; i<maxIx; i++) {
-			if(!lookupComparer.compareTo(vector.getItem(i)).isEqual()) {
-				return i-1;
-			}
-		}
-		return maxIx - 1;
-	}
-
-	public static LookupValueComparer createLookupComparer(ValueEval lookupValue, boolean matchExact, boolean isMatchFunction) {
-
-		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
-			return new NumberLookupComparer(NumberEval.ZERO);
-		}
-		if (lookupValue instanceof StringEval) {
+        }
+        @Override
+        protected String getValueAsString() {
+            return _value;
+        }
+    }
+    private static final class NumberLookupComparer extends LookupValueComparerBase {
+        private final double _value;
+
+        protected NumberLookupComparer(NumberEval ne) {
+            super(ne);
+            _value = ne.getNumberValue();
+        }
+        @Override
+        protected CompareResult compareSameType(ValueEval other) {
+            NumberEval ne = (NumberEval) other;
+            return CompareResult.valueOf(Double.compare(_value, ne.getNumberValue()));
+        }
+        @Override
+        protected String getValueAsString() {
+            return String.valueOf(_value);
+        }
+    }
+    private static final class BooleanLookupComparer extends LookupValueComparerBase {
+        private final boolean _value;
+
+        protected BooleanLookupComparer(BoolEval be) {
+            super(be);
+            _value = be.getBooleanValue();
+        }
+        @Override
+        protected CompareResult compareSameType(ValueEval other) {
+            BoolEval be = (BoolEval) other;
+            boolean otherVal = be.getBooleanValue();
+            if(_value == otherVal) {
+                return CompareResult.EQUAL;
+            }
+            // TRUE > FALSE
+            if(_value) {
+                return CompareResult.GREATER_THAN;
+            }
+            return CompareResult.LESS_THAN;
+        }
+        @Override
+        protected String getValueAsString() {
+            return String.valueOf(_value);
+        }
+    }
+
+    /**
+     * Processes the third argument to VLOOKUP, or HLOOKUP (<b>col_index_num</b>
+     * or <b>row_index_num</b> respectively).<br>
+     * Sample behaviour:
+     *    <table>
+     *      <caption>Sample behaviour</caption>
+     *      <tr><th>Input&nbsp;&nbsp;&nbsp;Return</th><th>Value&nbsp;&nbsp;</th><th>Thrown Error</th></tr>
+     *      <tr><td>5</td><td>4</td><td>&nbsp;</td></tr>
+     *      <tr><td>2.9</td><td>2</td><td>&nbsp;</td></tr>
+     *      <tr><td>"5"</td><td>4</td><td>&nbsp;</td></tr>
+     *      <tr><td>"2.18e1"</td><td>21</td><td>&nbsp;</td></tr>
+     *      <tr><td>"-$2"</td><td>-3</td><td>*</td></tr>
+     *      <tr><td>FALSE</td><td>-1</td><td>*</td></tr>
+     *      <tr><td>TRUE</td><td>0</td><td>&nbsp;</td></tr>
+     *      <tr><td>"TRUE"</td><td>&nbsp;</td><td>#REF!</td></tr>
+     *      <tr><td>"abc"</td><td>&nbsp;</td><td>#REF!</td></tr>
+     *      <tr><td>""</td><td>&nbsp;</td><td>#REF!</td></tr>
+     *      <tr><td>&lt;blank&gt;</td><td>&nbsp;</td><td>#VALUE!</td></tr>
+     *    </table><br>
+     *
+     * Note - out of range errors (result index too high) are handled by the caller.
+     * @return column or row index as a zero-based value, never negative.
+     * @throws EvaluationException when the specified arg cannot be coerced to a non-negative integer
+     */
+    public static int resolveRowOrColIndexArg(ValueEval rowColIndexArg, int srcCellRow, int srcCellCol) throws EvaluationException {
+        if(rowColIndexArg == null) {
+            throw new IllegalArgumentException("argument must not be null");
+        }
+
+        ValueEval veRowColIndexArg;
+        try {
+            veRowColIndexArg = OperandResolver.getSingleValue(rowColIndexArg, srcCellRow, (short)srcCellCol);
+        } catch (EvaluationException e) {
+            // All errors get translated to #REF!
+            throw EvaluationException.invalidRef();
+        }
+        int oneBasedIndex;
+        if(veRowColIndexArg instanceof StringEval) {
+            StringEval se = (StringEval) veRowColIndexArg;
+            String strVal = se.getStringValue();
+            Double dVal = OperandResolver.parseDouble(strVal);
+            if(dVal == null) {
+                // String does not resolve to a number. Raise #REF! error.
+                throw EvaluationException.invalidRef();
+                // This includes text booleans "TRUE" and "FALSE".  They are not valid.
+            }
+            // else - numeric value parses OK
+        }
+        // actual BoolEval values get interpreted as FALSE->0 and TRUE->1
+        oneBasedIndex = OperandResolver.coerceValueToInt(veRowColIndexArg);
+        if (oneBasedIndex < 1) {
+            // note this is asymmetric with the errors when the index is too large (#REF!)
+            throw EvaluationException.invalidValue();
+        }
+        return oneBasedIndex - 1; // convert to zero based
+    }
+
+
+
+    /**
+     * The second argument (table_array) should be an area ref, but can actually be a cell ref, in
+     * which case it is interpreted as a 1x1 area ref.  Other scalar values cause #VALUE! error.
+     */
+    public static TwoDEval resolveTableArrayArg(ValueEval eval) throws EvaluationException {
+        if (eval instanceof TwoDEval) {
+            return (TwoDEval) eval;
+        }
+
+        if(eval instanceof RefEval) {
+            RefEval refEval = (RefEval) eval;
+            // Make this cell ref look like a 1x1 area ref.
+
+            // It doesn't matter if eval is a 2D or 3D ref, because that detail is never asked of AreaEval.
+            return refEval.offset(0, 0, 0, 0);
+        }
+        throw EvaluationException.invalidValue();
+    }
+
+
+    /**
+     * Resolves the last (optional) parameter (<b>range_lookup</b>) to the VLOOKUP and HLOOKUP functions.
+     * @param rangeLookupArg must not be {@code null}
+     */
+    public static boolean resolveRangeLookupArg(ValueEval rangeLookupArg, int srcCellRow, int srcCellCol) throws EvaluationException {
+
+        ValueEval valEval = OperandResolver.getSingleValue(rangeLookupArg, srcCellRow, srcCellCol);
+        if(valEval == MissingArgEval.instance) {
+            // Tricky:
+            // forth arg exists but is not supplied: "=VLOOKUP(A1,A2:A4,2,)"
+            return false;
+        }
+        if(valEval instanceof BlankEval) {
+            // Tricky:
+            // fourth arg supplied but evaluates to blank
+            // this does not get the default value
+            return false;
+        }
+        if(valEval instanceof BoolEval) {
+            // Happy day flow
+            BoolEval boolEval = (BoolEval) valEval;
+            return boolEval.getBooleanValue();
+        }
+
+        if (valEval instanceof StringEval) {
+            String stringValue = ((StringEval) valEval).getStringValue();
+            if(stringValue.length() < 1) {
+                // More trickiness:
+                // Empty string is not the same as BlankEval.  It causes #VALUE! error
+                throw EvaluationException.invalidValue();
+            }
+            // TODO move parseBoolean to OperandResolver
+            Boolean b = Countif.parseBoolean(stringValue);
+            if(b != null) {
+                // string converted to boolean OK
+                return b;
+            }
+            // Even more trickiness:
+            // Note - even if the StringEval represents a number value (for example "1"),
+            // Excel does not resolve it to a boolean.
+            throw EvaluationException.invalidValue();
+            // This is in contrast to the code below,, where NumberEvals values (for
+            // example 0.01) *do* resolve to equivalent boolean values.
+        }
+        if (valEval instanceof NumericValueEval) {
+            NumericValueEval nve = (NumericValueEval) valEval;
+            // zero is FALSE, everything else is TRUE
+            return 0.0 != nve.getNumberValue();
+        }
+        throw new RuntimeException("Unexpected eval type (" + valEval + ")");
+    }
+
+    public static int lookupIndexOfValue(ValueEval lookupValue, ValueVector vector, boolean isRangeLookup) throws EvaluationException {
+        LookupValueComparer lookupComparer = createLookupComparer(lookupValue, isRangeLookup, false);
+        int result;
+        if(isRangeLookup) {
+            result = performBinarySearch(vector, lookupComparer);
+        } else {
+            result = lookupIndexOfExactValue(lookupComparer, vector);
+        }
+        if(result < 0) {
+            throw new EvaluationException(ErrorEval.NA);
+        }
+        return result;
+    }
+
+
+    /**
+     * Finds first (lowest index) exact occurrence of specified value.
+     * @param lookupComparer the value to be found in column or row vector
+     * @param vector the values to be searched. For VLOOKUP this is the first column of the
+     *  tableArray. For HLOOKUP this is the first row of the tableArray.
+     * @return zero based index into the vector, -1 if value cannot be found
+     */
+    private static int lookupIndexOfExactValue(LookupValueComparer lookupComparer, ValueVector vector) {
+
+        // find first occurrence of lookup value
+        int size = vector.getSize();
+        for (int i = 0; i < size; i++) {
+            if(lookupComparer.compareTo(vector.getItem(i)).isEqual()) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+
+    /**
+     * Encapsulates some standard binary search functionality so the unusual Excel behaviour can
+     * be clearly distinguished.
+     */
+    private static final class BinarySearchIndexes {
+
+        private int _lowIx;
+        private int _highIx;
+
+        public BinarySearchIndexes(int highIx) {
+            _lowIx = -1;
+            _highIx = highIx;
+        }
+
+        /**
+         * @return -1 if the search range is empty
+         */
+        public int getMidIx() {
+            int ixDiff = _highIx - _lowIx;
+            if(ixDiff < 2) {
+                return -1;
+            }
+            return _lowIx + (ixDiff / 2);
+        }
+
+        public int getLowIx() {
+            return _lowIx;
+        }
+        public int getHighIx() {
+            return _highIx;
+        }
+        public void narrowSearch(int midIx, boolean isLessThan) {
+            if(isLessThan) {
+                _highIx = midIx;
+            } else {
+                _lowIx = midIx;
+            }
+        }
+    }
+    /**
+     * Excel has funny behaviour when the some elements in the search vector are the wrong type.
+     *
+     */
+    private static int performBinarySearch(ValueVector vector, LookupValueComparer lookupComparer) {
+        // both low and high indexes point to values assumed too low and too high.
+        BinarySearchIndexes bsi = new BinarySearchIndexes(vector.getSize());
+
+        while(true) {
+            int midIx = bsi.getMidIx();
+
+            if(midIx < 0) {
+                return bsi.getLowIx();
+            }
+            CompareResult cr = lookupComparer.compareTo(vector.getItem(midIx));
+            if(cr.isTypeMismatch()) {
+                int newMidIx = handleMidValueTypeMismatch(lookupComparer, vector, bsi, midIx);
+                if(newMidIx < 0) {
+                    continue;
+                }
+                midIx = newMidIx;
+                cr = lookupComparer.compareTo(vector.getItem(midIx));
+            }
+            if(cr.isEqual()) {
+                return findLastIndexInRunOfEqualValues(lookupComparer, vector, midIx, bsi.getHighIx());
+            }
+            bsi.narrowSearch(midIx, cr.isLessThan());
+        }
+    }
+    /**
+     * Excel seems to handle mismatched types initially by just stepping 'mid' ix forward to the
+     * first compatible value.
+     * @param midIx 'mid' index (value which has the wrong type)
+     * @return usually -1, signifying that the BinarySearchIndex has been narrowed to the new mid
+     * index.  Zero or greater signifies that an exact match for the lookup value was found
+     */
+    private static int handleMidValueTypeMismatch(LookupValueComparer lookupComparer, ValueVector vector,
+            BinarySearchIndexes bsi, int midIx) {
+        int newMid = midIx;
+        int highIx = bsi.getHighIx();
+
+        while(true) {
+            newMid++;
+            if(newMid == highIx) {
+                // every element from midIx to highIx was the wrong type
+                // move highIx down to the low end of the mid values
+                bsi.narrowSearch(midIx, true);
+                return -1;
+            }
+            CompareResult cr = lookupComparer.compareTo(vector.getItem(newMid));
+            if(cr.isLessThan() && newMid == highIx-1) {
+                // move highIx down to the low end of the mid values
+                bsi.narrowSearch(midIx, true);
+                return -1;
+                // but only when "newMid == highIx-1"? slightly weird.
+                // It would seem more efficient to always do this.
+            }
+            if(cr.isTypeMismatch()) {
+                // keep stepping over values until the right type is found
+                continue;
+            }
+            if(cr.isEqual()) {
+                return newMid;
+            }
+            // Note - if moving highIx down (due to lookup<vector[newMid]),
+            // this execution path only moves highIx it down as far as newMid, not midIx,
+            // which would be more efficient.
+            bsi.narrowSearch(newMid, cr.isLessThan());
+            return -1;
+        }
+    }
+    /**
+     * Once the binary search has found a single match, (V/H)LOOKUP steps one by one over subsequent
+     * values to choose the last matching item.
+     */
+    private static int findLastIndexInRunOfEqualValues(LookupValueComparer lookupComparer, ValueVector vector,
+                int firstFoundIndex, int maxIx) {
+        for(int i=firstFoundIndex+1; i<maxIx; i++) {
+            if(!lookupComparer.compareTo(vector.getItem(i)).isEqual()) {
+                return i-1;
+            }
+        }
+        return maxIx - 1;
+    }
+
+    public static LookupValueComparer createLookupComparer(ValueEval lookupValue, boolean matchExact, boolean isMatchFunction) {
+
+        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
+            return new NumberLookupComparer(NumberEval.ZERO);
+        }
+        if (lookupValue instanceof StringEval) {
             //TODO eventually here return a WildcardStringLookupComparer
-			return new StringLookupComparer((StringEval) lookupValue, matchExact, isMatchFunction);
-		}
-		if (lookupValue instanceof NumberEval) {
-			return new NumberLookupComparer((NumberEval) lookupValue);
-		}
-		if (lookupValue instanceof BoolEval) {
-			return new BooleanLookupComparer((BoolEval) lookupValue);
-		}
-		throw new IllegalArgumentException("Bad lookup value type (" + lookupValue.getClass().getName() + ")");
-	}
+            return new StringLookupComparer((StringEval) lookupValue, matchExact, isMatchFunction);
+        }
+        if (lookupValue instanceof NumberEval) {
+            return new NumberLookupComparer((NumberEval) lookupValue);
+        }
+        if (lookupValue instanceof BoolEval) {
+            return new BooleanLookupComparer((BoolEval) lookupValue);
+        }
+        throw new IllegalArgumentException("Bad lookup value type (" + lookupValue.getClass().getName() + ")");
+    }
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Match.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Match.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Match.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Match.java Sat May 22 20:56:44 2021
@@ -65,185 +65,185 @@ import org.apache.poi.ss.formula.functio
  */
 public final class Match extends Var2or3ArgFunction {
 
-	@Override
-	public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
-		// default match_type is 1.0
-		return eval(srcRowIndex, srcColumnIndex, arg0, arg1, 1.0);
-	}
-
-
-	@Override
-	public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
-			ValueEval arg2) {
-
-		double match_type;
-
-		try {
-			match_type = evaluateMatchTypeArg(arg2, srcRowIndex, srcColumnIndex);
-		} catch (EvaluationException e) {
-			// Excel/MATCH() seems to have slightly abnormal handling of errors with
-			// the last parameter.  Errors do not propagate up.  Every error gets
-			// translated into #REF!
-			return ErrorEval.REF_INVALID;
-		}
-
-		return eval(srcRowIndex, srcColumnIndex, arg0, arg1, match_type);
-	}
-
-	private static  ValueEval eval(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
-			double match_type) {
-		boolean matchExact = match_type == 0;
-		// Note - Excel does not strictly require -1 and +1
-		boolean findLargestLessThanOrEqual = match_type > 0;
-
-		try {
-			ValueEval lookupValue = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
-			ValueVector lookupRange = evaluateLookupRange(arg1);
-			int index = findIndexOfValue(lookupValue, lookupRange, matchExact, findLargestLessThanOrEqual);
-			return new NumberEval(index + 1.); // +1 to convert to 1-based
-		} catch (EvaluationException e) {
-			return e.getErrorEval();
-		}
-	}
-
-	private static final class SingleValueVector implements ValueVector {
-
-		private final ValueEval _value;
-
-		public SingleValueVector(ValueEval value) {
-			_value = value;
-		}
+    @Override
+    public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
+        // default match_type is 1.0
+        return eval(srcRowIndex, srcColumnIndex, arg0, arg1, 1.0);
+    }
+
+
+    @Override
+    public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+            ValueEval arg2) {
+
+        double match_type;
+
+        try {
+            match_type = evaluateMatchTypeArg(arg2, srcRowIndex, srcColumnIndex);
+        } catch (EvaluationException e) {
+            // Excel/MATCH() seems to have slightly abnormal handling of errors with
+            // the last parameter.  Errors do not propagate up.  Every error gets
+            // translated into #REF!
+            return ErrorEval.REF_INVALID;
+        }
+
+        return eval(srcRowIndex, srcColumnIndex, arg0, arg1, match_type);
+    }
+
+    private static  ValueEval eval(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+            double match_type) {
+        boolean matchExact = match_type == 0;
+        // Note - Excel does not strictly require -1 and +1
+        boolean findLargestLessThanOrEqual = match_type > 0;
+
+        try {
+            ValueEval lookupValue = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
+            ValueVector lookupRange = evaluateLookupRange(arg1);
+            int index = findIndexOfValue(lookupValue, lookupRange, matchExact, findLargestLessThanOrEqual);
+            return new NumberEval(index + 1.); // +1 to convert to 1-based
+        } catch (EvaluationException e) {
+            return e.getErrorEval();
+        }
+    }
+
+    private static final class SingleValueVector implements ValueVector {
+
+        private final ValueEval _value;
+
+        public SingleValueVector(ValueEval value) {
+            _value = value;
+        }
 
-		@Override
+        @Override
         public ValueEval getItem(int index) {
-			if (index != 0) {
-				throw new RuntimeException("Invalid index ("
-						+ index + ") only zero is allowed");
-			}
-			return _value;
-		}
-
-		@Override
-		public int getSize() {
-			return 1;
-		}
-	}
-
-	private static ValueVector evaluateLookupRange(ValueEval eval) throws EvaluationException {
-		if (eval instanceof RefEval) {
-			RefEval re = (RefEval) eval;
-			if (re.getNumberOfSheets() == 1) {
-			    return new SingleValueVector(re.getInnerValueEval(re.getFirstSheetIndex()));
-			} else {
-			    return LookupUtils.createVector(re);
-			}
-		}
-		if (eval instanceof TwoDEval) {
-			ValueVector result = LookupUtils.createVector((TwoDEval)eval);
-			if (result == null) {
-				throw new EvaluationException(ErrorEval.NA);
-			}
-			return result;
-		}
-
-		// Error handling for lookup_range arg is also unusual
-		if(eval instanceof NumericValueEval) {
-			throw new EvaluationException(ErrorEval.NA);
-		}
-		if (eval instanceof StringEval) {
-			StringEval se = (StringEval) eval;
-			Double d = OperandResolver.parseDouble(se.getStringValue());
-			if(d == null) {
-				// plain string
-				throw new EvaluationException(ErrorEval.VALUE_INVALID);
-			}
-			// else looks like a number
-			throw new EvaluationException(ErrorEval.NA);
-		}
-		throw new RuntimeException("Unexpected eval type (" + eval + ")");
-	}
-
-
-
-	private static double evaluateMatchTypeArg(ValueEval arg, int srcCellRow, int srcCellCol)
-			throws EvaluationException {
-		ValueEval match_type = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
-
-		if(match_type instanceof ErrorEval) {
-			throw new EvaluationException((ErrorEval)match_type);
-		}
-		if(match_type instanceof NumericValueEval) {
-			NumericValueEval ne = (NumericValueEval) match_type;
-			return ne.getNumberValue();
-		}
-		if (match_type instanceof StringEval) {
-			StringEval se = (StringEval) match_type;
-			Double d = OperandResolver.parseDouble(se.getStringValue());
-			if(d == null) {
-				// plain string
-				throw new EvaluationException(ErrorEval.VALUE_INVALID);
-			}
-			// if the string parses as a number, it is OK
-			return d;
-		}
-		if (match_type instanceof MissingArgEval || match_type instanceof BlankEval) {
-			// Excel-Online ignores a missing match-type and
-			// uses the default-value instead
-			return 1;
-		}
-		throw new RuntimeException("Unexpected match_type type (" + match_type.getClass().getName() + ")");
-	}
-
-	/**
-	 * @return zero based index
-	 */
-	private static int findIndexOfValue(ValueEval lookupValue, ValueVector lookupRange,
-			boolean matchExact, boolean findLargestLessThanOrEqual) throws EvaluationException {
-
-		LookupValueComparer lookupComparer = createLookupComparer(lookupValue, matchExact);
-
-		int size = lookupRange.getSize();
-		if(matchExact) {
-			for (int i = 0; i < size; i++) {
-				if(lookupComparer.compareTo(lookupRange.getItem(i)).isEqual()) {
-					return i;
-				}
-			}
-			throw new EvaluationException(ErrorEval.NA);
-		}
-
-		if(findLargestLessThanOrEqual) {
-			// Note - backward iteration
-			for (int i = size - 1; i>=0;  i--) {
-				CompareResult cmp = lookupComparer.compareTo(lookupRange.getItem(i));
-				if(cmp.isTypeMismatch()) {
-					continue;
-				}
-				if(!cmp.isLessThan()) {
-					return i;
-				}
-			}
-			throw new EvaluationException(ErrorEval.NA);
-		}
-
-		// else - find smallest greater than or equal to
-		// TODO - is binary search used for (match_type==+1) ?
-		for (int i = 0; i<size; i++) {
-			CompareResult cmp = lookupComparer.compareTo(lookupRange.getItem(i));
-			if(cmp.isEqual()) {
-				return i;
-			}
-			if(cmp.isGreaterThan()) {
-				if(i<1) {
-					throw new EvaluationException(ErrorEval.NA);
-				}
-				return i-1;
-			}
-		}
-		return size-1;
-	}
-
-	private static LookupValueComparer createLookupComparer(ValueEval lookupValue, boolean matchExact) {
-		return LookupUtils.createLookupComparer(lookupValue, matchExact, true);
-	}
+            if (index != 0) {
+                throw new RuntimeException("Invalid index ("
+                        + index + ") only zero is allowed");
+            }
+            return _value;
+        }
+
+        @Override
+        public int getSize() {
+            return 1;
+        }
+    }
+
+    private static ValueVector evaluateLookupRange(ValueEval eval) throws EvaluationException {
+        if (eval instanceof RefEval) {
+            RefEval re = (RefEval) eval;
+            if (re.getNumberOfSheets() == 1) {
+                return new SingleValueVector(re.getInnerValueEval(re.getFirstSheetIndex()));
+            } else {
+                return LookupUtils.createVector(re);
+            }
+        }
+        if (eval instanceof TwoDEval) {
+            ValueVector result = LookupUtils.createVector((TwoDEval)eval);
+            if (result == null) {
+                throw new EvaluationException(ErrorEval.NA);
+            }
+            return result;
+        }
+
+        // Error handling for lookup_range arg is also unusual
+        if(eval instanceof NumericValueEval) {
+            throw new EvaluationException(ErrorEval.NA);
+        }
+        if (eval instanceof StringEval) {
+            StringEval se = (StringEval) eval;
+            Double d = OperandResolver.parseDouble(se.getStringValue());
+            if(d == null) {
+                // plain string
+                throw new EvaluationException(ErrorEval.VALUE_INVALID);
+            }
+            // else looks like a number
+            throw new EvaluationException(ErrorEval.NA);
+        }
+        throw new RuntimeException("Unexpected eval type (" + eval + ")");
+    }
+
+
+
+    private static double evaluateMatchTypeArg(ValueEval arg, int srcCellRow, int srcCellCol)
+            throws EvaluationException {
+        ValueEval match_type = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+
+        if(match_type instanceof ErrorEval) {
+            throw new EvaluationException((ErrorEval)match_type);
+        }
+        if(match_type instanceof NumericValueEval) {
+            NumericValueEval ne = (NumericValueEval) match_type;
+            return ne.getNumberValue();
+        }
+        if (match_type instanceof StringEval) {
+            StringEval se = (StringEval) match_type;
+            Double d = OperandResolver.parseDouble(se.getStringValue());
+            if(d == null) {
+                // plain string
+                throw new EvaluationException(ErrorEval.VALUE_INVALID);
+            }
+            // if the string parses as a number, it is OK
+            return d;
+        }
+        if (match_type instanceof MissingArgEval || match_type instanceof BlankEval) {
+            // Excel-Online ignores a missing match-type and
+            // uses the default-value instead
+            return 1;
+        }
+        throw new RuntimeException("Unexpected match_type type (" + match_type.getClass().getName() + ")");
+    }
+
+    /**
+     * @return zero based index
+     */
+    private static int findIndexOfValue(ValueEval lookupValue, ValueVector lookupRange,
+            boolean matchExact, boolean findLargestLessThanOrEqual) throws EvaluationException {
+
+        LookupValueComparer lookupComparer = createLookupComparer(lookupValue, matchExact);
+
+        int size = lookupRange.getSize();
+        if(matchExact) {
+            for (int i = 0; i < size; i++) {
+                if(lookupComparer.compareTo(lookupRange.getItem(i)).isEqual()) {
+                    return i;
+                }
+            }
+            throw new EvaluationException(ErrorEval.NA);
+        }
+
+        if(findLargestLessThanOrEqual) {
+            // Note - backward iteration
+            for (int i = size - 1; i>=0;  i--) {
+                CompareResult cmp = lookupComparer.compareTo(lookupRange.getItem(i));
+                if(cmp.isTypeMismatch()) {
+                    continue;
+                }
+                if(!cmp.isLessThan()) {
+                    return i;
+                }
+            }
+            throw new EvaluationException(ErrorEval.NA);
+        }
+
+        // else - find smallest greater than or equal to
+        // TODO - is binary search used for (match_type==+1) ?
+        for (int i = 0; i<size; i++) {
+            CompareResult cmp = lookupComparer.compareTo(lookupRange.getItem(i));
+            if(cmp.isEqual()) {
+                return i;
+            }
+            if(cmp.isGreaterThan()) {
+                if(i<1) {
+                    throw new EvaluationException(ErrorEval.NA);
+                }
+                return i-1;
+            }
+        }
+        return size-1;
+    }
+
+    private static LookupValueComparer createLookupComparer(ValueEval lookupValue, boolean matchExact) {
+        return LookupUtils.createLookupComparer(lookupValue, matchExact, true);
+    }
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/MinaMaxa.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/MinaMaxa.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/MinaMaxa.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/MinaMaxa.java Sat May 22 20:56:44 2021
@@ -19,18 +19,18 @@ package org.apache.poi.ss.formula.functi
 
 public abstract class MinaMaxa extends MultiOperandNumericFunction {
 
-	protected MinaMaxa() {
-		super(true, true);
-	}
+    protected MinaMaxa() {
+        super(true, true);
+    }
 
-	public static final Function MAXA = new MinaMaxa() {
-		protected double evaluate(double[] values) {
-			return values.length > 0 ? MathX.max(values) : 0;
-		}
-	};
-	public static final Function MINA = new MinaMaxa() {
-		protected double evaluate(double[] values) {
-			return values.length > 0 ? MathX.min(values) : 0;
-		}
-	};
+    public static final Function MAXA = new MinaMaxa() {
+        protected double evaluate(double[] values) {
+            return values.length > 0 ? MathX.max(values) : 0;
+        }
+    };
+    public static final Function MINA = new MinaMaxa() {
+        protected double evaluate(double[] values) {
+            return values.length > 0 ? MathX.min(values) : 0;
+        }
+    };
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Mode.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Mode.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Mode.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Mode.java Sat May 22 20:56:44 2021
@@ -33,101 +33,101 @@ import org.apache.poi.ss.formula.eval.Va
 
 public final class Mode implements Function {
 
-	/**
-	 * if v is zero length or contains no duplicates, return value is
-	 * Double.NaN. Else returns the value that occurs most times and if there is
-	 * a tie, returns the first such value.
-	 *
-	 * @param v An array of values on which the mode is computed.
-	 */
-	public static double evaluate(double[] v) throws EvaluationException {
-		if (v.length < 2) {
-			throw new EvaluationException(ErrorEval.NA);
-		}
-
-		// very naive impl, may need to be optimized
-		int[] counts = new int[v.length];
-		Arrays.fill(counts, 1);
-		for (int i = 0, iSize = v.length; i < iSize; i++) {
-			for (int j = i + 1, jSize = v.length; j < jSize; j++) {
-				if (v[i] == v[j])
-					counts[i]++;
-			}
-		}
-		double maxv = 0;
-		int maxc = 0;
-		for (int i = 0, iSize = counts.length; i < iSize; i++) {
-			if (counts[i] > maxc) {
-				maxv = v[i];
-				maxc = counts[i];
-			}
-		}
-		if (maxc > 1) {
-			return maxv;
-		}
-		throw new EvaluationException(ErrorEval.NA);
-
-	}
-
-	public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
-		double result;
-		try {
-			List<Double> temp = new ArrayList<>();
-			for (ValueEval arg : args) {
-				collectValues(arg, temp);
-			}
-			double[] values = new double[temp.size()];
-			for (int i = 0; i < values.length; i++) {
-				values[i] = temp.get(i).doubleValue();
-			}
-			result = evaluate(values);
-		} catch (EvaluationException e) {
-			return e.getErrorEval();
-		}
-		return new NumberEval(result);
-	}
-
-	private static void collectValues(ValueEval arg, List<Double> temp) throws EvaluationException {
-		if (arg instanceof TwoDEval) {
-			TwoDEval ae = (TwoDEval) arg;
-			int width = ae.getWidth();
-			int height = ae.getHeight();
-			for (int rrIx = 0; rrIx < height; rrIx++) {
-				for (int rcIx = 0; rcIx < width; rcIx++) {
-					ValueEval ve1 = ae.getValue(rrIx, rcIx);
-					collectValue(ve1, temp, false);
-				}
-			}
-			return;
-		}
-		if (arg instanceof RefEval) {
-			RefEval re = (RefEval) arg;
-			final int firstSheetIndex = re.getFirstSheetIndex();
-			final int lastSheetIndex = re.getLastSheetIndex();
-			for (int sIx = firstSheetIndex; sIx <= lastSheetIndex; sIx++) {
-			    collectValue(re.getInnerValueEval(sIx), temp, true);
-			}
-			return;
-		}
-		collectValue(arg, temp, true);
-
-	}
-
-	private static void collectValue(ValueEval arg, List<Double> temp, boolean mustBeNumber)
-			throws EvaluationException {
-		if (arg instanceof ErrorEval) {
-			throw new EvaluationException((ErrorEval) arg);
-		}
-		if (arg == BlankEval.instance || arg instanceof BoolEval || arg instanceof StringEval) {
-			if (mustBeNumber) {
-				throw EvaluationException.invalidValue();
-			}
-			return;
-		}
-		if (arg instanceof NumberEval) {
-			temp.add(Double.valueOf(((NumberEval) arg).getNumberValue()));
-			return;
-		}
-		throw new RuntimeException("Unexpected value type (" + arg.getClass().getName() + ")");
-	}
+    /**
+     * if v is zero length or contains no duplicates, return value is
+     * Double.NaN. Else returns the value that occurs most times and if there is
+     * a tie, returns the first such value.
+     *
+     * @param v An array of values on which the mode is computed.
+     */
+    public static double evaluate(double[] v) throws EvaluationException {
+        if (v.length < 2) {
+            throw new EvaluationException(ErrorEval.NA);
+        }
+
+        // very naive impl, may need to be optimized
+        int[] counts = new int[v.length];
+        Arrays.fill(counts, 1);
+        for (int i = 0, iSize = v.length; i < iSize; i++) {
+            for (int j = i + 1, jSize = v.length; j < jSize; j++) {
+                if (v[i] == v[j])
+                    counts[i]++;
+            }
+        }
+        double maxv = 0;
+        int maxc = 0;
+        for (int i = 0, iSize = counts.length; i < iSize; i++) {
+            if (counts[i] > maxc) {
+                maxv = v[i];
+                maxc = counts[i];
+            }
+        }
+        if (maxc > 1) {
+            return maxv;
+        }
+        throw new EvaluationException(ErrorEval.NA);
+
+    }
+
+    public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
+        double result;
+        try {
+            List<Double> temp = new ArrayList<>();
+            for (ValueEval arg : args) {
+                collectValues(arg, temp);
+            }
+            double[] values = new double[temp.size()];
+            for (int i = 0; i < values.length; i++) {
+                values[i] = temp.get(i).doubleValue();
+            }
+            result = evaluate(values);
+        } catch (EvaluationException e) {
+            return e.getErrorEval();
+        }
+        return new NumberEval(result);
+    }
+
+    private static void collectValues(ValueEval arg, List<Double> temp) throws EvaluationException {
+        if (arg instanceof TwoDEval) {
+            TwoDEval ae = (TwoDEval) arg;
+            int width = ae.getWidth();
+            int height = ae.getHeight();
+            for (int rrIx = 0; rrIx < height; rrIx++) {
+                for (int rcIx = 0; rcIx < width; rcIx++) {
+                    ValueEval ve1 = ae.getValue(rrIx, rcIx);
+                    collectValue(ve1, temp, false);
+                }
+            }
+            return;
+        }
+        if (arg instanceof RefEval) {
+            RefEval re = (RefEval) arg;
+            final int firstSheetIndex = re.getFirstSheetIndex();
+            final int lastSheetIndex = re.getLastSheetIndex();
+            for (int sIx = firstSheetIndex; sIx <= lastSheetIndex; sIx++) {
+                collectValue(re.getInnerValueEval(sIx), temp, true);
+            }
+            return;
+        }
+        collectValue(arg, temp, true);
+
+    }
+
+    private static void collectValue(ValueEval arg, List<Double> temp, boolean mustBeNumber)
+            throws EvaluationException {
+        if (arg instanceof ErrorEval) {
+            throw new EvaluationException((ErrorEval) arg);
+        }
+        if (arg == BlankEval.instance || arg instanceof BoolEval || arg instanceof StringEval) {
+            if (mustBeNumber) {
+                throw EvaluationException.invalidValue();
+            }
+            return;
+        }
+        if (arg instanceof NumberEval) {
+            temp.add(Double.valueOf(((NumberEval) arg).getNumberValue()));
+            return;
+        }
+        throw new RuntimeException("Unexpected value type (" + arg.getClass().getName() + ")");
+    }
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Na.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Na.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Na.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Na.java Sat May 22 20:56:44 2021
@@ -24,7 +24,7 @@ import org.apache.poi.ss.formula.eval.Va
  * Implementation of Excel function NA()
  */
 public final class Na {
-	public static ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
-		return args.length != 0 ? ErrorEval.VALUE_INVALID : ErrorEval.NA;
-	}
+    public static ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
+        return args.length != 0 ? ErrorEval.VALUE_INVALID : ErrorEval.NA;
+    }
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/NotImplementedFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/NotImplementedFunction.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/NotImplementedFunction.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/NotImplementedFunction.java Sat May 22 20:56:44 2021
@@ -28,18 +28,18 @@ import org.apache.poi.ss.formula.eval.Va
  * yet implemented.
  */
 public final class NotImplementedFunction implements Function {
-	private final String _functionName;
-	protected NotImplementedFunction() {
-		_functionName = getClass().getName();
-	}
-	public NotImplementedFunction(String name) {
-		_functionName = name;
-	}
+    private final String _functionName;
+    protected NotImplementedFunction() {
+        _functionName = getClass().getName();
+    }
+    public NotImplementedFunction(String name) {
+        _functionName = name;
+    }
 
-	public ValueEval evaluate(ValueEval[] operands, int srcRow, int srcCol) {
-		throw new NotImplementedFunctionException(_functionName);
-	}
-	public String getFunctionName() {
-		return _functionName;
-	}
+    public ValueEval evaluate(ValueEval[] operands, int srcRow, int srcCol) {
+        throw new NotImplementedFunctionException(_functionName);
+    }
+    public String getFunctionName() {
+        return _functionName;
+    }
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Now.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Now.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Now.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Now.java Sat May 22 20:56:44 2021
@@ -28,11 +28,11 @@ import org.apache.poi.ss.usermodel.DateU
  * Implementation of Excel NOW() Function
  */
 public final class Now {
-	public static ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
-		if (args.length != 0) {
-			return ErrorEval.VALUE_INVALID;
-		}
-		Date now = new Date(System.currentTimeMillis());
-		return new NumberEval(DateUtil.getExcelDate(now));
-	}
+    public static ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+        if (args.length != 0) {
+            return ErrorEval.VALUE_INVALID;
+        }
+        Date now = new Date(System.currentTimeMillis());
+        return new NumberEval(DateUtil.getExcelDate(now));
+    }
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Npv.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Npv.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Npv.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Npv.java Sat May 22 20:56:44 2021
@@ -33,23 +33,23 @@ import org.apache.poi.ss.formula.eval.Va
  */
 public final class Npv implements Function {
 
-	public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
-		int nArgs = args.length;
-		if (nArgs < 2) {
-			return ErrorEval.VALUE_INVALID;
-		}
+    public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+        int nArgs = args.length;
+        if (nArgs < 2) {
+            return ErrorEval.VALUE_INVALID;
+        }
 
         try {
-			double rate = NumericFunction.singleOperandEvaluate(args[0], srcRowIndex, srcColumnIndex);
+            double rate = NumericFunction.singleOperandEvaluate(args[0], srcRowIndex, srcColumnIndex);
             // convert tail arguments into an array of doubles
             ValueEval[] vargs = Arrays.copyOfRange(args, 1, args.length, ValueEval[].class);
             double[] values = AggregateFunction.ValueCollector.collectValues(vargs);
 
             double result = FinanceLib.npv(rate, values);
-			NumericFunction.checkValue(result);
+            NumericFunction.checkValue(result);
             return new NumberEval(result);
-		} catch (EvaluationException e) {
-			return e.getErrorEval();
-		}
-	}
+        } catch (EvaluationException e) {
+            return e.getErrorEval();
+        }
+    }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org