refactor LookupUtils

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1895568 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
PJ Fanning 2021-12-04 08:53:29 +00:00
parent 7e00f3594a
commit 7314afd6e5
1 changed files with 23 additions and 8 deletions

View File

@ -625,8 +625,10 @@ public final class LookupUtils {
public static int xlookupIndexOfValue(ValueEval lookupValue, ValueVector vector, MatchMode matchMode, SearchMode searchMode) throws EvaluationException { public static int xlookupIndexOfValue(ValueEval lookupValue, ValueVector vector, MatchMode matchMode, SearchMode searchMode) throws EvaluationException {
LookupValueComparer lookupComparer = createTolerantLookupComparer(lookupValue, matchMode != MatchMode.WildcardMatch, true); LookupValueComparer lookupComparer = createTolerantLookupComparer(lookupValue, matchMode != MatchMode.WildcardMatch, true);
int result; int result;
if (searchMode == SearchMode.BinarySearchForward || searchMode == SearchMode.BinarySearchBackward) { if (searchMode == SearchMode.BinarySearchForward) {
result = binarySearchIndexOfValue(lookupComparer, vector, matchMode); result = binarySearchIndexOfValue(lookupComparer, vector, matchMode, false);
} else if (searchMode == SearchMode.BinarySearchBackward) {
result = binarySearchIndexOfValue(lookupComparer, vector, matchMode, true);
} else if (searchMode == SearchMode.IterateBackward) { } else if (searchMode == SearchMode.IterateBackward) {
result = lookupLastIndexOfValue(lookupComparer, vector, matchMode); result = lookupLastIndexOfValue(lookupComparer, vector, matchMode);
} else { } else {
@ -711,7 +713,7 @@ public final class LookupUtils {
} }
private static int binarySearchIndexOfValue(LookupValueComparer lookupComparer, ValueVector vector, private static int binarySearchIndexOfValue(LookupValueComparer lookupComparer, ValueVector vector,
MatchMode matchMode) { MatchMode matchMode, boolean reverse) {
int bestMatchIdx = -1; int bestMatchIdx = -1;
ValueEval bestMatchEval = null; ValueEval bestMatchEval = null;
HashSet<Integer> alreadySearched = new HashSet<>(); HashSet<Integer> alreadySearched = new HashSet<>();
@ -758,7 +760,9 @@ public final class LookupUtils {
break; break;
} }
if (result.isTypeMismatch()) { if (result.isTypeMismatch()) {
handleMidValueTypeMismatch(lookupComparer, vector, bsi, i); handleMidValueTypeMismatch(lookupComparer, vector, bsi, i, reverse);
} else if (reverse) {
bsi.narrowSearch(i, result.isGreaterThan());
} else { } else {
bsi.narrowSearch(i, result.isLessThan()); bsi.narrowSearch(i, result.isLessThan());
} }
@ -820,7 +824,7 @@ public final class LookupUtils {
} }
CompareResult cr = lookupComparer.compareTo(vector.getItem(midIx)); CompareResult cr = lookupComparer.compareTo(vector.getItem(midIx));
if(cr.isTypeMismatch()) { if(cr.isTypeMismatch()) {
int newMidIx = handleMidValueTypeMismatch(lookupComparer, vector, bsi, midIx); int newMidIx = handleMidValueTypeMismatch(lookupComparer, vector, bsi, midIx, false);
if(newMidIx < 0) { if(newMidIx < 0) {
continue; continue;
} }
@ -837,11 +841,12 @@ public final class LookupUtils {
* Excel seems to handle mismatched types initially by just stepping 'mid' ix forward to the * Excel seems to handle mismatched types initially by just stepping 'mid' ix forward to the
* first compatible value. * first compatible value.
* @param midIx 'mid' index (value which has the wrong type) * @param midIx 'mid' index (value which has the wrong type)
* @param reverse the data is sorted in reverse order
* @return usually -1, signifying that the BinarySearchIndex has been narrowed to the new mid * @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 * index. Zero or greater signifies that an exact match for the lookup value was found
*/ */
private static int handleMidValueTypeMismatch(LookupValueComparer lookupComparer, ValueVector vector, private static int handleMidValueTypeMismatch(LookupValueComparer lookupComparer, ValueVector vector,
BinarySearchIndexes bsi, int midIx) { BinarySearchIndexes bsi, int midIx, boolean reverse) {
int newMid = midIx; int newMid = midIx;
int highIx = bsi.getHighIx(); int highIx = bsi.getHighIx();
@ -854,7 +859,13 @@ public final class LookupUtils {
return -1; return -1;
} }
CompareResult cr = lookupComparer.compareTo(vector.getItem(newMid)); CompareResult cr = lookupComparer.compareTo(vector.getItem(newMid));
if(cr.isLessThan() && newMid == highIx-1) { if(cr.isLessThan() && !reverse && 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.
} else if(cr.isGreaterThan() && reverse && newMid == highIx-1) {
// move highIx down to the low end of the mid values // move highIx down to the low end of the mid values
bsi.narrowSearch(midIx, true); bsi.narrowSearch(midIx, true);
return -1; return -1;
@ -871,7 +882,11 @@ public final class LookupUtils {
// Note - if moving highIx down (due to lookup<vector[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, // this execution path only moves highIx it down as far as newMid, not midIx,
// which would be more efficient. // which would be more efficient.
if (reverse) {
bsi.narrowSearch(newMid, cr.isGreaterThan());
} else {
bsi.narrowSearch(newMid, cr.isLessThan()); bsi.narrowSearch(newMid, cr.isLessThan());
}
return -1; return -1;
} }
} }