/** * Excel has funny behaviour when the some elements in the search vector are the wrong type. * */ private static int PerformBinarySearch(ValueVector vector, LookupValueComparer lookupComparer) { // both low and high indexes point to values assumed too low and too high. BinarySearchIndexes bsi = new BinarySearchIndexes(vector.Size); while (true) { int midIx = bsi.GetMidIx(); if (midIx < 0) { return(bsi.GetLowIx()); } CompareResult cr = lookupComparer.CompareTo(vector.GetItem(midIx)); if (cr.IsTypeMismatch) { int newMidIx = HandleMidValueTypeMismatch(lookupComparer, vector, bsi, midIx); if (newMidIx < 0) { continue; } midIx = newMidIx; cr = lookupComparer.CompareTo(vector.GetItem(midIx)); } if (cr.IsEqual) { return(FindLastIndexInRunOfEqualValues(lookupComparer, vector, midIx, bsi.GetHighIx())); } bsi.narrowSearch(midIx, cr.IsLessThan); } }
/** * Excel seems to handle mismatched types initially by just stepping 'mid' ix forward to the * first compatible value. * @param midIx 'mid' index (value which has the wrong type) * @return usually -1, signifying that the BinarySearchIndex has been narrowed to the new mid * index. Zero or greater signifies that an exact match for the lookup value was found */ private static int HandleMidValueTypeMismatch(LookupValueComparer lookupComparer, ValueVector vector, BinarySearchIndexes bsi, int midIx) { int newMid = midIx; int highIx = bsi.GetHighIx(); while (true) { newMid++; if (newMid == highIx) { // every element from midIx to highIx was the wrong type // move highIx down to the low end of the mid values bsi.narrowSearch(midIx, true); return(-1); } CompareResult cr = lookupComparer.CompareTo(vector.GetItem(newMid)); if (cr.IsLessThan && newMid == highIx - 1) { // move highIx down to the low end of the mid values bsi.narrowSearch(midIx, true); return(-1); // but only when "newMid == highIx-1"? slightly weird. // It would seem more efficient to always do this. } if (cr.IsTypeMismatch) { // keep stepping over values Until the right type Is found continue; } if (cr.IsEqual) { return(newMid); } // Note - if moving highIx down (due to lookup<vector[newMid]), // this execution path only moves highIx it down as far as newMid, not midIx, // which would be more efficient. bsi.narrowSearch(newMid, cr.IsLessThan); return(-1); } }
/** * Excel seems to handle mismatched types initially by just stepping 'mid' ix forward to the * first compatible value. * @param midIx 'mid' index (value which has the wrong type) * @return usually -1, signifying that the BinarySearchIndex has been narrowed to the new mid * index. Zero or greater signifies that an exact match for the lookup value was found */ private static int HandleMidValueTypeMismatch(LookupValueComparer lookupComparer, ValueVector vector, BinarySearchIndexes bsi, int midIx) { int newMid = midIx; int highIx = bsi.GetHighIx(); while (true) { newMid++; if (newMid == highIx) { // every element from midIx to highIx was the wrong type // move highIx down to the low end of the mid values bsi.narrowSearch(midIx, true); return -1; } CompareResult cr = lookupComparer.CompareTo(vector.GetItem(newMid)); if (cr.IsLessThan && newMid == highIx - 1) { // move highIx down to the low end of the mid values bsi.narrowSearch(midIx, true); return -1; // but only when "newMid == highIx-1"? slightly weird. // It would seem more efficient to always do this. } if (cr.IsTypeMismatch) { // keep stepping over values Until the right type Is found continue; } if (cr.IsEqual) { return newMid; } // Note - if moving highIx down (due to lookup<vector[newMid]), // this execution path only moves highIx it down as far as newMid, not midIx, // which would be more efficient. bsi.narrowSearch(newMid, cr.IsLessThan); return -1; } }
/** * Excel has funny behaviour when the some elements in the search vector are the wrong type. * */ private static int PerformBinarySearch(ValueVector vector, LookupValueComparer lookupComparer) { // both low and high indexes point to values assumed too low and too high. BinarySearchIndexes bsi = new BinarySearchIndexes(vector.Size); while (true) { int midIx = bsi.GetMidIx(); if (midIx < 0) { return bsi.GetLowIx(); } CompareResult cr = lookupComparer.CompareTo(vector.GetItem(midIx)); if (cr.IsTypeMismatch) { int newMidIx = HandleMidValueTypeMismatch(lookupComparer, vector, bsi, midIx); if (newMidIx < 0) { continue; } midIx = newMidIx; cr = lookupComparer.CompareTo(vector.GetItem(midIx)); } if (cr.IsEqual) { return FindLastIndexInRunOfEqualValues(lookupComparer, vector, midIx, bsi.GetHighIx()); } bsi.narrowSearch(midIx, cr.IsLessThan); } }