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 [18/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/eval/RelationalOperationEval.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/RelationalOperationEval.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/RelationalOperationEval.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/RelationalOperationEval.java Sat May 22 20:56:44 2021
@@ -27,154 +27,154 @@ import org.apache.poi.ss.util.NumberComp
  */
 public abstract class RelationalOperationEval extends Fixed2ArgFunction implements ArrayFunction {
 
-	/**
-	 * Converts a standard compare result (-1, 0, 1) to <code>true</code> or <code>false</code>
-	 * according to subclass' comparison type.
-	 */
-	protected abstract boolean convertComparisonResult(int cmpResult);
-
-	/**
-	 * This is a description of how the relational operators apply in MS Excel.
-	 * Use this as a guideline when testing/implementing the evaluate methods
-	 * for the relational operators Evals.
-	 *
-	 * <pre>
-	 * Bool.TRUE &gt; any number.
-	 * Bool &gt; any string. ALWAYS
-	 * Bool.TRUE &gt; Bool.FALSE
-	 * Bool.FALSE == Blank
-	 *
-	 * Strings are never converted to numbers or booleans
-	 * String &gt; any number. ALWAYS
-	 * Non-empty String &gt; Blank
-	 * Empty String == Blank
-	 * String are sorted dictionary wise
-	 *
-	 * Blank &gt; Negative numbers
-	 * Blank == 0
-	 * Blank &lt; Positive numbers
-	 * </pre>
-	 */
-
-	public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
-
-		ValueEval vA;
-		ValueEval vB;
-		try {
-			vA = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
-			vB = OperandResolver.getSingleValue(arg1, srcRowIndex, srcColumnIndex);
-		} catch (EvaluationException e) {
-			return e.getErrorEval();
-		}
-		int cmpResult = doCompare(vA, vB);
-		boolean result = convertComparisonResult(cmpResult);
-		return BoolEval.valueOf(result);
-	}
-
-	@Override
-	public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
-		ValueEval arg0 = args[0];
-		ValueEval arg1 = args[1];
-		return evaluateTwoArrayArgs(arg0, arg1, srcRowIndex, srcColumnIndex, (vA, vB) -> {
-			int cmpResult = doCompare(vA, vB);
-			boolean result = convertComparisonResult(cmpResult);
-			return BoolEval.valueOf(result);
-		});
-
-	}
-
-	private static int doCompare(ValueEval va, ValueEval vb) {
-		// special cases when one operand is blank or missing
-		if (va == BlankEval.instance || va instanceof MissingArgEval) {
-			return compareBlank(vb);
-		}
-		if (vb == BlankEval.instance || vb instanceof MissingArgEval) {
-			return -compareBlank(va);
-		}
-
-		if (va instanceof BoolEval) {
-			if (vb instanceof BoolEval) {
-				BoolEval bA = (BoolEval) va;
-				BoolEval bB = (BoolEval) vb;
-				if (bA.getBooleanValue() == bB.getBooleanValue()) {
-					return 0;
-				}
-				return bA.getBooleanValue() ? 1 : -1;
-			}
-			return 1;
-		}
-		if (vb instanceof BoolEval) {
-			return -1;
-		}
-		if (va instanceof StringEval) {
-			if (vb instanceof StringEval) {
-				StringEval sA = (StringEval) va;
-				StringEval sB = (StringEval) vb;
-				return sA.getStringValue().compareToIgnoreCase(sB.getStringValue());
-			}
-			return 1;
-		}
-		if (vb instanceof StringEval) {
-			return -1;
-		}
-		if (va instanceof NumberEval) {
-			if (vb instanceof NumberEval) {
-				NumberEval nA = (NumberEval) va;
-				NumberEval nB = (NumberEval) vb;
-				return NumberComparer.compare(nA.getNumberValue(), nB.getNumberValue());
-			}
-		}
-		throw new IllegalArgumentException("Bad operand types (" + va.getClass().getName() + "), ("
-				+ vb.getClass().getName() + ")");
-	}
-
-	private static int compareBlank(ValueEval v) {
-		if (v == BlankEval.instance || v instanceof MissingArgEval) {
-			return 0;
-		}
-		if (v instanceof BoolEval) {
-			BoolEval boolEval = (BoolEval) v;
-			return boolEval.getBooleanValue() ? -1 : 0;
-		}
-		if (v instanceof NumberEval) {
-			NumberEval ne = (NumberEval) v;
-			return NumberComparer.compare(0.0, ne.getNumberValue());
-		}
-		if (v instanceof StringEval) {
-			StringEval se = (StringEval) v;
-			return se.getStringValue().length() < 1 ? 0 : -1;
-		}
-		throw new IllegalArgumentException("bad value class (" + v.getClass().getName() + ")");
-	}
-
-	public static final Function EqualEval = new RelationalOperationEval() {
-		protected boolean convertComparisonResult(int cmpResult) {
-			return cmpResult == 0;
-		}
-	};
-	public static final Function GreaterEqualEval = new RelationalOperationEval() {
-		protected boolean convertComparisonResult(int cmpResult) {
-			return cmpResult >= 0;
-		}
-	};
-	public static final Function GreaterThanEval = new RelationalOperationEval() {
-		protected boolean convertComparisonResult(int cmpResult) {
-			return cmpResult > 0;
-		}
-	};
-	public static final Function LessEqualEval = new RelationalOperationEval() {
-		protected boolean convertComparisonResult(int cmpResult) {
-			return cmpResult <= 0;
-		}
-	};
-	public static final Function LessThanEval = new RelationalOperationEval() {
-		protected boolean convertComparisonResult(int cmpResult) {
-			return cmpResult < 0;
-		}
-	};
-	public static final Function NotEqualEval = new RelationalOperationEval() {
-		protected boolean convertComparisonResult(int cmpResult) {
-			return cmpResult != 0;
-		}
-	};
+    /**
+     * Converts a standard compare result (-1, 0, 1) to <code>true</code> or <code>false</code>
+     * according to subclass' comparison type.
+     */
+    protected abstract boolean convertComparisonResult(int cmpResult);
+
+    /**
+     * This is a description of how the relational operators apply in MS Excel.
+     * Use this as a guideline when testing/implementing the evaluate methods
+     * for the relational operators Evals.
+     *
+     * <pre>
+     * Bool.TRUE &gt; any number.
+     * Bool &gt; any string. ALWAYS
+     * Bool.TRUE &gt; Bool.FALSE
+     * Bool.FALSE == Blank
+     *
+     * Strings are never converted to numbers or booleans
+     * String &gt; any number. ALWAYS
+     * Non-empty String &gt; Blank
+     * Empty String == Blank
+     * String are sorted dictionary wise
+     *
+     * Blank &gt; Negative numbers
+     * Blank == 0
+     * Blank &lt; Positive numbers
+     * </pre>
+     */
+
+    public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
+
+        ValueEval vA;
+        ValueEval vB;
+        try {
+            vA = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
+            vB = OperandResolver.getSingleValue(arg1, srcRowIndex, srcColumnIndex);
+        } catch (EvaluationException e) {
+            return e.getErrorEval();
+        }
+        int cmpResult = doCompare(vA, vB);
+        boolean result = convertComparisonResult(cmpResult);
+        return BoolEval.valueOf(result);
+    }
+
+    @Override
+    public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+        ValueEval arg0 = args[0];
+        ValueEval arg1 = args[1];
+        return evaluateTwoArrayArgs(arg0, arg1, srcRowIndex, srcColumnIndex, (vA, vB) -> {
+            int cmpResult = doCompare(vA, vB);
+            boolean result = convertComparisonResult(cmpResult);
+            return BoolEval.valueOf(result);
+        });
+
+    }
+
+    private static int doCompare(ValueEval va, ValueEval vb) {
+        // special cases when one operand is blank or missing
+        if (va == BlankEval.instance || va instanceof MissingArgEval) {
+            return compareBlank(vb);
+        }
+        if (vb == BlankEval.instance || vb instanceof MissingArgEval) {
+            return -compareBlank(va);
+        }
+
+        if (va instanceof BoolEval) {
+            if (vb instanceof BoolEval) {
+                BoolEval bA = (BoolEval) va;
+                BoolEval bB = (BoolEval) vb;
+                if (bA.getBooleanValue() == bB.getBooleanValue()) {
+                    return 0;
+                }
+                return bA.getBooleanValue() ? 1 : -1;
+            }
+            return 1;
+        }
+        if (vb instanceof BoolEval) {
+            return -1;
+        }
+        if (va instanceof StringEval) {
+            if (vb instanceof StringEval) {
+                StringEval sA = (StringEval) va;
+                StringEval sB = (StringEval) vb;
+                return sA.getStringValue().compareToIgnoreCase(sB.getStringValue());
+            }
+            return 1;
+        }
+        if (vb instanceof StringEval) {
+            return -1;
+        }
+        if (va instanceof NumberEval) {
+            if (vb instanceof NumberEval) {
+                NumberEval nA = (NumberEval) va;
+                NumberEval nB = (NumberEval) vb;
+                return NumberComparer.compare(nA.getNumberValue(), nB.getNumberValue());
+            }
+        }
+        throw new IllegalArgumentException("Bad operand types (" + va.getClass().getName() + "), ("
+                + vb.getClass().getName() + ")");
+    }
+
+    private static int compareBlank(ValueEval v) {
+        if (v == BlankEval.instance || v instanceof MissingArgEval) {
+            return 0;
+        }
+        if (v instanceof BoolEval) {
+            BoolEval boolEval = (BoolEval) v;
+            return boolEval.getBooleanValue() ? -1 : 0;
+        }
+        if (v instanceof NumberEval) {
+            NumberEval ne = (NumberEval) v;
+            return NumberComparer.compare(0.0, ne.getNumberValue());
+        }
+        if (v instanceof StringEval) {
+            StringEval se = (StringEval) v;
+            return se.getStringValue().length() < 1 ? 0 : -1;
+        }
+        throw new IllegalArgumentException("bad value class (" + v.getClass().getName() + ")");
+    }
+
+    public static final Function EqualEval = new RelationalOperationEval() {
+        protected boolean convertComparisonResult(int cmpResult) {
+            return cmpResult == 0;
+        }
+    };
+    public static final Function GreaterEqualEval = new RelationalOperationEval() {
+        protected boolean convertComparisonResult(int cmpResult) {
+            return cmpResult >= 0;
+        }
+    };
+    public static final Function GreaterThanEval = new RelationalOperationEval() {
+        protected boolean convertComparisonResult(int cmpResult) {
+            return cmpResult > 0;
+        }
+    };
+    public static final Function LessEqualEval = new RelationalOperationEval() {
+        protected boolean convertComparisonResult(int cmpResult) {
+            return cmpResult <= 0;
+        }
+    };
+    public static final Function LessThanEval = new RelationalOperationEval() {
+        protected boolean convertComparisonResult(int cmpResult) {
+            return cmpResult < 0;
+        }
+    };
+    public static final Function NotEqualEval = new RelationalOperationEval() {
+        protected boolean convertComparisonResult(int cmpResult) {
+            return cmpResult != 0;
+        }
+    };
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/StringEval.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/StringEval.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/StringEval.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/StringEval.java Sat May 22 20:56:44 2021
@@ -24,29 +24,29 @@ import org.apache.poi.ss.formula.ptg.Str
 
 public final class StringEval implements StringValueEval {
 
-	public static final StringEval EMPTY_INSTANCE = new StringEval("");
+    public static final StringEval EMPTY_INSTANCE = new StringEval("");
 
-	//@NotNull
-	private final String _value;
+    //@NotNull
+    private final String _value;
 
-	public StringEval(Ptg ptg) {
-		this(((StringPtg) ptg).getValue());
-	}
-
-	public StringEval(String value) {
-		if (value == null) {
-			throw new IllegalArgumentException("value must not be null");
-		}
-		_value = value;
-	}
-
-	public String getStringValue() {
-		return _value;
-	}
-
-	public String toString() {
-		return getClass().getName() + " [" +
-				_value +
-				"]";
-	}
+    public StringEval(Ptg ptg) {
+        this(((StringPtg) ptg).getValue());
+    }
+
+    public StringEval(String value) {
+        if (value == null) {
+            throw new IllegalArgumentException("value must not be null");
+        }
+        _value = value;
+    }
+
+    public String getStringValue() {
+        return _value;
+    }
+
+    public String toString() {
+        return getClass().getName() + " [" +
+                _value +
+                "]";
+    }
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/TwoOperandNumericOperation.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/TwoOperandNumericOperation.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/TwoOperandNumericOperation.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/TwoOperandNumericOperation.java Sat May 22 20:56:44 2021
@@ -23,94 +23,94 @@ import org.apache.poi.ss.formula.functio
 
 public abstract class TwoOperandNumericOperation extends Fixed2ArgFunction implements ArrayFunction {
 
-	protected final double singleOperandEvaluate(ValueEval arg, int srcCellRow, int srcCellCol) throws EvaluationException {
-		ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
-		return OperandResolver.coerceValueToDouble(ve);
-	}
+    protected final double singleOperandEvaluate(ValueEval arg, int srcCellRow, int srcCellCol) throws EvaluationException {
+        ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+        return OperandResolver.coerceValueToDouble(ve);
+    }
 
-	@Override
+    @Override
     public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
-	    if (args.length != 2) {
-	        return ErrorEval.VALUE_INVALID;
-	    }
-	    //return new ArrayEval().evaluate(srcRowIndex, srcColumnIndex, args[0], args[1]);
-
-		return evaluateTwoArrayArgs(args[0], args[1], srcRowIndex, srcColumnIndex,
-				(vA, vB) -> {
-					try {
-						double d0 = OperandResolver.coerceValueToDouble(vA);
-						double d1 = OperandResolver.coerceValueToDouble(vB);
-						double result = evaluate(d0, d1);
-						return new NumberEval(result);
-					} catch (EvaluationException e){
-						return e.getErrorEval();
-					}
-				});
-
-	}
-
-	@Override
-	public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
-		double result;
-		try {
-			double d0 = singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
-			double d1 = singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
-			result = evaluate(d0, d1);
-			if (result == 0.0) { // this '==' matches +0.0 and -0.0
-				// Excel converts -0.0 to +0.0 for '*', '/', '%', '+' and '^'
-				if (!(this instanceof SubtractEvalClass)) {
-					return NumberEval.ZERO;
-				}
-			}
-			if (Double.isNaN(result) || Double.isInfinite(result)) {
-				return ErrorEval.NUM_ERROR;
-			}
-		} catch (EvaluationException e) {
-			return e.getErrorEval();
-		}
-		return new NumberEval(result);
-	}
-
-	protected abstract double evaluate(double d0, double d1) throws EvaluationException;
-
-	public static final Function AddEval = new TwoOperandNumericOperation() {
-		@Override
-		protected double evaluate(double d0, double d1) {
-			return d0+d1;
-		}
-	};
-	public static final Function DivideEval = new TwoOperandNumericOperation() {
-		@Override
-		protected double evaluate(double d0, double d1) throws EvaluationException {
-			if (d1 == 0.0) {
-				throw new EvaluationException(ErrorEval.DIV_ZERO);
-			}
-			return d0/d1;
-		}
-	};
-	public static final Function MultiplyEval = new TwoOperandNumericOperation() {
-		@Override
-		protected double evaluate(double d0, double d1) {
-			return d0*d1;
-		}
-	};
-	public static final Function PowerEval = new TwoOperandNumericOperation() {
-		@Override
-		protected double evaluate(double d0, double d1) {
-			if(d0 < 0 && Math.abs(d1) > 0.0 && Math.abs(d1) < 1.0) {
-				return -1 * Math.pow(d0 * -1, d1);
-			}
-			return Math.pow(d0, d1);
-		}
-	};
-	private static final class SubtractEvalClass extends TwoOperandNumericOperation {
-		public SubtractEvalClass() {
-			//
-		}
-		@Override
-		protected double evaluate(double d0, double d1) {
-			return d0-d1;
-		}
-	}
-	public static final Function SubtractEval = new SubtractEvalClass();
+        if (args.length != 2) {
+            return ErrorEval.VALUE_INVALID;
+        }
+        //return new ArrayEval().evaluate(srcRowIndex, srcColumnIndex, args[0], args[1]);
+
+        return evaluateTwoArrayArgs(args[0], args[1], srcRowIndex, srcColumnIndex,
+                (vA, vB) -> {
+                    try {
+                        double d0 = OperandResolver.coerceValueToDouble(vA);
+                        double d1 = OperandResolver.coerceValueToDouble(vB);
+                        double result = evaluate(d0, d1);
+                        return new NumberEval(result);
+                    } catch (EvaluationException e){
+                        return e.getErrorEval();
+                    }
+                });
+
+    }
+
+    @Override
+    public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
+        double result;
+        try {
+            double d0 = singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+            double d1 = singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
+            result = evaluate(d0, d1);
+            if (result == 0.0) { // this '==' matches +0.0 and -0.0
+                // Excel converts -0.0 to +0.0 for '*', '/', '%', '+' and '^'
+                if (!(this instanceof SubtractEvalClass)) {
+                    return NumberEval.ZERO;
+                }
+            }
+            if (Double.isNaN(result) || Double.isInfinite(result)) {
+                return ErrorEval.NUM_ERROR;
+            }
+        } catch (EvaluationException e) {
+            return e.getErrorEval();
+        }
+        return new NumberEval(result);
+    }
+
+    protected abstract double evaluate(double d0, double d1) throws EvaluationException;
+
+    public static final Function AddEval = new TwoOperandNumericOperation() {
+        @Override
+        protected double evaluate(double d0, double d1) {
+            return d0+d1;
+        }
+    };
+    public static final Function DivideEval = new TwoOperandNumericOperation() {
+        @Override
+        protected double evaluate(double d0, double d1) throws EvaluationException {
+            if (d1 == 0.0) {
+                throw new EvaluationException(ErrorEval.DIV_ZERO);
+            }
+            return d0/d1;
+        }
+    };
+    public static final Function MultiplyEval = new TwoOperandNumericOperation() {
+        @Override
+        protected double evaluate(double d0, double d1) {
+            return d0*d1;
+        }
+    };
+    public static final Function PowerEval = new TwoOperandNumericOperation() {
+        @Override
+        protected double evaluate(double d0, double d1) {
+            if(d0 < 0 && Math.abs(d1) > 0.0 && Math.abs(d1) < 1.0) {
+                return -1 * Math.pow(d0 * -1, d1);
+            }
+            return Math.pow(d0, d1);
+        }
+    };
+    private static final class SubtractEvalClass extends TwoOperandNumericOperation {
+        public SubtractEvalClass() {
+            //
+        }
+        @Override
+        protected double evaluate(double d0, double d1) {
+            return d0-d1;
+        }
+    }
+    public static final Function SubtractEval = new SubtractEvalClass();
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/UnaryMinusEval.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/UnaryMinusEval.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/UnaryMinusEval.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/UnaryMinusEval.java Sat May 22 20:56:44 2021
@@ -23,34 +23,34 @@ import org.apache.poi.ss.formula.functio
 
 public final class UnaryMinusEval extends Fixed1ArgFunction  implements ArrayFunction {
 
-	public static final Function instance = new UnaryMinusEval();
+    public static final Function instance = new UnaryMinusEval();
 
-	private UnaryMinusEval() {
-		// enforce singleton
-	}
-
-	public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
-		double d;
-		try {
-			ValueEval ve = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
-			d = OperandResolver.coerceValueToDouble(ve);
-		} catch (EvaluationException e) {
-			return e.getErrorEval();
-		}
-		if (d == 0.0) { // this '==' matches +0.0 and -0.0
-			return NumberEval.ZERO;
-		}
-		return new NumberEval(-d);
-	}
-
-	@Override
-	public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex){
-		if (args.length != 1) {
-			return ErrorEval.VALUE_INVALID;
-		}
-		return evaluateOneArrayArg(args[0], srcRowIndex, srcColumnIndex, (valA) ->
-				evaluate(srcRowIndex, srcColumnIndex, valA)
-		);
-	}
+    private UnaryMinusEval() {
+        // enforce singleton
+    }
+
+    public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
+        double d;
+        try {
+            ValueEval ve = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
+            d = OperandResolver.coerceValueToDouble(ve);
+        } catch (EvaluationException e) {
+            return e.getErrorEval();
+        }
+        if (d == 0.0) { // this '==' matches +0.0 and -0.0
+            return NumberEval.ZERO;
+        }
+        return new NumberEval(-d);
+    }
+
+    @Override
+    public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex){
+        if (args.length != 1) {
+            return ErrorEval.VALUE_INVALID;
+        }
+        return evaluateOneArrayArg(args[0], srcRowIndex, srcColumnIndex, (valA) ->
+                evaluate(srcRowIndex, srcColumnIndex, valA)
+        );
+    }
 
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/UnaryPlusEval.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/UnaryPlusEval.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/UnaryPlusEval.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/UnaryPlusEval.java Sat May 22 20:56:44 2021
@@ -24,37 +24,37 @@ import org.apache.poi.ss.formula.functio
 
 public final class UnaryPlusEval extends Fixed1ArgFunction  implements ArrayFunction {
 
-	public static final Function instance = new UnaryPlusEval();
+    public static final Function instance = new UnaryPlusEval();
 
-	private UnaryPlusEval() {
-		// enforce singleton
-	}
-
-	public ValueEval evaluate(int srcCellRow, int srcCellCol, ValueEval arg0) {
-		double d;
-		try {
-			ValueEval ve = OperandResolver.getSingleValue(arg0, srcCellRow, srcCellCol);
-			if(ve instanceof StringEval) {
-				// Note - asymmetric with UnaryMinus
-				// -"hello" evaluates to #VALUE!
-				// but +"hello" evaluates to "hello"
-				return ve;
-			}
-			d = OperandResolver.coerceValueToDouble(ve);
-		} catch (EvaluationException e) {
-			return e.getErrorEval();
-		}
-		return new NumberEval(+d);
-	}
-
-	@Override
-	public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex){
-		if (args.length != 1) {
-			return ErrorEval.VALUE_INVALID;
-		}
-		return evaluateOneArrayArg(args[0], srcRowIndex, srcColumnIndex, (valA) ->
-				evaluate(srcRowIndex, srcColumnIndex, valA)
-		);
-	}
+    private UnaryPlusEval() {
+        // enforce singleton
+    }
+
+    public ValueEval evaluate(int srcCellRow, int srcCellCol, ValueEval arg0) {
+        double d;
+        try {
+            ValueEval ve = OperandResolver.getSingleValue(arg0, srcCellRow, srcCellCol);
+            if(ve instanceof StringEval) {
+                // Note - asymmetric with UnaryMinus
+                // -"hello" evaluates to #VALUE!
+                // but +"hello" evaluates to "hello"
+                return ve;
+            }
+            d = OperandResolver.coerceValueToDouble(ve);
+        } catch (EvaluationException e) {
+            return e.getErrorEval();
+        }
+        return new NumberEval(+d);
+    }
+
+    @Override
+    public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex){
+        if (args.length != 1) {
+            return ErrorEval.VALUE_INVALID;
+        }
+        return evaluateOneArrayArg(args[0], srcRowIndex, srcColumnIndex, (valA) ->
+                evaluate(srcRowIndex, srcColumnIndex, valA)
+        );
+    }
 
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/ValueEval.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/ValueEval.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/ValueEval.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/ValueEval.java Sat May 22 20:56:44 2021
@@ -18,5 +18,5 @@
 package org.apache.poi.ss.formula.eval;
 
 public interface ValueEval {
-	// no methods
+    // no methods
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationCell.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationCell.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationCell.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationCell.java Sat May 22 20:56:44 2021
@@ -35,124 +35,124 @@ import org.apache.poi.ss.util.CellRangeA
  */
 final class ForkedEvaluationCell implements EvaluationCell {
 
-	private final EvaluationSheet _sheet;
-	/** corresponding cell from master workbook */
-	private final EvaluationCell _masterCell;
-	private boolean _booleanValue;
-	private CellType _cellType;
-	private int _errorValue;
-	private double _numberValue;
-	private String _stringValue;
-
-	public ForkedEvaluationCell(ForkedEvaluationSheet sheet, EvaluationCell masterCell) {
-		_sheet = sheet;
-		_masterCell = masterCell;
-		// start with value blank, but expect construction to be immediately
-		setValue(BlankEval.instance); // followed by a proper call to setValue()
-	}
-
-	@Override
-	public Object getIdentityKey() {
-		return _masterCell.getIdentityKey();
-	}
-
-	public void setValue(ValueEval value) {
-		Class<? extends ValueEval> cls = value.getClass();
-
-		if (cls == NumberEval.class) {
-			_cellType = CellType.NUMERIC;
-			_numberValue = ((NumberEval)value).getNumberValue();
-			return;
-		}
-		if (cls == StringEval.class) {
-			_cellType = CellType.STRING;
-			_stringValue = ((StringEval)value).getStringValue();
-			return;
-		}
-		if (cls == BoolEval.class) {
-			_cellType = CellType.BOOLEAN;
-			_booleanValue = ((BoolEval)value).getBooleanValue();
-			return;
-		}
-		if (cls == ErrorEval.class) {
-			_cellType = CellType.ERROR;
-			_errorValue = ((ErrorEval)value).getErrorCode();
-			return;
-		}
-		if (cls == BlankEval.class) {
-			_cellType = CellType.BLANK;
-			return;
-		}
-		throw new IllegalArgumentException("Unexpected value class (" + cls.getName() + ")");
-	}
-	public void copyValue(Cell destCell) {
-		switch (_cellType) {
-			case BLANK:   destCell.setBlank();                           return;
-			case NUMERIC: destCell.setCellValue(_numberValue);           return;
-			case BOOLEAN: destCell.setCellValue(_booleanValue);          return;
-			case STRING:  destCell.setCellValue(_stringValue);           return;
-			case ERROR:   destCell.setCellErrorValue((byte)_errorValue); return;
-			default: throw new IllegalStateException("Unexpected data type (" + _cellType + ")");
-		}
-	}
-
-	private void checkCellType(CellType expectedCellType) {
-		if (_cellType != expectedCellType) {
-			throw new RuntimeException("Wrong data type (" + _cellType + ")");
-		}
-	}
-
-	@Override
-	public CellType getCellType() {
-		return _cellType;
-	}
-	@Override
-	public boolean getBooleanCellValue() {
-		checkCellType(CellType.BOOLEAN);
-		return _booleanValue;
-	}
-	@Override
-	public int getErrorCellValue() {
-		checkCellType(CellType.ERROR);
-		return _errorValue;
-	}
-	@Override
-	public double getNumericCellValue() {
-		checkCellType(CellType.NUMERIC);
-		return _numberValue;
-	}
-	@Override
-	public String getStringCellValue() {
-		checkCellType(CellType.STRING);
-		return _stringValue;
-	}
-	@Override
-	public EvaluationSheet getSheet() {
-		return _sheet;
-	}
-	@Override
-	public int getRowIndex() {
-		return _masterCell.getRowIndex();
-	}
-	@Override
-	public int getColumnIndex() {
-		return _masterCell.getColumnIndex();
-	}
-
-	@Override
-	public CellRangeAddress getArrayFormulaRange() {
-		return _masterCell.getArrayFormulaRange();
-	}
-
-	@Override
-	public boolean isPartOfArrayFormulaGroup() {
-		return _masterCell.isPartOfArrayFormulaGroup();
-	}
-	/**
-	 * @return cell type of cached formula result
-	 */
-	@Override
-	public CellType getCachedFormulaResultType() {
-		return _masterCell.getCachedFormulaResultType();
-	}
+    private final EvaluationSheet _sheet;
+    /** corresponding cell from master workbook */
+    private final EvaluationCell _masterCell;
+    private boolean _booleanValue;
+    private CellType _cellType;
+    private int _errorValue;
+    private double _numberValue;
+    private String _stringValue;
+
+    public ForkedEvaluationCell(ForkedEvaluationSheet sheet, EvaluationCell masterCell) {
+        _sheet = sheet;
+        _masterCell = masterCell;
+        // start with value blank, but expect construction to be immediately
+        setValue(BlankEval.instance); // followed by a proper call to setValue()
+    }
+
+    @Override
+    public Object getIdentityKey() {
+        return _masterCell.getIdentityKey();
+    }
+
+    public void setValue(ValueEval value) {
+        Class<? extends ValueEval> cls = value.getClass();
+
+        if (cls == NumberEval.class) {
+            _cellType = CellType.NUMERIC;
+            _numberValue = ((NumberEval)value).getNumberValue();
+            return;
+        }
+        if (cls == StringEval.class) {
+            _cellType = CellType.STRING;
+            _stringValue = ((StringEval)value).getStringValue();
+            return;
+        }
+        if (cls == BoolEval.class) {
+            _cellType = CellType.BOOLEAN;
+            _booleanValue = ((BoolEval)value).getBooleanValue();
+            return;
+        }
+        if (cls == ErrorEval.class) {
+            _cellType = CellType.ERROR;
+            _errorValue = ((ErrorEval)value).getErrorCode();
+            return;
+        }
+        if (cls == BlankEval.class) {
+            _cellType = CellType.BLANK;
+            return;
+        }
+        throw new IllegalArgumentException("Unexpected value class (" + cls.getName() + ")");
+    }
+    public void copyValue(Cell destCell) {
+        switch (_cellType) {
+            case BLANK:   destCell.setBlank();                           return;
+            case NUMERIC: destCell.setCellValue(_numberValue);           return;
+            case BOOLEAN: destCell.setCellValue(_booleanValue);          return;
+            case STRING:  destCell.setCellValue(_stringValue);           return;
+            case ERROR:   destCell.setCellErrorValue((byte)_errorValue); return;
+            default: throw new IllegalStateException("Unexpected data type (" + _cellType + ")");
+        }
+    }
+
+    private void checkCellType(CellType expectedCellType) {
+        if (_cellType != expectedCellType) {
+            throw new RuntimeException("Wrong data type (" + _cellType + ")");
+        }
+    }
+
+    @Override
+    public CellType getCellType() {
+        return _cellType;
+    }
+    @Override
+    public boolean getBooleanCellValue() {
+        checkCellType(CellType.BOOLEAN);
+        return _booleanValue;
+    }
+    @Override
+    public int getErrorCellValue() {
+        checkCellType(CellType.ERROR);
+        return _errorValue;
+    }
+    @Override
+    public double getNumericCellValue() {
+        checkCellType(CellType.NUMERIC);
+        return _numberValue;
+    }
+    @Override
+    public String getStringCellValue() {
+        checkCellType(CellType.STRING);
+        return _stringValue;
+    }
+    @Override
+    public EvaluationSheet getSheet() {
+        return _sheet;
+    }
+    @Override
+    public int getRowIndex() {
+        return _masterCell.getRowIndex();
+    }
+    @Override
+    public int getColumnIndex() {
+        return _masterCell.getColumnIndex();
+    }
+
+    @Override
+    public CellRangeAddress getArrayFormulaRange() {
+        return _masterCell.getArrayFormulaRange();
+    }
+
+    @Override
+    public boolean isPartOfArrayFormulaGroup() {
+        return _masterCell.isPartOfArrayFormulaGroup();
+    }
+    /**
+     * @return cell type of cached formula result
+     */
+    @Override
+    public CellType getCachedFormulaResultType() {
+        return _masterCell.getCachedFormulaResultType();
+    }
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluator.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluator.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluator.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluator.java Sat May 22 20:56:44 2021
@@ -43,84 +43,84 @@ import org.apache.poi.ss.usermodel.Workb
  */
 public final class ForkedEvaluator {
 
-	private final WorkbookEvaluator _evaluator;
-	private final ForkedEvaluationWorkbook _sewb;
+    private final WorkbookEvaluator _evaluator;
+    private final ForkedEvaluationWorkbook _sewb;
 
-	private ForkedEvaluator(EvaluationWorkbook masterWorkbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
-		_sewb = new ForkedEvaluationWorkbook(masterWorkbook);
-		_evaluator = new WorkbookEvaluator(_sewb, stabilityClassifier, udfFinder);
-	}
-
-	/**
-	 * @param udfFinder pass {@code null} for default (AnalysisToolPak only)
-	 */
-	public static ForkedEvaluator create(Workbook wb, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
-		return new ForkedEvaluator(wb.createEvaluationWorkbook(), stabilityClassifier, udfFinder);
-	}
-
-	/**
-	 * Sets the specified cell to the supplied {@code value}
-	 * @param sheetName the name of the sheet containing the cell
-	 * @param rowIndex zero based
-	 * @param columnIndex zero based
-	 */
-	public void updateCell(String sheetName, int rowIndex, int columnIndex, ValueEval value) {
-
-		ForkedEvaluationCell cell = _sewb.getOrCreateUpdatableCell(sheetName, rowIndex, columnIndex);
-		cell.setValue(value);
-		_evaluator.notifyUpdateCell(cell);
-	}
-	/**
-	 * Copies the values of all updated cells (modified by calls to {@link
-	 * #updateCell(String, int, int, ValueEval)}) to the supplied {@code workbook}.<br>
-	 * Typically, the supplied {@code workbook} is a writable copy of the 'master workbook',
-	 * but at the very least it must contain sheets with the same names.
-	 */
-	public void copyUpdatedCells(Workbook workbook) {
-		_sewb.copyUpdatedCells(workbook);
-	}
-
-	/**
-	 * If cell contains a formula, the formula is evaluated and returned,
-	 * else the CellValue simply copies the appropriate cell value from
-	 * the cell and also its cell type. This method should be preferred over
-	 * evaluateInCell() when the call should not modify the contents of the
-	 * original cell.
-	 *
+    private ForkedEvaluator(EvaluationWorkbook masterWorkbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
+        _sewb = new ForkedEvaluationWorkbook(masterWorkbook);
+        _evaluator = new WorkbookEvaluator(_sewb, stabilityClassifier, udfFinder);
+    }
+
+    /**
+     * @param udfFinder pass {@code null} for default (AnalysisToolPak only)
+     */
+    public static ForkedEvaluator create(Workbook wb, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
+        return new ForkedEvaluator(wb.createEvaluationWorkbook(), stabilityClassifier, udfFinder);
+    }
+
+    /**
+     * Sets the specified cell to the supplied {@code value}
+     * @param sheetName the name of the sheet containing the cell
+     * @param rowIndex zero based
+     * @param columnIndex zero based
+     */
+    public void updateCell(String sheetName, int rowIndex, int columnIndex, ValueEval value) {
+
+        ForkedEvaluationCell cell = _sewb.getOrCreateUpdatableCell(sheetName, rowIndex, columnIndex);
+        cell.setValue(value);
+        _evaluator.notifyUpdateCell(cell);
+    }
+    /**
+     * Copies the values of all updated cells (modified by calls to {@link
+     * #updateCell(String, int, int, ValueEval)}) to the supplied {@code workbook}.<br>
+     * Typically, the supplied {@code workbook} is a writable copy of the 'master workbook',
+     * but at the very least it must contain sheets with the same names.
+     */
+    public void copyUpdatedCells(Workbook workbook) {
+        _sewb.copyUpdatedCells(workbook);
+    }
+
+    /**
+     * If cell contains a formula, the formula is evaluated and returned,
+     * else the CellValue simply copies the appropriate cell value from
+     * the cell and also its cell type. This method should be preferred over
+     * evaluateInCell() when the call should not modify the contents of the
+     * original cell.
+     *
      * @param sheetName the name of the sheet containing the cell
      * @param rowIndex zero based
      * @param columnIndex zero based
-	 * @return {@code null} if the supplied cell is {@code null} or blank
-	 */
-	public ValueEval evaluate(String sheetName, int rowIndex, int columnIndex) {
-		EvaluationCell cell = _sewb.getEvaluationCell(sheetName, rowIndex, columnIndex);
-
-		switch (cell.getCellType()) {
-			case BOOLEAN:
-				return BoolEval.valueOf(cell.getBooleanCellValue());
-			case ERROR:
-				return ErrorEval.valueOf(cell.getErrorCellValue());
-			case FORMULA:
-				return _evaluator.evaluate(cell);
-			case NUMERIC:
-				return new NumberEval(cell.getNumericCellValue());
-			case STRING:
-				return new StringEval(cell.getStringCellValue());
-			case BLANK:
-				return null;
-			default:
-				throw new IllegalStateException("Bad cell type (" + cell.getCellType() + ")");
-		}
-	}
-	/**
-	 * Coordinates several formula evaluators together so that formulas that involve external
-	 * references can be evaluated.
-	 * @param workbookNames the simple file names used to identify the workbooks in formulas
-	 * with external links (for example "MyData.xls" as used in a formula "[MyData.xls]Sheet1!A1")
-	 * @param evaluators all evaluators for the full set of workbooks required by the formulas.
-	 */
-	public static void setupEnvironment(String[] workbookNames, ForkedEvaluator[] evaluators) {
-		WorkbookEvaluator[] wbEvals = Stream.of(evaluators).map(e -> e._evaluator).toArray(WorkbookEvaluator[]::new);
-		CollaboratingWorkbooksEnvironment.setup(workbookNames, wbEvals);
-	}
+     * @return {@code null} if the supplied cell is {@code null} or blank
+     */
+    public ValueEval evaluate(String sheetName, int rowIndex, int columnIndex) {
+        EvaluationCell cell = _sewb.getEvaluationCell(sheetName, rowIndex, columnIndex);
+
+        switch (cell.getCellType()) {
+            case BOOLEAN:
+                return BoolEval.valueOf(cell.getBooleanCellValue());
+            case ERROR:
+                return ErrorEval.valueOf(cell.getErrorCellValue());
+            case FORMULA:
+                return _evaluator.evaluate(cell);
+            case NUMERIC:
+                return new NumberEval(cell.getNumericCellValue());
+            case STRING:
+                return new StringEval(cell.getStringCellValue());
+            case BLANK:
+                return null;
+            default:
+                throw new IllegalStateException("Bad cell type (" + cell.getCellType() + ")");
+        }
+    }
+    /**
+     * Coordinates several formula evaluators together so that formulas that involve external
+     * references can be evaluated.
+     * @param workbookNames the simple file names used to identify the workbooks in formulas
+     * with external links (for example "MyData.xls" as used in a formula "[MyData.xls]Sheet1!A1")
+     * @param evaluators all evaluators for the full set of workbooks required by the formulas.
+     */
+    public static void setupEnvironment(String[] workbookNames, ForkedEvaluator[] evaluators) {
+        WorkbookEvaluator[] wbEvals = Stream.of(evaluators).map(e -> e._evaluator).toArray(WorkbookEvaluator[]::new);
+        CollaboratingWorkbooksEnvironment.setup(workbookNames, wbEvals);
+    }
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/function/FunctionDataBuilder.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/function/FunctionDataBuilder.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/function/FunctionDataBuilder.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/function/FunctionDataBuilder.java Sat May 22 20:56:44 2021
@@ -27,62 +27,62 @@ import java.util.Set;
  * {@code FunctionMetadataRegistry}.
  */
 final class FunctionDataBuilder {
-	private int _maxFunctionIndex;
-	private final Map<String,FunctionMetadata> _functionDataByName;
-	private final Map<Integer,FunctionMetadata> _functionDataByIndex;
-	/** stores indexes of all functions with footnotes (i.e. whose definitions might change) */
-	private final Set<Integer> _mutatingFunctionIndexes;
-
-	public FunctionDataBuilder(int sizeEstimate) {
-		_maxFunctionIndex = -1;
-		_functionDataByName = new HashMap<>(sizeEstimate * 3 / 2);
-		_functionDataByIndex = new HashMap<>(sizeEstimate * 3 / 2);
-		_mutatingFunctionIndexes = new HashSet<>();
-	}
-
-	public void add(int functionIndex, String functionName, int minParams, int maxParams,
-			byte returnClassCode, byte[] parameterClassCodes, boolean hasFootnote) {
-		FunctionMetadata fm = new FunctionMetadata(functionIndex, functionName, minParams, maxParams,
-				returnClassCode, parameterClassCodes);
-
-		Integer indexKey = functionIndex;
-
-
-		if(functionIndex > _maxFunctionIndex) {
-			_maxFunctionIndex = functionIndex;
-		}
-		// allow function definitions to change only if both previous and the new items have footnotes
-		FunctionMetadata prevFM;
-		prevFM = _functionDataByName.get(functionName);
-		if(prevFM != null) {
-			if(!hasFootnote || !_mutatingFunctionIndexes.contains(indexKey)) {
-				throw new RuntimeException("Multiple entries for function name '" + functionName + "'");
-			}
-			_functionDataByIndex.remove(prevFM.getIndex());
-		}
-		prevFM = _functionDataByIndex.get(indexKey);
-		if(prevFM != null) {
-			if(!hasFootnote || !_mutatingFunctionIndexes.contains(indexKey)) {
-				throw new RuntimeException("Multiple entries for function index (" + functionIndex + ")");
-			}
-			_functionDataByName.remove(prevFM.getName());
-		}
-		if(hasFootnote) {
-			_mutatingFunctionIndexes.add(indexKey);
-		}
-		_functionDataByIndex.put(indexKey, fm);
-		_functionDataByName.put(functionName, fm);
-	}
-
-	public FunctionMetadataRegistry build() {
-
-		FunctionMetadata[] jumbledArray =  new FunctionMetadata[_functionDataByName.size()];
-		_functionDataByName.values().toArray(jumbledArray);
-		FunctionMetadata[] fdIndexArray = new FunctionMetadata[_maxFunctionIndex+1];
-		for (FunctionMetadata fd : jumbledArray) {
-			fdIndexArray[fd.getIndex()] = fd;
-		}
+    private int _maxFunctionIndex;
+    private final Map<String,FunctionMetadata> _functionDataByName;
+    private final Map<Integer,FunctionMetadata> _functionDataByIndex;
+    /** stores indexes of all functions with footnotes (i.e. whose definitions might change) */
+    private final Set<Integer> _mutatingFunctionIndexes;
+
+    public FunctionDataBuilder(int sizeEstimate) {
+        _maxFunctionIndex = -1;
+        _functionDataByName = new HashMap<>(sizeEstimate * 3 / 2);
+        _functionDataByIndex = new HashMap<>(sizeEstimate * 3 / 2);
+        _mutatingFunctionIndexes = new HashSet<>();
+    }
+
+    public void add(int functionIndex, String functionName, int minParams, int maxParams,
+            byte returnClassCode, byte[] parameterClassCodes, boolean hasFootnote) {
+        FunctionMetadata fm = new FunctionMetadata(functionIndex, functionName, minParams, maxParams,
+                returnClassCode, parameterClassCodes);
+
+        Integer indexKey = functionIndex;
+
+
+        if(functionIndex > _maxFunctionIndex) {
+            _maxFunctionIndex = functionIndex;
+        }
+        // allow function definitions to change only if both previous and the new items have footnotes
+        FunctionMetadata prevFM;
+        prevFM = _functionDataByName.get(functionName);
+        if(prevFM != null) {
+            if(!hasFootnote || !_mutatingFunctionIndexes.contains(indexKey)) {
+                throw new RuntimeException("Multiple entries for function name '" + functionName + "'");
+            }
+            _functionDataByIndex.remove(prevFM.getIndex());
+        }
+        prevFM = _functionDataByIndex.get(indexKey);
+        if(prevFM != null) {
+            if(!hasFootnote || !_mutatingFunctionIndexes.contains(indexKey)) {
+                throw new RuntimeException("Multiple entries for function index (" + functionIndex + ")");
+            }
+            _functionDataByName.remove(prevFM.getName());
+        }
+        if(hasFootnote) {
+            _mutatingFunctionIndexes.add(indexKey);
+        }
+        _functionDataByIndex.put(indexKey, fm);
+        _functionDataByName.put(functionName, fm);
+    }
+
+    public FunctionMetadataRegistry build() {
+
+        FunctionMetadata[] jumbledArray =  new FunctionMetadata[_functionDataByName.size()];
+        _functionDataByName.values().toArray(jumbledArray);
+        FunctionMetadata[] fdIndexArray = new FunctionMetadata[_maxFunctionIndex+1];
+        for (FunctionMetadata fd : jumbledArray) {
+            fdIndexArray[fd.getIndex()] = fd;
+        }
 
-		return new FunctionMetadataRegistry(fdIndexArray, _functionDataByName);
-	}
+        return new FunctionMetadataRegistry(fdIndexArray, _functionDataByName);
+    }
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/function/FunctionMetadata.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/function/FunctionMetadata.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/function/FunctionMetadata.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/function/FunctionMetadata.java Sat May 22 20:56:44 2021
@@ -6,7 +6,7 @@
    (the "License"); you may not use this file except in compliance with
    the License.  You may obtain a copy of the License at
 
-	   http://www.apache.org/licenses/LICENSE-2.0
+       http://www.apache.org/licenses/LICENSE-2.0
 
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
@@ -21,74 +21,74 @@ package org.apache.poi.ss.formula.functi
  * Holds information about Excel built-in functions.
  */
 public final class FunctionMetadata {
-	/**
-	 * maxParams=30 in functionMetadata.txt means the maximum number arguments supported
-	 * by the given version of Excel. Validation routines should take the actual limit (Excel 97 or 2007)
-	 * from the SpreadsheetVersion enum.
-	 * Perhaps a value like 'M' should be used instead of '30' in functionMetadata.txt
-	 * to make that file more version neutral.
-	 * @see org.apache.poi.ss.formula.FormulaParser#validateNumArgs(int, FunctionMetadata)
-	 */
-	@SuppressWarnings("JavadocReference")
-	private static final short FUNCTION_MAX_PARAMS = 30;
-
-	private final int _index;
-	private final String _name;
-	private final int _minParams;
-	private final int _maxParams;
-	private final byte _returnClassCode;
-	private final byte[] _parameterClassCodes;
-
-	/* package */ FunctionMetadata(int index, String name, int minParams, int maxParams,
-			byte returnClassCode, byte[] parameterClassCodes) {
-		_index = index;
-		_name = name;
-		_minParams = minParams;
-		_maxParams = maxParams;
-		_returnClassCode = returnClassCode;
-		_parameterClassCodes = (parameterClassCodes == null) ? null : parameterClassCodes.clone();
-	}
-
-	public int getIndex() {
-		return _index;
-	}
-
-	public String getName() {
-		return _name;
-	}
-
-	public int getMinParams() {
-		return _minParams;
-	}
-
-	public int getMaxParams() {
-		return _maxParams;
-	}
-
-	public boolean hasFixedArgsLength() {
-		return _minParams == _maxParams;
-	}
-
-	public byte getReturnClassCode() {
-		return _returnClassCode;
-	}
-
-	public byte[] getParameterClassCodes() {
-		return _parameterClassCodes.clone();
-	}
-
-	/**
-	 * Some varags functions (like VLOOKUP) have a specific limit to the number of arguments that
-	 * can be passed.  Other functions (like SUM) don't have such a limit.  For those functions,
-	 * the spreadsheet version determines the maximum number of arguments that can be passed.
-	 * @return <code>true</code> if this function can the maximum number of arguments allowable by
-	 * the {@link org.apache.poi.ss.SpreadsheetVersion}
-	 */
-	public boolean hasUnlimitedVarags() {
-		return FUNCTION_MAX_PARAMS == _maxParams;
-	}
-
-	public String toString() {
-		return getClass().getName() + " [" + _index + " " + _name + "]";
-	}
+    /**
+     * maxParams=30 in functionMetadata.txt means the maximum number arguments supported
+     * by the given version of Excel. Validation routines should take the actual limit (Excel 97 or 2007)
+     * from the SpreadsheetVersion enum.
+     * Perhaps a value like 'M' should be used instead of '30' in functionMetadata.txt
+     * to make that file more version neutral.
+     * @see org.apache.poi.ss.formula.FormulaParser#validateNumArgs(int, FunctionMetadata)
+     */
+    @SuppressWarnings("JavadocReference")
+    private static final short FUNCTION_MAX_PARAMS = 30;
+
+    private final int _index;
+    private final String _name;
+    private final int _minParams;
+    private final int _maxParams;
+    private final byte _returnClassCode;
+    private final byte[] _parameterClassCodes;
+
+    /* package */ FunctionMetadata(int index, String name, int minParams, int maxParams,
+            byte returnClassCode, byte[] parameterClassCodes) {
+        _index = index;
+        _name = name;
+        _minParams = minParams;
+        _maxParams = maxParams;
+        _returnClassCode = returnClassCode;
+        _parameterClassCodes = (parameterClassCodes == null) ? null : parameterClassCodes.clone();
+    }
+
+    public int getIndex() {
+        return _index;
+    }
+
+    public String getName() {
+        return _name;
+    }
+
+    public int getMinParams() {
+        return _minParams;
+    }
+
+    public int getMaxParams() {
+        return _maxParams;
+    }
+
+    public boolean hasFixedArgsLength() {
+        return _minParams == _maxParams;
+    }
+
+    public byte getReturnClassCode() {
+        return _returnClassCode;
+    }
+
+    public byte[] getParameterClassCodes() {
+        return _parameterClassCodes.clone();
+    }
+
+    /**
+     * Some varags functions (like VLOOKUP) have a specific limit to the number of arguments that
+     * can be passed.  Other functions (like SUM) don't have such a limit.  For those functions,
+     * the spreadsheet version determines the maximum number of arguments that can be passed.
+     * @return <code>true</code> if this function can the maximum number of arguments allowable by
+     * the {@link org.apache.poi.ss.SpreadsheetVersion}
+     */
+    public boolean hasUnlimitedVarags() {
+        return FUNCTION_MAX_PARAMS == _maxParams;
+    }
+
+    public String toString() {
+        return getClass().getName() + " [" + _index + " " + _name + "]";
+    }
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/function/FunctionMetadataReader.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/function/FunctionMetadataReader.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/function/FunctionMetadataReader.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/function/FunctionMetadataReader.java Sat May 22 20:56:44 2021
@@ -6,7 +6,7 @@
    (the "License"); you may not use this file except in compliance with
    the License.  You may obtain a copy of the License at
 
-	   http://www.apache.org/licenses/LICENSE-2.0
+       http://www.apache.org/licenses/LICENSE-2.0
 
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
@@ -35,162 +35,162 @@ import org.apache.poi.util.IOUtils;
  */
 final class FunctionMetadataReader {
 
-	//arbitrarily selected; may need to increase
-	private static final int MAX_RECORD_LENGTH = 100_000;
+    //arbitrarily selected; may need to increase
+    private static final int MAX_RECORD_LENGTH = 100_000;
 
-	private static final String METADATA_FILE_NAME = "functionMetadata.txt";
-	private static final String METADATA_FILE_NAME_CETAB = "functionMetadataCetab.txt";
+    private static final String METADATA_FILE_NAME = "functionMetadata.txt";
+    private static final String METADATA_FILE_NAME_CETAB = "functionMetadataCetab.txt";
 
-	/** plain ASCII text metadata file uses three dots for ellipsis */
-	private static final String ELLIPSIS = "...";
+    /** plain ASCII text metadata file uses three dots for ellipsis */
+    private static final String ELLIPSIS = "...";
 
-	private static final Pattern TAB_DELIM_PATTERN = Pattern.compile("\t");
-	private static final Pattern SPACE_DELIM_PATTERN = Pattern.compile(" ");
-	private static final byte[] EMPTY_BYTE_ARRAY = { };
-
-	private static final String[] DIGIT_ENDING_FUNCTION_NAMES = {
-		// Digits at the end of a function might be due to a left-over footnote marker.
-		// except in these cases
-		"LOG10", "ATAN2", "DAYS360", "SUMXMY2", "SUMX2MY2", "SUMX2PY2", "A1.R1C1",
-	};
-	private static final Set<String> DIGIT_ENDING_FUNCTION_NAMES_SET = new HashSet<>(Arrays.asList(DIGIT_ENDING_FUNCTION_NAMES));
-
-	public static FunctionMetadataRegistry createRegistry() {
-		FunctionDataBuilder fdb = new FunctionDataBuilder(800);
-		readResourceFile(fdb, METADATA_FILE_NAME);
-		return fdb.build();
-	}
-
-	public static FunctionMetadataRegistry createRegistryCetab() {
-		FunctionDataBuilder fdb = new FunctionDataBuilder(800);
-		readResourceFile(fdb, METADATA_FILE_NAME_CETAB);
-		return fdb.build();
-	}
-
-	private static void readResourceFile(FunctionDataBuilder fdb, String resourceFile) {
-		try (InputStream is = FunctionMetadataReader.class.getResourceAsStream(resourceFile)) {
-			if (is == null) {
-				throw new RuntimeException("resource '" + resourceFile + "' not found");
-			}
-
-			try(BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
-
-				while (true) {
-					String line = br.readLine();
-					if (line == null) {
-						break;
-					}
-					if (line.length() < 1 || line.charAt(0) == '#') {
-						continue;
-					}
-					String trimLine = line.trim();
-					if (trimLine.length() < 1) {
-						continue;
-					}
-					processLine(fdb, line);
-				}
-			}
-		} catch (IOException e) {
-			throw new RuntimeException(e);
-		}
-	}
-
-	private static void processLine(FunctionDataBuilder fdb, String line) {
-
-		String[] parts = TAB_DELIM_PATTERN.split(line, -2);
-		if(parts.length != 8) {
-			throw new RuntimeException("Bad line format '" + line + "' - expected 8 data fields delimited by tab, " +
-					"but had " + parts.length + ": " + Arrays.toString(parts));
-		}
-		int functionIndex = parseInt(parts[0]);
-		String functionName = parts[1];
-		int minParams = parseInt(parts[2]);
-		int maxParams = parseInt(parts[3]);
-		byte returnClassCode = parseReturnTypeCode(parts[4]);
-		byte[] parameterClassCodes = parseOperandTypeCodes(parts[5]);
-		// 6 isVolatile
-		boolean hasNote = parts[7].length() > 0;
-
-		validateFunctionName(functionName);
-		// TODO - make POI use isVolatile
-		fdb.add(functionIndex, functionName, minParams, maxParams,
-				returnClassCode, parameterClassCodes, hasNote);
-	}
-
-
-	private static byte parseReturnTypeCode(String code) {
-		if(code.length() == 0) {
-			return Ptg.CLASS_REF; // happens for GETPIVOTDATA
-		}
-		return parseOperandTypeCode(code);
-	}
-
-	private static byte[] parseOperandTypeCodes(String codes) {
-		if(codes.length() < 1) {
-			return EMPTY_BYTE_ARRAY; // happens for GETPIVOTDATA
-		}
-		if(isDash(codes)) {
-			// '-' means empty:
-			return EMPTY_BYTE_ARRAY;
-		}
-		String[] array = SPACE_DELIM_PATTERN.split(codes);
-		int nItems = array.length;
-		if(ELLIPSIS.equals(array[nItems-1])) {
-			// final ellipsis is optional, and ignored
-			// (all unspecified params are assumed to be the same as the last)
-			nItems --;
-		}
-		byte[] result = IOUtils.safelyAllocate(nItems, MAX_RECORD_LENGTH);
-		for (int i = 0; i < nItems; i++) {
-			result[i] = parseOperandTypeCode(array[i]);
-		}
-		return result;
-	}
-
-	private static boolean isDash(String codes) {
-		return codes.length() == 1 && codes.charAt(0) == '-';
-	}
-
-	private static byte parseOperandTypeCode(String code) {
-		if(code.length() != 1) {
-			throw new RuntimeException("Bad operand type code format '" + code  + "' expected single char");
-		}
-		switch(code.charAt(0)) {
-			case 'V': return Ptg.CLASS_VALUE;
-			case 'R': return Ptg.CLASS_REF;
-			case 'A': return Ptg.CLASS_ARRAY;
-		}
-		throw new IllegalArgumentException("Unexpected operand type code '" + code + "' (" + (int)code.charAt(0) + ")");
-	}
-
-	/**
-	 * Makes sure that footnote digits from the original OOO document have not been accidentally
-	 * left behind
-	 */
-	private static void validateFunctionName(String functionName) {
-		int len = functionName.length();
-		int ix = len - 1;
-		if (!Character.isDigit(functionName.charAt(ix))) {
-			return;
-		}
-		while(ix >= 0) {
-			if (!Character.isDigit(functionName.charAt(ix))) {
-				break;
-			}
-			ix--;
-		}
-		if(DIGIT_ENDING_FUNCTION_NAMES_SET.contains(functionName)) {
-			return;
-		}
-		throw new RuntimeException("Invalid function name '" + functionName
-				+ "' (is footnote number incorrectly appended)");
-	}
-
-	private static int parseInt(String valStr) {
-		try {
-			return Integer.parseInt(valStr);
-		} catch (NumberFormatException e) {
-			throw new RuntimeException("Value '" + valStr + "' could not be parsed as an integer");
-		}
-	}
+    private static final Pattern TAB_DELIM_PATTERN = Pattern.compile("\t");
+    private static final Pattern SPACE_DELIM_PATTERN = Pattern.compile(" ");
+    private static final byte[] EMPTY_BYTE_ARRAY = { };
+
+    private static final String[] DIGIT_ENDING_FUNCTION_NAMES = {
+        // Digits at the end of a function might be due to a left-over footnote marker.
+        // except in these cases
+        "LOG10", "ATAN2", "DAYS360", "SUMXMY2", "SUMX2MY2", "SUMX2PY2", "A1.R1C1",
+    };
+    private static final Set<String> DIGIT_ENDING_FUNCTION_NAMES_SET = new HashSet<>(Arrays.asList(DIGIT_ENDING_FUNCTION_NAMES));
+
+    public static FunctionMetadataRegistry createRegistry() {
+        FunctionDataBuilder fdb = new FunctionDataBuilder(800);
+        readResourceFile(fdb, METADATA_FILE_NAME);
+        return fdb.build();
+    }
+
+    public static FunctionMetadataRegistry createRegistryCetab() {
+        FunctionDataBuilder fdb = new FunctionDataBuilder(800);
+        readResourceFile(fdb, METADATA_FILE_NAME_CETAB);
+        return fdb.build();
+    }
+
+    private static void readResourceFile(FunctionDataBuilder fdb, String resourceFile) {
+        try (InputStream is = FunctionMetadataReader.class.getResourceAsStream(resourceFile)) {
+            if (is == null) {
+                throw new RuntimeException("resource '" + resourceFile + "' not found");
+            }
+
+            try(BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
+
+                while (true) {
+                    String line = br.readLine();
+                    if (line == null) {
+                        break;
+                    }
+                    if (line.length() < 1 || line.charAt(0) == '#') {
+                        continue;
+                    }
+                    String trimLine = line.trim();
+                    if (trimLine.length() < 1) {
+                        continue;
+                    }
+                    processLine(fdb, line);
+                }
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static void processLine(FunctionDataBuilder fdb, String line) {
+
+        String[] parts = TAB_DELIM_PATTERN.split(line, -2);
+        if(parts.length != 8) {
+            throw new RuntimeException("Bad line format '" + line + "' - expected 8 data fields delimited by tab, " +
+                    "but had " + parts.length + ": " + Arrays.toString(parts));
+        }
+        int functionIndex = parseInt(parts[0]);
+        String functionName = parts[1];
+        int minParams = parseInt(parts[2]);
+        int maxParams = parseInt(parts[3]);
+        byte returnClassCode = parseReturnTypeCode(parts[4]);
+        byte[] parameterClassCodes = parseOperandTypeCodes(parts[5]);
+        // 6 isVolatile
+        boolean hasNote = parts[7].length() > 0;
+
+        validateFunctionName(functionName);
+        // TODO - make POI use isVolatile
+        fdb.add(functionIndex, functionName, minParams, maxParams,
+                returnClassCode, parameterClassCodes, hasNote);
+    }
+
+
+    private static byte parseReturnTypeCode(String code) {
+        if(code.length() == 0) {
+            return Ptg.CLASS_REF; // happens for GETPIVOTDATA
+        }
+        return parseOperandTypeCode(code);
+    }
+
+    private static byte[] parseOperandTypeCodes(String codes) {
+        if(codes.length() < 1) {
+            return EMPTY_BYTE_ARRAY; // happens for GETPIVOTDATA
+        }
+        if(isDash(codes)) {
+            // '-' means empty:
+            return EMPTY_BYTE_ARRAY;
+        }
+        String[] array = SPACE_DELIM_PATTERN.split(codes);
+        int nItems = array.length;
+        if(ELLIPSIS.equals(array[nItems-1])) {
+            // final ellipsis is optional, and ignored
+            // (all unspecified params are assumed to be the same as the last)
+            nItems --;
+        }
+        byte[] result = IOUtils.safelyAllocate(nItems, MAX_RECORD_LENGTH);
+        for (int i = 0; i < nItems; i++) {
+            result[i] = parseOperandTypeCode(array[i]);
+        }
+        return result;
+    }
+
+    private static boolean isDash(String codes) {
+        return codes.length() == 1 && codes.charAt(0) == '-';
+    }
+
+    private static byte parseOperandTypeCode(String code) {
+        if(code.length() != 1) {
+            throw new RuntimeException("Bad operand type code format '" + code  + "' expected single char");
+        }
+        switch(code.charAt(0)) {
+            case 'V': return Ptg.CLASS_VALUE;
+            case 'R': return Ptg.CLASS_REF;
+            case 'A': return Ptg.CLASS_ARRAY;
+        }
+        throw new IllegalArgumentException("Unexpected operand type code '" + code + "' (" + (int)code.charAt(0) + ")");
+    }
+
+    /**
+     * Makes sure that footnote digits from the original OOO document have not been accidentally
+     * left behind
+     */
+    private static void validateFunctionName(String functionName) {
+        int len = functionName.length();
+        int ix = len - 1;
+        if (!Character.isDigit(functionName.charAt(ix))) {
+            return;
+        }
+        while(ix >= 0) {
+            if (!Character.isDigit(functionName.charAt(ix))) {
+                break;
+            }
+            ix--;
+        }
+        if(DIGIT_ENDING_FUNCTION_NAMES_SET.contains(functionName)) {
+            return;
+        }
+        throw new RuntimeException("Invalid function name '" + functionName
+                + "' (is footnote number incorrectly appended)");
+    }
+
+    private static int parseInt(String valStr) {
+        try {
+            return Integer.parseInt(valStr);
+        } catch (NumberFormatException e) {
+            throw new RuntimeException("Value '" + valStr + "' could not be parsed as an integer");
+        }
+    }
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/function/FunctionMetadataRegistry.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/function/FunctionMetadataRegistry.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/function/FunctionMetadataRegistry.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/function/FunctionMetadataRegistry.java Sat May 22 20:56:44 2021
@@ -24,86 +24,86 @@ import java.util.Set;
  * Allows clients to get {@link FunctionMetadata} instances for any built-in function of Excel.
  */
 public final class FunctionMetadataRegistry {
-	/**
-	 * The name of the IF function (i.e. "IF").  Extracted as a constant for clarity.
-	 */
-	public static final String FUNCTION_NAME_IF = "IF";
-
-	public static final int FUNCTION_INDEX_IF = 1;
-	public static final short FUNCTION_INDEX_SUM = 4;
-	public static final int FUNCTION_INDEX_CHOOSE = 100;
-	public static final short FUNCTION_INDEX_INDIRECT = 148;
-	public static final short FUNCTION_INDEX_EXTERNAL = 255;
-
-	private static FunctionMetadataRegistry _instance;
-	private static FunctionMetadataRegistry _instanceCetab;
-
-	private final FunctionMetadata[] _functionDataByIndex;
-	private final Map<String, FunctionMetadata> _functionDataByName;
-
-	private static FunctionMetadataRegistry getInstance() {
-		if (_instance == null) {
-			_instance = FunctionMetadataReader.createRegistry();
-		}
-		return _instance;
-	}
-
-	private static FunctionMetadataRegistry getInstanceCetab() {
-		if (_instanceCetab == null) {
-			_instanceCetab = FunctionMetadataReader.createRegistryCetab();
-		}
-		return _instanceCetab;
-	}
-
-	/* package */ FunctionMetadataRegistry(FunctionMetadata[] functionDataByIndex, Map<String, FunctionMetadata> functionDataByName) {
-		_functionDataByIndex = (functionDataByIndex == null) ? null : functionDataByIndex.clone();
-		_functionDataByName = functionDataByName;
-	}
-
-	/* package */ Set<String> getAllFunctionNames() {
-		return _functionDataByName.keySet();
-	}
-
-
-	public static FunctionMetadata getFunctionByIndex(int index) {
-		return getInstance().getFunctionByIndexInternal(index);
-	}
-
-	public static FunctionMetadata getCetabFunctionByIndex(int index) {
-		return getInstanceCetab().getFunctionByIndexInternal(index);
-	}
-
-	private FunctionMetadata getFunctionByIndexInternal(int index) {
-		return _functionDataByIndex[index];
-	}
-	/**
-	 * Resolves a built-in function index.
-	 * @param name uppercase function name
-	 * @return a negative value if the function name is not found.
-	 * This typically occurs for external functions.
-	 */
-	public static short lookupIndexByName(String name) {
-		FunctionMetadata fd = getInstance().getFunctionByNameInternal(name);
-		if (fd == null) {
-			// also try the cetab functions
-			fd = getInstanceCetab().getFunctionByNameInternal(name);
-			if (fd == null) {
-				return -1;
-			}
-		}
-		return (short) fd.getIndex();
-	}
-
-	private FunctionMetadata getFunctionByNameInternal(String name) {
-		return _functionDataByName.get(name);
-	}
-
-	public static FunctionMetadata getFunctionByName(String name) {
-		FunctionMetadata fm = getInstance().getFunctionByNameInternal(name);
-		if(fm == null) {
-			return getInstanceCetab().getFunctionByNameInternal(name);
-		}
+    /**
+     * The name of the IF function (i.e. "IF").  Extracted as a constant for clarity.
+     */
+    public static final String FUNCTION_NAME_IF = "IF";
+
+    public static final int FUNCTION_INDEX_IF = 1;
+    public static final short FUNCTION_INDEX_SUM = 4;
+    public static final int FUNCTION_INDEX_CHOOSE = 100;
+    public static final short FUNCTION_INDEX_INDIRECT = 148;
+    public static final short FUNCTION_INDEX_EXTERNAL = 255;
+
+    private static FunctionMetadataRegistry _instance;
+    private static FunctionMetadataRegistry _instanceCetab;
+
+    private final FunctionMetadata[] _functionDataByIndex;
+    private final Map<String, FunctionMetadata> _functionDataByName;
+
+    private static FunctionMetadataRegistry getInstance() {
+        if (_instance == null) {
+            _instance = FunctionMetadataReader.createRegistry();
+        }
+        return _instance;
+    }
+
+    private static FunctionMetadataRegistry getInstanceCetab() {
+        if (_instanceCetab == null) {
+            _instanceCetab = FunctionMetadataReader.createRegistryCetab();
+        }
+        return _instanceCetab;
+    }
+
+    /* package */ FunctionMetadataRegistry(FunctionMetadata[] functionDataByIndex, Map<String, FunctionMetadata> functionDataByName) {
+        _functionDataByIndex = (functionDataByIndex == null) ? null : functionDataByIndex.clone();
+        _functionDataByName = functionDataByName;
+    }
+
+    /* package */ Set<String> getAllFunctionNames() {
+        return _functionDataByName.keySet();
+    }
+
+
+    public static FunctionMetadata getFunctionByIndex(int index) {
+        return getInstance().getFunctionByIndexInternal(index);
+    }
+
+    public static FunctionMetadata getCetabFunctionByIndex(int index) {
+        return getInstanceCetab().getFunctionByIndexInternal(index);
+    }
+
+    private FunctionMetadata getFunctionByIndexInternal(int index) {
+        return _functionDataByIndex[index];
+    }
+    /**
+     * Resolves a built-in function index.
+     * @param name uppercase function name
+     * @return a negative value if the function name is not found.
+     * This typically occurs for external functions.
+     */
+    public static short lookupIndexByName(String name) {
+        FunctionMetadata fd = getInstance().getFunctionByNameInternal(name);
+        if (fd == null) {
+            // also try the cetab functions
+            fd = getInstanceCetab().getFunctionByNameInternal(name);
+            if (fd == null) {
+                return -1;
+            }
+        }
+        return (short) fd.getIndex();
+    }
+
+    private FunctionMetadata getFunctionByNameInternal(String name) {
+        return _functionDataByName.get(name);
+    }
+
+    public static FunctionMetadata getFunctionByName(String name) {
+        FunctionMetadata fm = getInstance().getFunctionByNameInternal(name);
+        if(fm == null) {
+            return getInstanceCetab().getFunctionByNameInternal(name);
+        }
 
-		return fm;
-	}
+        return fm;
+    }
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Address.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Address.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Address.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/Address.java Sat May 22 20:56:44 2021
@@ -44,7 +44,7 @@ public class Address implements Function
             if (args.length > 2  &&  args[2] != MissingArgEval.instance) {
                 refType = (int)NumericFunction.singleOperandEvaluate(args[2], srcRowIndex, srcColumnIndex);
             } else {
-                refType = REF_ABSOLUTE;		// this is also the default if parameter is not given
+                refType = REF_ABSOLUTE;     // this is also the default if parameter is not given
             }
             switch (refType){
                 case REF_ABSOLUTE:

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/BooleanFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/BooleanFunction.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/BooleanFunction.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/BooleanFunction.java Sat May 22 20:56:44 2021
@@ -37,45 +37,45 @@ import org.apache.poi.ss.formula.eval.Va
  */
 public abstract class BooleanFunction implements Function,ArrayFunction {
 
-	public final ValueEval evaluate(ValueEval[] args, int srcRow, int srcCol) {
-		if (args.length < 1) {
-			return ErrorEval.VALUE_INVALID;
-		}
-		boolean boolResult;
-		try {
-			boolResult = calculate(args);
-		} catch (EvaluationException e) {
-			return e.getErrorEval();
-		}
-		return BoolEval.valueOf(boolResult);
-	}
-
-	private boolean calculate(ValueEval[] args) throws EvaluationException {
-
-		boolean result = getInitialResultValue();
-		boolean atLeastOneNonBlank = false;
-
-		/*
-		 * Note: no short-circuit boolean loop exit because any ErrorEvals will override the result
-		 */
-		for (final ValueEval arg : args) {
+    public final ValueEval evaluate(ValueEval[] args, int srcRow, int srcCol) {
+        if (args.length < 1) {
+            return ErrorEval.VALUE_INVALID;
+        }
+        boolean boolResult;
+        try {
+            boolResult = calculate(args);
+        } catch (EvaluationException e) {
+            return e.getErrorEval();
+        }
+        return BoolEval.valueOf(boolResult);
+    }
+
+    private boolean calculate(ValueEval[] args) throws EvaluationException {
+
+        boolean result = getInitialResultValue();
+        boolean atLeastOneNonBlank = false;
+
+        /*
+         * Note: no short-circuit boolean loop exit because any ErrorEvals will override the result
+         */
+        for (final ValueEval arg : args) {
             Boolean tempVe;
-			if (arg instanceof TwoDEval) {
-				TwoDEval ae = (TwoDEval) arg;
-				int height = ae.getHeight();
-				int width = ae.getWidth();
-				for (int rrIx=0; rrIx<height; rrIx++) {
-					for (int rcIx=0; rcIx<width; rcIx++) {
-						ValueEval ve = ae.getValue(rrIx, rcIx);
-						tempVe = OperandResolver.coerceValueToBoolean(ve, true);
-						if (tempVe != null) {
-							result = partialEvaluate(result, tempVe);
-							atLeastOneNonBlank = true;
-						}
-					}
-				}
-				continue;
-			}
+            if (arg instanceof TwoDEval) {
+                TwoDEval ae = (TwoDEval) arg;
+                int height = ae.getHeight();
+                int width = ae.getWidth();
+                for (int rrIx=0; rrIx<height; rrIx++) {
+                    for (int rcIx=0; rcIx<width; rcIx++) {
+                        ValueEval ve = ae.getValue(rrIx, rcIx);
+                        tempVe = OperandResolver.coerceValueToBoolean(ve, true);
+                        if (tempVe != null) {
+                            result = partialEvaluate(result, tempVe);
+                            atLeastOneNonBlank = true;
+                        }
+                    }
+                }
+                continue;
+            }
             if (arg instanceof RefEval) {
                 RefEval re = (RefEval) arg;
                 final int firstSheetIndex = re.getFirstSheetIndex();
@@ -91,84 +91,84 @@ public abstract class BooleanFunction im
                 continue;
             }
 
-			if (arg == MissingArgEval.instance) {
-				tempVe = false;		// missing parameters are treated as FALSE
-			} else {
-				tempVe = OperandResolver.coerceValueToBoolean(arg, false);
-			}
-
-			if (tempVe != null) {
-				result = partialEvaluate(result, tempVe);
-				atLeastOneNonBlank = true;
-			}
-		}
-
-		if (!atLeastOneNonBlank) {
-			throw new EvaluationException(ErrorEval.VALUE_INVALID);
-		}
-		return result;
-	}
-
-
-	protected abstract boolean getInitialResultValue();
-	protected abstract boolean partialEvaluate(boolean cumulativeResult, boolean currentValue);
-
-
-	public static final Function AND = new BooleanFunction() {
-		protected boolean getInitialResultValue() {
-			return true;
-		}
-		protected boolean partialEvaluate(boolean cumulativeResult, boolean currentValue) {
-			return cumulativeResult && currentValue;
-		}
-	};
-	public static final Function OR = new BooleanFunction() {
-		protected boolean getInitialResultValue() {
-			return false;
-		}
-		protected boolean partialEvaluate(boolean cumulativeResult, boolean currentValue) {
-			return cumulativeResult || currentValue;
-		}
-	};
-
-	public static final Function FALSE = BooleanFunction::evaluateFalse;
-
-	public static final Function TRUE = BooleanFunction::evaluateTrue;
-
-	public static final Function NOT = BooleanFunction::evaluateNot;
-
-	@Override
-	public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
-		if (args.length != 1) {
-			return ErrorEval.VALUE_INVALID;
-		}
-		return evaluateOneArrayArg(args[0], srcRowIndex, srcColumnIndex,
-				vA -> evaluate(new ValueEval[]{vA}, srcRowIndex, srcColumnIndex));
-	}
-
-	private static ValueEval evaluateFalse(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
-		return args.length != 0 ? ErrorEval.VALUE_INVALID : BoolEval.FALSE;
-	}
-
-	private static ValueEval evaluateTrue(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
-		return args.length != 0 ? ErrorEval.VALUE_INVALID : BoolEval.TRUE;
-	}
-
-	private static ValueEval evaluateNot(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
-		if (args.length != 1) {
-			return ErrorEval.VALUE_INVALID;
-		}
-		java.util.function.Function<ValueEval, ValueEval> notInner = (va) -> {
-			try {
-				ValueEval ve = OperandResolver.getSingleValue(va, srcRowIndex, srcColumnIndex);
-				Boolean b = OperandResolver.coerceValueToBoolean(ve, false);
-				boolean boolArgVal = b != null && b;
-				return BoolEval.valueOf(!boolArgVal);
-			} catch (EvaluationException e) {
-				return e.getErrorEval();
-			}
-		};
+            if (arg == MissingArgEval.instance) {
+                tempVe = false;     // missing parameters are treated as FALSE
+            } else {
+                tempVe = OperandResolver.coerceValueToBoolean(arg, false);
+            }
+
+            if (tempVe != null) {
+                result = partialEvaluate(result, tempVe);
+                atLeastOneNonBlank = true;
+            }
+        }
+
+        if (!atLeastOneNonBlank) {
+            throw new EvaluationException(ErrorEval.VALUE_INVALID);
+        }
+        return result;
+    }
+
+
+    protected abstract boolean getInitialResultValue();
+    protected abstract boolean partialEvaluate(boolean cumulativeResult, boolean currentValue);
+
+
+    public static final Function AND = new BooleanFunction() {
+        protected boolean getInitialResultValue() {
+            return true;
+        }
+        protected boolean partialEvaluate(boolean cumulativeResult, boolean currentValue) {
+            return cumulativeResult && currentValue;
+        }
+    };
+    public static final Function OR = new BooleanFunction() {
+        protected boolean getInitialResultValue() {
+            return false;
+        }
+        protected boolean partialEvaluate(boolean cumulativeResult, boolean currentValue) {
+            return cumulativeResult || currentValue;
+        }
+    };
+
+    public static final Function FALSE = BooleanFunction::evaluateFalse;
+
+    public static final Function TRUE = BooleanFunction::evaluateTrue;
+
+    public static final Function NOT = BooleanFunction::evaluateNot;
+
+    @Override
+    public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+        if (args.length != 1) {
+            return ErrorEval.VALUE_INVALID;
+        }
+        return evaluateOneArrayArg(args[0], srcRowIndex, srcColumnIndex,
+                vA -> evaluate(new ValueEval[]{vA}, srcRowIndex, srcColumnIndex));
+    }
+
+    private static ValueEval evaluateFalse(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+        return args.length != 0 ? ErrorEval.VALUE_INVALID : BoolEval.FALSE;
+    }
+
+    private static ValueEval evaluateTrue(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+        return args.length != 0 ? ErrorEval.VALUE_INVALID : BoolEval.TRUE;
+    }
+
+    private static ValueEval evaluateNot(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+        if (args.length != 1) {
+            return ErrorEval.VALUE_INVALID;
+        }
+        java.util.function.Function<ValueEval, ValueEval> notInner = (va) -> {
+            try {
+                ValueEval ve = OperandResolver.getSingleValue(va, srcRowIndex, srcColumnIndex);
+                Boolean b = OperandResolver.coerceValueToBoolean(ve, false);
+                boolean boolArgVal = b != null && b;
+                return BoolEval.valueOf(!boolArgVal);
+            } catch (EvaluationException e) {
+                return e.getErrorEval();
+            }
+        };
 
-		return ArrayFunction._evaluateOneArrayArg(args[0], srcRowIndex, srcColumnIndex, notInner);
-	}
+        return ArrayFunction._evaluateOneArrayArg(args[0], srcRowIndex, srcColumnIndex, notInner);
+    }
 }
\ No newline at end of file

Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/CalendarFieldFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/CalendarFieldFunction.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/CalendarFieldFunction.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/formula/functions/CalendarFieldFunction.java Sat May 22 20:56:44 2021
@@ -32,56 +32,56 @@ import org.apache.poi.ss.usermodel.DateU
  *  Time - HOUR, MINUTE and SECOND
  */
 public final class CalendarFieldFunction extends Fixed1ArgFunction {
-	public static final Function YEAR = new CalendarFieldFunction(Calendar.YEAR);
-	public static final Function MONTH = new CalendarFieldFunction(Calendar.MONTH);
-	public static final Function DAY = new CalendarFieldFunction(Calendar.DAY_OF_MONTH);
-	public static final Function HOUR = new CalendarFieldFunction(Calendar.HOUR_OF_DAY);
+    public static final Function YEAR = new CalendarFieldFunction(Calendar.YEAR);
+    public static final Function MONTH = new CalendarFieldFunction(Calendar.MONTH);
+    public static final Function DAY = new CalendarFieldFunction(Calendar.DAY_OF_MONTH);
+    public static final Function HOUR = new CalendarFieldFunction(Calendar.HOUR_OF_DAY);
     public static final Function MINUTE = new CalendarFieldFunction(Calendar.MINUTE);
     public static final Function SECOND = new CalendarFieldFunction(Calendar.SECOND);
 
-	private final int _dateFieldId;
+    private final int _dateFieldId;
 
-	private CalendarFieldFunction(int dateFieldId) {
-		_dateFieldId = dateFieldId;
-	}
-
-	public final ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
-		double val;
-		try {
-			ValueEval ve = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
-			val = OperandResolver.coerceValueToDouble(ve);
-		} catch (EvaluationException e) {
-			return e.getErrorEval();
-		}
-		if (val < 0) {
-			return ErrorEval.NUM_ERROR;
-		}
-		return new NumberEval(getCalField(val));
-	}
-
-	private int getCalField(double serialDate) {
-	   // For some reason, a date of 0 in Excel gets shown
-	   //  as the non existant 1900-01-00
-		if (((int)serialDate) == 0) {
-			switch (_dateFieldId) {
-				case Calendar.YEAR: return 1900;
-				case Calendar.MONTH: return 1;
-				case Calendar.DAY_OF_MONTH: return 0;
-			}
-			// They want time, that's normal
-		}
-
-		// TODO Figure out if we're in 1900 or 1904
-		// EXCEL functions round up nearly a half second (probably to prevent floating point
-		// rounding issues); use UTC here to prevent daylight saving issues for HOUR
-		Calendar c = DateUtil.getJavaCalendarUTC(serialDate + 0.4995 / DateUtil.SECONDS_PER_DAY, false);
-		int result = c.get(_dateFieldId);
-
-		// Month is a special case due to C semantics
-		if (_dateFieldId == Calendar.MONTH) {
-			result++;
-		}
+    private CalendarFieldFunction(int dateFieldId) {
+        _dateFieldId = dateFieldId;
+    }
+
+    public final ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
+        double val;
+        try {
+            ValueEval ve = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
+            val = OperandResolver.coerceValueToDouble(ve);
+        } catch (EvaluationException e) {
+            return e.getErrorEval();
+        }
+        if (val < 0) {
+            return ErrorEval.NUM_ERROR;
+        }
+        return new NumberEval(getCalField(val));
+    }
+
+    private int getCalField(double serialDate) {
+       // For some reason, a date of 0 in Excel gets shown
+       //  as the non existant 1900-01-00
+        if (((int)serialDate) == 0) {
+            switch (_dateFieldId) {
+                case Calendar.YEAR: return 1900;
+                case Calendar.MONTH: return 1;
+                case Calendar.DAY_OF_MONTH: return 0;
+            }
+            // They want time, that's normal
+        }
+
+        // TODO Figure out if we're in 1900 or 1904
+        // EXCEL functions round up nearly a half second (probably to prevent floating point
+        // rounding issues); use UTC here to prevent daylight saving issues for HOUR
+        Calendar c = DateUtil.getJavaCalendarUTC(serialDate + 0.4995 / DateUtil.SECONDS_PER_DAY, false);
+        int result = c.get(_dateFieldId);
+
+        // Month is a special case due to C semantics
+        if (_dateFieldId == Calendar.MONTH) {
+            result++;
+        }
 
-		return result;
-	}
+        return result;
+    }
 }



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