diff --git a/library/src/main/java/com/google/android/exoplayer2/util/Util.java b/library/src/main/java/com/google/android/exoplayer2/util/Util.java index 8278bc7b15..62d8c3927e 100644 --- a/library/src/main/java/com/google/android/exoplayer2/util/Util.java +++ b/library/src/main/java/com/google/android/exoplayer2/util/Util.java @@ -299,110 +299,167 @@ public final class Util { } /** - * Returns the index of the largest value in an array that is less than (or optionally equal to) - * a specified value. + * Returns the index of the largest element in {@code array} that is less than (or optionally + * equal to) a specified {@code value}. *

- * The search is performed using a binary search algorithm, so the array must be sorted. + * The search is performed using a binary search algorithm, so the array must be sorted. If the + * array contains multiple elements equal to {@code value} and {@code inclusive} is true, the + * index of the first one will be returned. * - * @param a The array to search. + * @param array The array to search. * @param value The value being searched for. * @param inclusive If the value is present in the array, whether to return the corresponding - * index. If false then the returned index corresponds to the largest value in the array that - * is strictly less than the value. + * index. If false then the returned index corresponds to the largest element strictly less + * than the value. * @param stayInBounds If true, then 0 will be returned in the case that the value is smaller than - * the smallest value in the array. If false then -1 will be returned. + * the smallest element in the array. If false then -1 will be returned. + * @return The index of the largest element in {@code array} that is less than (or optionally + * equal to) {@code value}. */ - public static int binarySearchFloor(int[] a, int value, boolean inclusive, boolean stayInBounds) { - int index = Arrays.binarySearch(a, value); - index = index < 0 ? -(index + 2) : (inclusive ? index : (index - 1)); - return stayInBounds ? Math.max(0, index) : index; - } - - /** - * Returns the index of the largest value in an array that is less than (or optionally equal to) - * a specified value. - *

- * The search is performed using a binary search algorithm, so the array must be sorted. - * - * @param a The array to search. - * @param value The value being searched for. - * @param inclusive If the value is present in the array, whether to return the corresponding - * index. If false then the returned index corresponds to the largest value in the array that - * is strictly less than the value. - * @param stayInBounds If true, then 0 will be returned in the case that the value is smaller than - * the smallest value in the array. If false then -1 will be returned. - */ - public static int binarySearchFloor(long[] a, long value, boolean inclusive, + public static int binarySearchFloor(int[] array, int value, boolean inclusive, boolean stayInBounds) { - int index = Arrays.binarySearch(a, value); - index = index < 0 ? -(index + 2) : (inclusive ? index : (index - 1)); + int index = Arrays.binarySearch(array, value); + if (index < 0) { + index = -(index + 2); + } else { + while ((--index) >= 0 && array[index] == value) {} + if (inclusive) { + index++; + } + } return stayInBounds ? Math.max(0, index) : index; } /** - * Returns the index of the smallest value in an array that is greater than (or optionally equal - * to) a specified value. + * Returns the index of the largest element in {@code array} that is less than (or optionally + * equal to) a specified {@code value}. *

- * The search is performed using a binary search algorithm, so the array must be sorted. + * The search is performed using a binary search algorithm, so the array must be sorted. If the + * array contains multiple elements equal to {@code value} and {@code inclusive} is true, the + * index of the first one will be returned. * - * @param a The array to search. + * @param array The array to search. * @param value The value being searched for. * @param inclusive If the value is present in the array, whether to return the corresponding - * index. If false then the returned index corresponds to the largest value in the array that - * is strictly less than the value. + * index. If false then the returned index corresponds to the largest element strictly less + * than the value. + * @param stayInBounds If true, then 0 will be returned in the case that the value is smaller than + * the smallest element in the array. If false then -1 will be returned. + * @return The index of the largest element in {@code array} that is less than (or optionally + * equal to) {@code value}. + */ + public static int binarySearchFloor(long[] array, long value, boolean inclusive, + boolean stayInBounds) { + int index = Arrays.binarySearch(array, value); + if (index < 0) { + index = -(index + 2); + } else { + while ((--index) >= 0 && array[index] == value) {} + if (inclusive) { + index++; + } + } + return stayInBounds ? Math.max(0, index) : index; + } + + /** + * Returns the index of the smallest element in {@code array} that is greater than (or optionally + * equal to) a specified {@code value}. + *

+ * The search is performed using a binary search algorithm, so the array must be sorted. If + * the array contains multiple elements equal to {@code value} and {@code inclusive} is true, the + * index of the last one will be returned. + * + * @param array The array to search. + * @param value The value being searched for. + * @param inclusive If the value is present in the array, whether to return the corresponding + * index. If false then the returned index corresponds to the smallest element strictly + * greater than the value. * @param stayInBounds If true, then {@code (a.length - 1)} will be returned in the case that the - * value is greater than the largest value in the array. If false then {@code a.length} will + * value is greater than the largest element in the array. If false then {@code a.length} will * be returned. + * @return The index of the smallest element in {@code array} that is greater than (or optionally + * equal to) {@code value}. */ - public static int binarySearchCeil(long[] a, long value, boolean inclusive, + public static int binarySearchCeil(long[] array, long value, boolean inclusive, boolean stayInBounds) { - int index = Arrays.binarySearch(a, value); - index = index < 0 ? ~index : (inclusive ? index : (index + 1)); - return stayInBounds ? Math.min(a.length - 1, index) : index; + int index = Arrays.binarySearch(array, value); + if (index < 0) { + index = ~index; + } else { + while ((++index) < array.length && array[index] == value) {} + if (inclusive) { + index--; + } + } + return stayInBounds ? Math.min(array.length - 1, index) : index; } /** - * Returns the index of the largest value in an list that is less than (or optionally equal to) - * a specified value. + * Returns the index of the largest element in {@code list} that is less than (or optionally equal + * to) a specified {@code value}. *

- * The search is performed using a binary search algorithm, so the list must be sorted. + * The search is performed using a binary search algorithm, so the list must be sorted. If the + * list contains multiple elements equal to {@code value} and {@code inclusive} is true, the + * index of the first one will be returned. * * @param The type of values being searched. * @param list The list to search. * @param value The value being searched for. * @param inclusive If the value is present in the list, whether to return the corresponding - * index. If false then the returned index corresponds to the largest value in the list that - * is strictly less than the value. + * index. If false then the returned index corresponds to the largest element strictly less + * than the value. * @param stayInBounds If true, then 0 will be returned in the case that the value is smaller than - * the smallest value in the list. If false then -1 will be returned. + * the smallest element in the list. If false then -1 will be returned. + * @return The index of the largest element in {@code list} that is less than (or optionally equal + * to) {@code value}. */ public static int binarySearchFloor(List> list, T value, boolean inclusive, boolean stayInBounds) { int index = Collections.binarySearch(list, value); - index = index < 0 ? -(index + 2) : (inclusive ? index : (index - 1)); + if (index < 0) { + index = -(index + 2); + } else { + while ((--index) >= 0 && list.get(index).compareTo(value) == 0) {} + if (inclusive) { + index++; + } + } return stayInBounds ? Math.max(0, index) : index; } /** - * Returns the index of the smallest value in an list that is greater than (or optionally equal - * to) a specified value. + * Returns the index of the smallest element in {@code list} that is greater than (or optionally + * equal to) a specified value. *

- * The search is performed using a binary search algorithm, so the list must be sorted. + * The search is performed using a binary search algorithm, so the list must be sorted. If the + * list contains multiple elements equal to {@code value} and {@code inclusive} is true, the + * index of the last one will be returned. * * @param The type of values being searched. * @param list The list to search. * @param value The value being searched for. * @param inclusive If the value is present in the list, whether to return the corresponding - * index. If false then the returned index corresponds to the smallest value in the list that - * is strictly greater than the value. + * index. If false then the returned index corresponds to the smallest element strictly + * greater than the value. * @param stayInBounds If true, then {@code (list.size() - 1)} will be returned in the case that - * the value is greater than the largest value in the list. If false then {@code list.size()} - * will be returned. + * the value is greater than the largest element in the list. If false then + * {@code list.size()} will be returned. + * @return The index of the smallest element in {@code list} that is greater than (or optionally + * equal to) {@code value}. */ public static int binarySearchCeil(List> list, T value, boolean inclusive, boolean stayInBounds) { int index = Collections.binarySearch(list, value); - index = index < 0 ? ~index : (inclusive ? index : (index + 1)); + if (index < 0) { + index = ~index; + } else { + int listSize = list.size(); + while ((++index) < listSize && list.get(index).compareTo(value) == 0) {} + if (inclusive) { + index--; + } + } return stayInBounds ? Math.min(list.size() - 1, index) : index; }