diff --git a/lodash.js b/lodash.js index c08c32589..3648ea663 100644 --- a/lodash.js +++ b/lodash.js @@ -1014,7 +1014,7 @@ * Creates a `lodash` object which wraps `value` to enable intuitive chaining. * Methods that operate on and return arrays, collections, and functions can * be chained together. Methods that return a boolean or single value will - * automatically end the chain returning the unwrapped result. Explicit chaining + * automatically end the chain returning the unwrapped value. Explicit chaining * may be enabled by using `_.chain`. The execution of chained methods is lazy, * that is, execution is deferred until `_#value` is implicitly or explicitly * called. @@ -2604,29 +2604,20 @@ high = array ? array.length : low; value = iteratee(value); - - var valIsNaN = value !== value, - valIsUndef = typeof value == 'undefined'; - + if (value !== value || typeof value == 'undefined' || high > (MAX_ARRAY_LENGTH / 2)) { + return edgeSortedIndex(array, value, iteratee, retHighest); + } while (low < high) { - var mid = floor((low + high) / 2), - computed = iteratee(array[mid]), - isReflexive = computed === computed; + var mid = (low + high) >>> 1, + computed = iteratee(array[mid]); - if (valIsNaN) { - var setLow = isReflexive || retHighest; - } else if (valIsUndef) { - setLow = isReflexive && (retHighest || typeof computed != 'undefined'); - } else { - setLow = retHighest ? (computed <= value) : (computed < value); - } - if (setLow) { + if (retHighest ? (computed <= value) : (computed < value)) { low = mid + 1; } else { high = mid; } } - return nativeMin(high, MAX_ARRAY_INDEX); + return high; } /** @@ -3181,6 +3172,46 @@ return setter(result, newData); } + /** + * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` without + * support for callback shorthands and `this` binding. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} iteratee The function invoked per iteration. + * @param {boolean} [retHighest=false] Specify returning the highest, instead + * of the lowest, index at which a value should be inserted into `array`. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function edgeSortedIndex(array, value, iteratee, retHighest) { + var low = 0, + high = array ? array.length : low, + valIsNaN = value !== value, + valIsUndef = typeof value == 'undefined'; + + while (low < high) { + var mid = floor((low + high) / 2), + computed = iteratee(array[mid]), + isReflexive = computed === computed; + + if (valIsNaN) { + var setLow = isReflexive || retHighest; + } else if (valIsUndef) { + setLow = isReflexive && (retHighest || typeof computed != 'undefined'); + } else { + setLow = retHighest ? (computed <= value) : (computed < value); + } + if (setLow) { + low = mid + 1; + } else { + high = mid; + } + } + return nativeMin(high, MAX_ARRAY_INDEX); + } + /** * Gets the appropriate "callback" function. If the `_.callback` method is * customized this function returns the custom method, otherwise it returns