From b9180187af13ae672cb6a6e7e6cb09150d22d9ee Mon Sep 17 00:00:00 2001 From: ali-ghanbari Date: Tue, 14 Sep 2021 23:24:29 -0500 Subject: [PATCH 1/5] Added floor and ceiling binary search methods for sorted arrays. Initial implementation for Object type and each primitive type. A few test cases are also included. --- .../org/apache/commons/lang3/ArrayUtils.java | 664 ++++++++++++++++++ .../apache/commons/lang3/ArrayUtilsTest.java | 128 ++++ 2 files changed, 792 insertions(+) diff --git a/src/main/java/org/apache/commons/lang3/ArrayUtils.java b/src/main/java/org/apache/commons/lang3/ArrayUtils.java index a571636e074..965ed205920 100644 --- a/src/main/java/org/apache/commons/lang3/ArrayUtils.java +++ b/src/main/java/org/apache/commons/lang3/ArrayUtils.java @@ -1666,6 +1666,670 @@ public static boolean contains(final short[] array, final short valueToFind) { return indexOf(array, valueToFind) != INDEX_NOT_FOUND; } + @SuppressWarnings({"rawtypes", "unchecked"}) + public static int ceiling(final Object[] array, final Object valueToFind) { + return ceiling(array, 0, array.length, valueToFind, Comparator.comparing(v -> ((Comparable) v))); + } + + public static int ceiling(final T[] array, + final int fromIndex, + final int toIndex, + final T valueToFind, + final Comparator comparator) { + Validate.notNull(array); + Validate.notNull(comparator); + Validate.inclusiveBetween(0, array.length - 1, fromIndex); + Validate.inclusiveBetween(0, array.length, toIndex); + if (fromIndex >= toIndex) { + return -1; + } + int lo = fromIndex; + int hi = toIndex - 1; + if (comparator.compare(valueToFind, array[hi]) > 0) { + return -1; + } + if (comparator.compare(valueToFind, array[lo]) <= 0) { + return lo; + } + while (lo <= hi) { + final int mid = (lo + hi) / 2; + final int cmp = comparator.compare(array[mid], valueToFind); + if (cmp == 0) { + return mid; + } else if (cmp > 0) { + if (lo <= mid - 1 && comparator.compare(array[mid - 1], valueToFind) < 0) { + return mid; + } + hi = mid - 1; + } else { + if (mid + 1 <= hi && comparator.compare(array[mid + 1], valueToFind) >= 0) { + return mid + 1; + } + lo = mid + 1; + } + } + return -1; + } + + public static int ceiling(final int[] array, final int valueToFind) { + return ceiling(array, 0, array.length, valueToFind); + } + + public static int ceiling(final int[] array, + final int fromIndex, + final int toIndex, + final int valueToFind) { + Validate.notNull(array); + Validate.inclusiveBetween(0, array.length - 1, fromIndex); + Validate.inclusiveBetween(0, array.length, toIndex); + if (fromIndex >= toIndex) { + return -1; + } + int lo = fromIndex; + int hi = toIndex - 1; + if (valueToFind > array[hi]) { + return -1; + } + if (valueToFind <= array[lo]) { + return lo; + } + while (lo <= hi) { + final int mid = (lo + hi) / 2; + if (array[mid] == valueToFind) { + return mid; + } else if (array[mid] > valueToFind) { + if (lo <= mid - 1 && array[mid - 1] < valueToFind) { + return mid; + } + hi = mid - 1; + } else { + if (mid + 1 <= hi && array[mid + 1] >= valueToFind) { + return mid + 1; + } + lo = mid + 1; + } + } + return -1; + } + + public static int ceiling(final long[] array, final long valueToFind) { + return ceiling(array, 0, array.length, valueToFind); + } + + public static int ceiling(final long[] array, + final int fromIndex, + final int toIndex, + final long valueToFind) { + Validate.notNull(array); + Validate.inclusiveBetween(0, array.length - 1, fromIndex); + Validate.inclusiveBetween(0, array.length, toIndex); + if (fromIndex >= toIndex) { + return -1; + } + int lo = fromIndex; + int hi = toIndex - 1; + if (valueToFind > array[hi]) { + return -1; + } + if (valueToFind <= array[lo]) { + return lo; + } + while (lo <= hi) { + final int mid = (lo + hi) / 2; + if (array[mid] == valueToFind) { + return mid; + } else if (array[mid] > valueToFind) { + if (lo <= mid - 1 && array[mid - 1] < valueToFind) { + return mid; + } + hi = mid - 1; + } else { + if (mid + 1 <= hi && array[mid + 1] >= valueToFind) { + return mid + 1; + } + lo = mid + 1; + } + } + return -1; + } + + public static int ceiling(final short[] array, final short valueToFind) { + return ceiling(array, 0, array.length, valueToFind); + } + + public static int ceiling(final short[] array, + final int fromIndex, + final int toIndex, + final short valueToFind) { + Validate.notNull(array); + Validate.inclusiveBetween(0, array.length - 1, fromIndex); + Validate.inclusiveBetween(0, array.length, toIndex); + if (fromIndex >= toIndex) { + return -1; + } + int lo = fromIndex; + int hi = toIndex - 1; + if (valueToFind > array[hi]) { + return -1; + } + if (valueToFind <= array[lo]) { + return lo; + } + while (lo <= hi) { + final int mid = (lo + hi) / 2; + if (array[mid] == valueToFind) { + return mid; + } else if (array[mid] > valueToFind) { + if (lo <= mid - 1 && array[mid - 1] < valueToFind) { + return mid; + } + hi = mid - 1; + } else { + if (mid + 1 <= hi && array[mid + 1] >= valueToFind) { + return mid + 1; + } + lo = mid + 1; + } + } + return -1; + } + + public static int ceiling(final byte[] array, final byte valueToFind) { + return ceiling(array, 0, array.length, valueToFind); + } + + public static int ceiling(final byte[] array, + final int fromIndex, + final int toIndex, + final byte valueToFind) { + Validate.notNull(array); + Validate.inclusiveBetween(0, array.length - 1, fromIndex); + Validate.inclusiveBetween(0, array.length, toIndex); + if (fromIndex >= toIndex) { + return -1; + } + int lo = fromIndex; + int hi = toIndex - 1; + if (valueToFind > array[hi]) { + return -1; + } + if (valueToFind <= array[lo]) { + return lo; + } + while (lo <= hi) { + final int mid = (lo + hi) / 2; + if (array[mid] == valueToFind) { + return mid; + } else if (array[mid] > valueToFind) { + if (lo <= mid - 1 && array[mid - 1] < valueToFind) { + return mid; + } + hi = mid - 1; + } else { + if (mid + 1 <= hi && array[mid + 1] >= valueToFind) { + return mid + 1; + } + lo = mid + 1; + } + } + return -1; + } + + public static int ceiling(final char[] array, final char valueToFind) { + return ceiling(array, 0, array.length, valueToFind); + } + + public static int ceiling(final char[] array, + final int fromIndex, + final int toIndex, + final char valueToFind) { + Validate.notNull(array); + Validate.inclusiveBetween(0, array.length - 1, fromIndex); + Validate.inclusiveBetween(0, array.length, toIndex); + if (fromIndex >= toIndex) { + return -1; + } + int lo = fromIndex; + int hi = toIndex - 1; + if (valueToFind > array[hi]) { + return -1; + } + if (valueToFind <= array[lo]) { + return lo; + } + while (lo <= hi) { + final int mid = (lo + hi) / 2; + if (array[mid] == valueToFind) { + return mid; + } else if (array[mid] > valueToFind) { + if (lo <= mid - 1 && array[mid - 1] < valueToFind) { + return mid; + } + hi = mid - 1; + } else { + if (mid + 1 <= hi && array[mid + 1] >= valueToFind) { + return mid + 1; + } + lo = mid + 1; + } + } + return -1; + } + + public static int ceiling(final float[] array, final float valueToFind) { + return ceiling(array, 0, array.length, valueToFind); + } + + public static int ceiling(final float[] array, + final int fromIndex, + final int toIndex, + final float valueToFind) { + Validate.notNull(array); + Validate.inclusiveBetween(0, array.length - 1, fromIndex); + Validate.inclusiveBetween(0, array.length, toIndex); + if (fromIndex >= toIndex) { + return -1; + } + int lo = fromIndex; + int hi = toIndex - 1; + if (valueToFind > array[hi]) { + return -1; + } + if (valueToFind <= array[lo]) { + return lo; + } + while (lo <= hi) { + final int mid = (lo + hi) / 2; + if (array[mid] == valueToFind) { + return mid; + } else if (array[mid] > valueToFind) { + if (lo <= mid - 1 && array[mid - 1] < valueToFind) { + return mid; + } + hi = mid - 1; + } else { + if (mid + 1 <= hi && array[mid + 1] >= valueToFind) { + return mid + 1; + } + lo = mid + 1; + } + } + return -1; + } + + public static int ceiling(final double[] array, final double valueToFind) { + return ceiling(array, 0, array.length, valueToFind); + } + + public static int ceiling(final double[] array, + final int fromIndex, + final int toIndex, + final double valueToFind) { + Validate.notNull(array); + Validate.inclusiveBetween(0, array.length - 1, fromIndex); + Validate.inclusiveBetween(0, array.length, toIndex); + if (fromIndex >= toIndex) { + return -1; + } + int lo = fromIndex; + int hi = toIndex - 1; + if (valueToFind > array[hi]) { + return -1; + } + if (valueToFind <= array[lo]) { + return lo; + } + while (lo <= hi) { + final int mid = (lo + hi) / 2; + if (array[mid] == valueToFind) { + return mid; + } else if (array[mid] > valueToFind) { + if (lo <= mid - 1 && array[mid - 1] < valueToFind) { + return mid; + } + hi = mid - 1; + } else { + if (mid + 1 <= hi && array[mid + 1] >= valueToFind) { + return mid + 1; + } + lo = mid + 1; + } + } + return -1; + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + public static int floor(final Object[] array, final Object valueToFind) { + return floor(array, 0, array.length, valueToFind, Comparator.comparing(v -> ((Comparable) v))); + } + + public static int floor(final T[] array, + final int fromIndex, + final int toIndex, + final T valueToFind, + final Comparator comparator) { + Validate.notNull(array); + Validate.notNull(comparator); + Validate.inclusiveBetween(0, array.length - 1, fromIndex); + Validate.inclusiveBetween(0, array.length, toIndex); + if (fromIndex >= toIndex) { + return -1; + } + int lo = fromIndex; + int hi = toIndex - 1; + if (comparator.compare(array[lo], valueToFind) > 0) { + return -1; + } + if (comparator.compare(array[hi], valueToFind) <= 0) { + return hi; + } + while (lo <= hi) { + final int mid = (lo + hi) / 2; + final int cmp = comparator.compare(array[mid], valueToFind); + if (cmp == 0) { + return mid; + } else if (cmp > 0) { + if (lo <= mid - 1 && comparator.compare(array[mid - 1], valueToFind) <= 0) { + return mid - 1; + } + hi = mid - 1; + } else { + if (mid + 1 <= hi && comparator.compare(array[mid + 1], valueToFind) > 0) { + return mid; + } + lo = mid + 1; + } + } + return -1; + } + + public static int floor(final int[] array, final int valueToFind) { + return floor(array, 0, array.length, valueToFind); + } + + public static int floor(final int[] array, + final int fromIndex, + final int toIndex, + final int valueToFind) { + Validate.notNull(array); + Validate.inclusiveBetween(0, array.length - 1, fromIndex); + Validate.inclusiveBetween(0, array.length, toIndex); + if (fromIndex >= toIndex) { + return -1; + } + int lo = fromIndex; + int hi = toIndex - 1; + if (array[lo] > valueToFind) { + return -1; + } + if (array[hi] <= valueToFind) { + return hi; + } + while (lo <= hi) { + final int mid = (lo + hi) / 2; + if (array[mid] == valueToFind) { + return mid; + } else if (array[mid] > valueToFind) { + if (lo <= mid - 1 && array[mid - 1] <= valueToFind) { + return mid - 1; + } + hi = mid - 1; + } else { + if (mid + 1 <= hi && array[mid + 1] > valueToFind) { + return mid; + } + lo = mid + 1; + } + } + return -1; + } + + public static int floor(final long[] array, final long valueToFind) { + return floor(array, 0, array.length, valueToFind); + } + + public static int floor(final long[] array, + final int fromIndex, + final int toIndex, + final long valueToFind) { + Validate.notNull(array); + Validate.inclusiveBetween(0, array.length - 1, fromIndex); + Validate.inclusiveBetween(0, array.length, toIndex); + if (fromIndex >= toIndex) { + return -1; + } + int lo = fromIndex; + int hi = toIndex - 1; + if (array[lo] > valueToFind) { + return -1; + } + if (array[hi] <= valueToFind) { + return hi; + } + while (lo <= hi) { + final int mid = (lo + hi) / 2; + if (array[mid] == valueToFind) { + return mid; + } else if (array[mid] > valueToFind) { + if (lo <= mid - 1 && array[mid - 1] <= valueToFind) { + return mid - 1; + } + hi = mid - 1; + } else { + if (mid + 1 <= hi && array[mid + 1] > valueToFind) { + return mid; + } + lo = mid + 1; + } + } + return -1; + } + + public static int floor(final float[] array, final float valueToFind) { + return floor(array, 0, array.length, valueToFind); + } + + public static int floor(final float[] array, + final int fromIndex, + final int toIndex, + final float valueToFind) { + Validate.notNull(array); + Validate.inclusiveBetween(0, array.length - 1, fromIndex); + Validate.inclusiveBetween(0, array.length, toIndex); + if (fromIndex >= toIndex) { + return -1; + } + int lo = fromIndex; + int hi = toIndex - 1; + if (array[lo] > valueToFind) { + return -1; + } + if (array[hi] <= valueToFind) { + return hi; + } + while (lo <= hi) { + final int mid = (lo + hi) / 2; + if (array[mid] == valueToFind) { + return mid; + } else if (array[mid] > valueToFind) { + if (lo <= mid - 1 && array[mid - 1] <= valueToFind) { + return mid - 1; + } + hi = mid - 1; + } else { + if (mid + 1 <= hi && array[mid + 1] > valueToFind) { + return mid; + } + lo = mid + 1; + } + } + return -1; + } + + public static int floor(final double[] array, final double valueToFind) { + return floor(array, 0, array.length, valueToFind); + } + + public static int floor(final double[] array, + final int fromIndex, + final int toIndex, + final double valueToFind) { + Validate.notNull(array); + Validate.inclusiveBetween(0, array.length - 1, fromIndex); + Validate.inclusiveBetween(0, array.length, toIndex); + if (fromIndex >= toIndex) { + return -1; + } + int lo = fromIndex; + int hi = toIndex - 1; + if (array[lo] > valueToFind) { + return -1; + } + if (array[hi] <= valueToFind) { + return hi; + } + while (lo <= hi) { + final int mid = (lo + hi) / 2; + if (array[mid] == valueToFind) { + return mid; + } else if (array[mid] > valueToFind) { + if (lo <= mid - 1 && array[mid - 1] <= valueToFind) { + return mid - 1; + } + hi = mid - 1; + } else { + if (mid + 1 <= hi && array[mid + 1] > valueToFind) { + return mid; + } + lo = mid + 1; + } + } + return -1; + } + + public static int floor(final short[] array, final short valueToFind) { + return floor(array, 0, array.length, valueToFind); + } + + public static int floor(final short[] array, + final int fromIndex, + final int toIndex, + final short valueToFind) { + Validate.notNull(array); + Validate.inclusiveBetween(0, array.length - 1, fromIndex); + Validate.inclusiveBetween(0, array.length, toIndex); + if (fromIndex >= toIndex) { + return -1; + } + int lo = fromIndex; + int hi = toIndex - 1; + if (array[lo] > valueToFind) { + return -1; + } + if (array[hi] <= valueToFind) { + return hi; + } + while (lo <= hi) { + final int mid = (lo + hi) / 2; + if (array[mid] == valueToFind) { + return mid; + } else if (array[mid] > valueToFind) { + if (lo <= mid - 1 && array[mid - 1] <= valueToFind) { + return mid - 1; + } + hi = mid - 1; + } else { + if (mid + 1 <= hi && array[mid + 1] > valueToFind) { + return mid; + } + lo = mid + 1; + } + } + return -1; + } + + public static int floor(final byte[] array, final byte valueToFind) { + return floor(array, 0, array.length, valueToFind); + } + + public static int floor(final byte[] array, + final int fromIndex, + final int toIndex, + final byte valueToFind) { + Validate.notNull(array); + Validate.inclusiveBetween(0, array.length - 1, fromIndex); + Validate.inclusiveBetween(0, array.length, toIndex); + if (fromIndex >= toIndex) { + return -1; + } + int lo = fromIndex; + int hi = toIndex - 1; + if (array[lo] > valueToFind) { + return -1; + } + if (array[hi] <= valueToFind) { + return hi; + } + while (lo <= hi) { + final int mid = (lo + hi) / 2; + if (array[mid] == valueToFind) { + return mid; + } else if (array[mid] > valueToFind) { + if (lo <= mid - 1 && array[mid - 1] <= valueToFind) { + return mid - 1; + } + hi = mid - 1; + } else { + if (mid + 1 <= hi && array[mid + 1] > valueToFind) { + return mid; + } + lo = mid + 1; + } + } + return -1; + } + + public static int floor(final char[] array, final char valueToFind) { + return floor(array, 0, array.length, valueToFind); + } + + public static int floor(final char[] array, + final int fromIndex, + final int toIndex, + final char valueToFind) { + Validate.notNull(array); + Validate.inclusiveBetween(0, array.length - 1, fromIndex); + Validate.inclusiveBetween(0, array.length, toIndex); + if (fromIndex >= toIndex) { + return -1; + } + int lo = fromIndex; + int hi = toIndex - 1; + if (array[lo] > valueToFind) { + return -1; + } + if (array[hi] <= valueToFind) { + return hi; + } + while (lo <= hi) { + final int mid = (lo + hi) / 2; + if (array[mid] == valueToFind) { + return mid; + } else if (array[mid] > valueToFind) { + if (lo <= mid - 1 && array[mid - 1] <= valueToFind) { + return mid - 1; + } + hi = mid - 1; + } else { + if (mid + 1 <= hi && array[mid + 1] > valueToFind) { + return mid; + } + lo = mid + 1; + } + } + return -1; + } + /** * Returns a copy of the given array of size 1 greater than the argument. * The last value of the array is left to the default value. diff --git a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java index 292a4a5fd73..6b782454a73 100644 --- a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java @@ -357,6 +357,134 @@ public void testContainsShort() { assertFalse(ArrayUtils.contains(array, (short) 99)); } + @Test + void testCeilingNullArray() { + boolean succeed = false; + try { + ArrayUtils.ceiling(null, 0, 0, 1, Integer::compareTo); + } catch (Exception ignored) { + succeed = true; + } + assertTrue(succeed); + } + + @Test + void testCeilingNullComparator() { + boolean succeed = false; + try { + ArrayUtils.ceiling(new Integer[] {1, 2}, 0, 0, 1, null); + } catch (Exception ignored) { + succeed = true; + } + assertTrue(succeed); + } + + @Test + void testCeilingBoxedNumbers() { + final Integer[] integers = {12, 14, 40, 70, 90}; + // full array + assertEquals(0, ArrayUtils.ceiling(integers, 12)); + assertEquals(1, ArrayUtils.ceiling(integers, 13)); + assertEquals(2, ArrayUtils.ceiling(integers, 40)); + assertEquals(3, ArrayUtils.ceiling(integers, 50)); + assertEquals(4, ArrayUtils.ceiling(integers, 89)); + assertEquals(-1, ArrayUtils.ceiling(integers, 91)); + assertEquals(0, ArrayUtils.ceiling(integers, 0)); + // range + assertEquals(1, ArrayUtils.ceiling(integers,1, 3, 12, Integer::compareTo)); + assertEquals(1, ArrayUtils.ceiling(integers,1, 3, 13, Integer::compareTo)); + assertEquals(2, ArrayUtils.ceiling(integers,1, 3, 40, Integer::compareTo)); + assertEquals(-1, ArrayUtils.ceiling(integers,1, 3, 50, Integer::compareTo)); + assertEquals(-1, ArrayUtils.ceiling(integers,1, 3, 89, Integer::compareTo)); + assertEquals(-1, ArrayUtils.ceiling(integers,1, 3, 91, Integer::compareTo)); + assertEquals(1, ArrayUtils.ceiling(integers,1, 3, 0, Integer::compareTo)); + } + + @Test + void testCeilingPrimitiveNumbers() { + final int[] integers = {12, 14, 40, 70, 90}; + // full array + assertEquals(0, ArrayUtils.ceiling(integers, 12)); + assertEquals(1, ArrayUtils.ceiling(integers, 13)); + assertEquals(2, ArrayUtils.ceiling(integers, 40)); + assertEquals(3, ArrayUtils.ceiling(integers, 50)); + assertEquals(4, ArrayUtils.ceiling(integers, 89)); + assertEquals(-1, ArrayUtils.ceiling(integers, 91)); + assertEquals(0, ArrayUtils.ceiling(integers, 0)); + // range + assertEquals(1, ArrayUtils.ceiling(integers,1, 3, 12)); + assertEquals(1, ArrayUtils.ceiling(integers,1, 3, 13)); + assertEquals(2, ArrayUtils.ceiling(integers,1, 3, 40)); + assertEquals(-1, ArrayUtils.ceiling(integers,1, 3, 50)); + assertEquals(-1, ArrayUtils.ceiling(integers,1, 3, 89)); + assertEquals(-1, ArrayUtils.ceiling(integers,1, 3, 91)); + assertEquals(1, ArrayUtils.ceiling(integers,1, 3, 0)); + } + + @Test + void testFloorNullArray() { + boolean succeed = false; + try { + ArrayUtils.floor(null, 0, 0, 1, Integer::compareTo); + } catch (Exception ignored) { + succeed = true; + } + assertTrue(succeed); + } + + @Test + void testFloorNullComparator() { + boolean succeed = false; + try { + ArrayUtils.floor(new Integer[] {1, 2}, 0, 0, 1, null); + } catch (Exception ignored) { + succeed = true; + } + assertTrue(succeed); + } + + @Test + void testFloorBoxedNumbers() { + final Integer[] integers = {12, 14, 40, 70, 90}; + // full array + assertEquals(0, ArrayUtils.floor(integers, 12)); + assertEquals(0, ArrayUtils.floor(integers, 13)); + assertEquals(2, ArrayUtils.floor(integers, 40)); + assertEquals(2, ArrayUtils.floor(integers, 50)); + assertEquals(3, ArrayUtils.floor(integers, 89)); + assertEquals(4, ArrayUtils.floor(integers, 91)); + assertEquals(-1, ArrayUtils.floor(integers, 0)); + // range + assertEquals(-1, ArrayUtils.floor(integers,1, 3, 12, Integer::compareTo)); + assertEquals(-1, ArrayUtils.floor(integers,1, 3, 13, Integer::compareTo)); + assertEquals(2, ArrayUtils.floor(integers,1, 3, 40, Integer::compareTo)); + assertEquals(2, ArrayUtils.floor(integers,1, 3, 50, Integer::compareTo)); + assertEquals(2, ArrayUtils.floor(integers,1, 3, 89, Integer::compareTo)); + assertEquals(2, ArrayUtils.floor(integers,1, 3, 91, Integer::compareTo)); + assertEquals(-1, ArrayUtils.floor(integers,1, 3, 0, Integer::compareTo)); + } + + @Test + void testFloorPrimitiveNumbers() { + final int[] integers = {12, 14, 40, 70, 90}; + // full array + assertEquals(0, ArrayUtils.floor(integers, 12)); + assertEquals(0, ArrayUtils.floor(integers, 13)); + assertEquals(2, ArrayUtils.floor(integers, 40)); + assertEquals(2, ArrayUtils.floor(integers, 50)); + assertEquals(3, ArrayUtils.floor(integers, 89)); + assertEquals(4, ArrayUtils.floor(integers, 91)); + assertEquals(-1, ArrayUtils.floor(integers, 0)); + // range + assertEquals(-1, ArrayUtils.floor(integers,1, 3, 12)); + assertEquals(-1, ArrayUtils.floor(integers,1, 3, 13)); + assertEquals(2, ArrayUtils.floor(integers,1, 3, 40)); + assertEquals(2, ArrayUtils.floor(integers,1, 3, 50)); + assertEquals(2, ArrayUtils.floor(integers,1, 3, 89)); + assertEquals(2, ArrayUtils.floor(integers,1, 3, 91)); + assertEquals(-1, ArrayUtils.floor(integers,1, 3, 0)); + } + @Test public void testCreatePrimitiveArray() { assertNull(ArrayUtils.toPrimitive((Object[]) null)); From ed98515962679f383e0be468777e67569946c8be Mon Sep 17 00:00:00 2001 From: ali-ghanbari Date: Wed, 15 Sep 2021 00:09:31 -0500 Subject: [PATCH 2/5] added whitespaces to avoid checkstyle errors --- .../apache/commons/lang3/ArrayUtilsTest.java | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java index 6b782454a73..93fc31fc6ba 100644 --- a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java @@ -391,13 +391,13 @@ void testCeilingBoxedNumbers() { assertEquals(-1, ArrayUtils.ceiling(integers, 91)); assertEquals(0, ArrayUtils.ceiling(integers, 0)); // range - assertEquals(1, ArrayUtils.ceiling(integers,1, 3, 12, Integer::compareTo)); - assertEquals(1, ArrayUtils.ceiling(integers,1, 3, 13, Integer::compareTo)); - assertEquals(2, ArrayUtils.ceiling(integers,1, 3, 40, Integer::compareTo)); - assertEquals(-1, ArrayUtils.ceiling(integers,1, 3, 50, Integer::compareTo)); - assertEquals(-1, ArrayUtils.ceiling(integers,1, 3, 89, Integer::compareTo)); - assertEquals(-1, ArrayUtils.ceiling(integers,1, 3, 91, Integer::compareTo)); - assertEquals(1, ArrayUtils.ceiling(integers,1, 3, 0, Integer::compareTo)); + assertEquals(1, ArrayUtils.ceiling(integers, 1, 3, 12, Integer::compareTo)); + assertEquals(1, ArrayUtils.ceiling(integers, 1, 3, 13, Integer::compareTo)); + assertEquals(2, ArrayUtils.ceiling(integers, 1, 3, 40, Integer::compareTo)); + assertEquals(-1, ArrayUtils.ceiling(integers, 1, 3, 50, Integer::compareTo)); + assertEquals(-1, ArrayUtils.ceiling(integers, 1, 3, 89, Integer::compareTo)); + assertEquals(-1, ArrayUtils.ceiling(integers, 1, 3, 91, Integer::compareTo)); + assertEquals(1, ArrayUtils.ceiling(integers, 1, 3, 0, Integer::compareTo)); } @Test @@ -412,13 +412,13 @@ void testCeilingPrimitiveNumbers() { assertEquals(-1, ArrayUtils.ceiling(integers, 91)); assertEquals(0, ArrayUtils.ceiling(integers, 0)); // range - assertEquals(1, ArrayUtils.ceiling(integers,1, 3, 12)); - assertEquals(1, ArrayUtils.ceiling(integers,1, 3, 13)); - assertEquals(2, ArrayUtils.ceiling(integers,1, 3, 40)); - assertEquals(-1, ArrayUtils.ceiling(integers,1, 3, 50)); - assertEquals(-1, ArrayUtils.ceiling(integers,1, 3, 89)); - assertEquals(-1, ArrayUtils.ceiling(integers,1, 3, 91)); - assertEquals(1, ArrayUtils.ceiling(integers,1, 3, 0)); + assertEquals(1, ArrayUtils.ceiling(integers, 1, 3, 12)); + assertEquals(1, ArrayUtils.ceiling(integers, 1, 3, 13)); + assertEquals(2, ArrayUtils.ceiling(integers, 1, 3, 40)); + assertEquals(-1, ArrayUtils.ceiling(integers, 1, 3, 50)); + assertEquals(-1, ArrayUtils.ceiling(integers, 1, 3, 89)); + assertEquals(-1, ArrayUtils.ceiling(integers, 1, 3, 91)); + assertEquals(1, ArrayUtils.ceiling(integers, 1, 3, 0)); } @Test @@ -455,13 +455,13 @@ void testFloorBoxedNumbers() { assertEquals(4, ArrayUtils.floor(integers, 91)); assertEquals(-1, ArrayUtils.floor(integers, 0)); // range - assertEquals(-1, ArrayUtils.floor(integers,1, 3, 12, Integer::compareTo)); - assertEquals(-1, ArrayUtils.floor(integers,1, 3, 13, Integer::compareTo)); - assertEquals(2, ArrayUtils.floor(integers,1, 3, 40, Integer::compareTo)); - assertEquals(2, ArrayUtils.floor(integers,1, 3, 50, Integer::compareTo)); - assertEquals(2, ArrayUtils.floor(integers,1, 3, 89, Integer::compareTo)); - assertEquals(2, ArrayUtils.floor(integers,1, 3, 91, Integer::compareTo)); - assertEquals(-1, ArrayUtils.floor(integers,1, 3, 0, Integer::compareTo)); + assertEquals(-1, ArrayUtils.floor(integers, 1, 3, 12, Integer::compareTo)); + assertEquals(-1, ArrayUtils.floor(integers, 1, 3, 13, Integer::compareTo)); + assertEquals(2, ArrayUtils.floor(integers, 1, 3, 40, Integer::compareTo)); + assertEquals(2, ArrayUtils.floor(integers, 1, 3, 50, Integer::compareTo)); + assertEquals(2, ArrayUtils.floor(integers, 1, 3, 89, Integer::compareTo)); + assertEquals(2, ArrayUtils.floor(integers, 1, 3, 91, Integer::compareTo)); + assertEquals(-1, ArrayUtils.floor(integers, 1, 3, 0, Integer::compareTo)); } @Test From a786aba7c6c1b90a430656559b9b9e24dc825a79 Mon Sep 17 00:00:00 2001 From: ali-ghanbari Date: Wed, 15 Sep 2021 09:37:03 -0500 Subject: [PATCH 3/5] added more whitespaces to avoid checkstyle errors --- .../org/apache/commons/lang3/ArrayUtilsTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java index 93fc31fc6ba..a68b1f680dd 100644 --- a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java @@ -476,13 +476,13 @@ void testFloorPrimitiveNumbers() { assertEquals(4, ArrayUtils.floor(integers, 91)); assertEquals(-1, ArrayUtils.floor(integers, 0)); // range - assertEquals(-1, ArrayUtils.floor(integers,1, 3, 12)); - assertEquals(-1, ArrayUtils.floor(integers,1, 3, 13)); - assertEquals(2, ArrayUtils.floor(integers,1, 3, 40)); - assertEquals(2, ArrayUtils.floor(integers,1, 3, 50)); - assertEquals(2, ArrayUtils.floor(integers,1, 3, 89)); - assertEquals(2, ArrayUtils.floor(integers,1, 3, 91)); - assertEquals(-1, ArrayUtils.floor(integers,1, 3, 0)); + assertEquals(-1, ArrayUtils.floor(integers, 1, 3, 12)); + assertEquals(-1, ArrayUtils.floor(integers, 1, 3, 13)); + assertEquals(2, ArrayUtils.floor(integers, 1, 3, 40)); + assertEquals(2, ArrayUtils.floor(integers, 1, 3, 50)); + assertEquals(2, ArrayUtils.floor(integers, 1, 3, 89)); + assertEquals(2, ArrayUtils.floor(integers, 1, 3, 91)); + assertEquals(-1, ArrayUtils.floor(integers, 1, 3, 0)); } @Test From 3f8003ff115d0c9081f4fce2bf04a606da3adf36 Mon Sep 17 00:00:00 2001 From: ali-ghanbari Date: Wed, 15 Sep 2021 15:20:24 -0500 Subject: [PATCH 4/5] added Javadoc, refined the code to avoid overlow warning, refined the code to avoid having magic numbers --- .../org/apache/commons/lang3/ArrayUtils.java | 664 ++++++++++++++++-- .../apache/commons/lang3/ArrayUtilsTest.java | 22 - 2 files changed, 598 insertions(+), 88 deletions(-) diff --git a/src/main/java/org/apache/commons/lang3/ArrayUtils.java b/src/main/java/org/apache/commons/lang3/ArrayUtils.java index 965ed205920..e439749c05e 100644 --- a/src/main/java/org/apache/commons/lang3/ArrayUtils.java +++ b/src/main/java/org/apache/commons/lang3/ArrayUtils.java @@ -1666,33 +1666,75 @@ public static boolean contains(final short[] array, final short valueToFind) { return indexOf(array, valueToFind) != INDEX_NOT_FOUND; } + /** + * Searches the specified array for the ceiling of the specified object using binary search algorithm. + * The ceiling of a comparable object is the least element in the array that is greater than or equal to the object. + * The input array must be sorted in ascending order according to the {@linkplain Comparable natural ordering} + * of its element. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * + * @param array The sorted array to be searched + * @param valueToFind A comparable object for which we want to find a ceiling + * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found. + * @throws ClassCastException If the array elements or valueToFind is not comparable + * @throws NullPointerException If array is null or comparing null values is not allowed + */ @SuppressWarnings({"rawtypes", "unchecked"}) public static int ceiling(final Object[] array, final Object valueToFind) { return ceiling(array, 0, array.length, valueToFind, Comparator.comparing(v -> ((Comparable) v))); } + /** + * Searches the specified array for the ceiling of the specified object using binary search algorithm within + * a specified range. + * The ceiling of a comparable object is the least element within the range that is greater than or equal to + * the object. + * The input array must be sorted in ascending order according to the {@linkplain Comparable natural ordering} + * of its element within the specified range (other array elements are not checked). + * Passing an array that is unsorted within the specified range (or an array that is sorted in descending order + * within that range) will lead to undefined behavior. + * The range is exclusive from the right end. + * + * @param the class of the objects in the array + * @param array The sorted array to be searched + * @param fromIndex The index of the first element (inclusive) to be searched + * @param toIndex The index of the last element (exclusive) to be searched + * @param valueToFind A comparable object for which we want to find a ceiling + * @param comparator The comparator by which the array is ordered. + * A {@code null} value indicates that the elements' {@linkplain Comparable natural ordering} + * should be used. + * @return The index of the ceiling if it is found; -1 will be returned if no ceiling was found within the + * specified range. + * @throws ClassCastException If the array elements or valueToFind is not comparable + * @throws NullPointerException If array is null or comparing null values is not allowed + * @throws IllegalArgumentException If any of the indices are out of bound + */ public static int ceiling(final T[] array, final int fromIndex, final int toIndex, final T valueToFind, final Comparator comparator) { + if (comparator == null) { + return ceiling(array, fromIndex, toIndex, valueToFind, + (v1, v2) -> ((Comparable) v1).compareTo((Comparable) v2)); + } Validate.notNull(array); - Validate.notNull(comparator); Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { - return -1; + return INDEX_NOT_FOUND; } int lo = fromIndex; int hi = toIndex - 1; if (comparator.compare(valueToFind, array[hi]) > 0) { - return -1; + return INDEX_NOT_FOUND; } if (comparator.compare(valueToFind, array[lo]) <= 0) { return lo; } while (lo <= hi) { - final int mid = (lo + hi) / 2; + final int mid = (lo + hi) >>> 1; final int cmp = comparator.compare(array[mid], valueToFind); if (cmp == 0) { return mid; @@ -1708,13 +1750,45 @@ public static int ceiling(final T[] array, lo = mid + 1; } } - return -1; + return INDEX_NOT_FOUND; } + /** + * Searches the specified array for the ceiling of the specified int value using binary search + * algorithm. + * The ceiling of an int value is the least element in the array that is greater than or equal to + * the value. + * The input array must be sorted in ascending order. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * + * @param array The sorted array to be searched + * @param valueToFind The int value for which we want to find a ceiling + * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found. + * @throws NullPointerException If array is null + */ public static int ceiling(final int[] array, final int valueToFind) { return ceiling(array, 0, array.length, valueToFind); } + /** + * Searches the specified array for the ceiling of the specified int value using binary search + * algorithm within the specified range. + * The ceiling of an int value within a range is the least element within the range that is greater + * than or equal to the value. + * The input array must be sorted in ascending order within the specified range. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * The range is exclusive from the right end. + * + * @param array The sorted array to be searched + * @param fromIndex The index of the first element (inclusive) to be searched + * @param toIndex The index of the last element (exclusive) to be searched + * @param valueToFind The int value for which we want to find a ceiling + * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found within the range. + * @throws NullPointerException If array is null + * @throws IllegalArgumentException If any of the indices are out of bound + */ public static int ceiling(final int[] array, final int fromIndex, final int toIndex, @@ -1723,18 +1797,18 @@ public static int ceiling(final int[] array, Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { - return -1; + return INDEX_NOT_FOUND; } int lo = fromIndex; int hi = toIndex - 1; if (valueToFind > array[hi]) { - return -1; + return INDEX_NOT_FOUND; } if (valueToFind <= array[lo]) { return lo; } while (lo <= hi) { - final int mid = (lo + hi) / 2; + final int mid = (lo + hi) >>> 1; if (array[mid] == valueToFind) { return mid; } else if (array[mid] > valueToFind) { @@ -1749,13 +1823,45 @@ public static int ceiling(final int[] array, lo = mid + 1; } } - return -1; + return INDEX_NOT_FOUND; } + /** + * Searches the specified array for the ceiling of the specified long value using binary search + * algorithm. + * The ceiling of an long value is the least element in the array that is greater than or equal to + * the value. + * The input array must be sorted in ascending order. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * + * @param array The sorted array to be searched + * @param valueToFind The long value for which we want to find a ceiling + * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found. + * @throws NullPointerException If array is null + */ public static int ceiling(final long[] array, final long valueToFind) { return ceiling(array, 0, array.length, valueToFind); } + /** + * Searches the specified array for the ceiling of the specified long value using binary search + * algorithm within the specified range. + * The ceiling of an long value within a range is the least element within the range that is greater + * than or equal to the value. + * The input array must be sorted in ascending order within the specified range. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * The range is exclusive from the right end. + * + * @param array The sorted array to be searched + * @param fromIndex The index of the first element (inclusive) to be searched + * @param toIndex The index of the last element (exclusive) to be searched + * @param valueToFind The long value for which we want to find a ceiling + * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found within the range. + * @throws NullPointerException If array is null + * @throws IllegalArgumentException If any of the indices are out of bound + */ public static int ceiling(final long[] array, final int fromIndex, final int toIndex, @@ -1764,18 +1870,18 @@ public static int ceiling(final long[] array, Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { - return -1; + return INDEX_NOT_FOUND; } int lo = fromIndex; int hi = toIndex - 1; if (valueToFind > array[hi]) { - return -1; + return INDEX_NOT_FOUND; } if (valueToFind <= array[lo]) { return lo; } while (lo <= hi) { - final int mid = (lo + hi) / 2; + final int mid = (lo + hi) >>> 1; if (array[mid] == valueToFind) { return mid; } else if (array[mid] > valueToFind) { @@ -1790,13 +1896,45 @@ public static int ceiling(final long[] array, lo = mid + 1; } } - return -1; + return INDEX_NOT_FOUND; } + /** + * Searches the specified array for the ceiling of the specified short value using binary search + * algorithm. + * The ceiling of an short value is the least element in the array that is greater than or equal to + * the value. + * The input array must be sorted in ascending order. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * + * @param array The sorted array to be searched + * @param valueToFind The short value for which we want to find a ceiling + * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found. + * @throws NullPointerException If array is null + */ public static int ceiling(final short[] array, final short valueToFind) { return ceiling(array, 0, array.length, valueToFind); } + /** + * Searches the specified array for the ceiling of the specified short value using binary search + * algorithm within the specified range. + * The ceiling of an short value within a range is the least element within the range that is greater + * than or equal to the value. + * The input array must be sorted in ascending order within the specified range. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * The range is exclusive from the right end. + * + * @param array The sorted array to be searched + * @param fromIndex The index of the first element (inclusive) to be searched + * @param toIndex The index of the last element (exclusive) to be searched + * @param valueToFind The short value for which we want to find a ceiling + * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found within the range. + * @throws NullPointerException If array is null + * @throws IllegalArgumentException If any of the indices are out of bound + */ public static int ceiling(final short[] array, final int fromIndex, final int toIndex, @@ -1805,18 +1943,18 @@ public static int ceiling(final short[] array, Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { - return -1; + return INDEX_NOT_FOUND; } int lo = fromIndex; int hi = toIndex - 1; if (valueToFind > array[hi]) { - return -1; + return INDEX_NOT_FOUND; } if (valueToFind <= array[lo]) { return lo; } while (lo <= hi) { - final int mid = (lo + hi) / 2; + final int mid = (lo + hi) >>> 1; if (array[mid] == valueToFind) { return mid; } else if (array[mid] > valueToFind) { @@ -1831,13 +1969,45 @@ public static int ceiling(final short[] array, lo = mid + 1; } } - return -1; + return INDEX_NOT_FOUND; } + /** + * Searches the specified array for the ceiling of the specified byte value using binary search + * algorithm. + * The ceiling of an byte value is the least element in the array that is greater than or equal to + * the value. + * The input array must be sorted in ascending order. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * + * @param array The sorted array to be searched + * @param valueToFind The byte value for which we want to find a ceiling + * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found. + * @throws NullPointerException If array is null + */ public static int ceiling(final byte[] array, final byte valueToFind) { return ceiling(array, 0, array.length, valueToFind); } + /** + * Searches the specified array for the ceiling of the specified byte value using binary search + * algorithm within the specified range. + * The ceiling of an byte value within a range is the least element within the range that is greater + * than or equal to the value. + * The input array must be sorted in ascending order within the specified range. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * The range is exclusive from the right end. + * + * @param array The sorted array to be searched + * @param fromIndex The index of the first element (inclusive) to be searched + * @param toIndex The index of the last element (exclusive) to be searched + * @param valueToFind The byte value for which we want to find a ceiling + * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found within the range. + * @throws NullPointerException If array is null + * @throws IllegalArgumentException If any of the indices are out of bound + */ public static int ceiling(final byte[] array, final int fromIndex, final int toIndex, @@ -1846,18 +2016,18 @@ public static int ceiling(final byte[] array, Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { - return -1; + return INDEX_NOT_FOUND; } int lo = fromIndex; int hi = toIndex - 1; if (valueToFind > array[hi]) { - return -1; + return INDEX_NOT_FOUND; } if (valueToFind <= array[lo]) { return lo; } while (lo <= hi) { - final int mid = (lo + hi) / 2; + final int mid = (lo + hi) >>> 1; if (array[mid] == valueToFind) { return mid; } else if (array[mid] > valueToFind) { @@ -1872,13 +2042,45 @@ public static int ceiling(final byte[] array, lo = mid + 1; } } - return -1; + return INDEX_NOT_FOUND; } + /** + * Searches the specified array for the ceiling of the specified char value using binary search + * algorithm. + * The ceiling of an char value is the least element in the array that is greater than or equal to + * the value. + * The input array must be sorted in ascending order. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * + * @param array The sorted array to be searched + * @param valueToFind The char value for which we want to find a ceiling + * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found. + * @throws NullPointerException If array is null + */ public static int ceiling(final char[] array, final char valueToFind) { return ceiling(array, 0, array.length, valueToFind); } + /** + * Searches the specified array for the ceiling of the specified char value using binary search + * algorithm within the specified range. + * The ceiling of an char value within a range is the least element within the range that is greater + * than or equal to the value. + * The input array must be sorted in ascending order within the specified range. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * The range is exclusive from the right end. + * + * @param array The sorted array to be searched + * @param fromIndex The index of the first element (inclusive) to be searched + * @param toIndex The index of the last element (exclusive) to be searched + * @param valueToFind The char value for which we want to find a ceiling + * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found within the range. + * @throws NullPointerException If array is null + * @throws IllegalArgumentException If any of the indices are out of bound + */ public static int ceiling(final char[] array, final int fromIndex, final int toIndex, @@ -1887,18 +2089,18 @@ public static int ceiling(final char[] array, Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { - return -1; + return INDEX_NOT_FOUND; } int lo = fromIndex; int hi = toIndex - 1; if (valueToFind > array[hi]) { - return -1; + return INDEX_NOT_FOUND; } if (valueToFind <= array[lo]) { return lo; } while (lo <= hi) { - final int mid = (lo + hi) / 2; + final int mid = (lo + hi) >>> 1; if (array[mid] == valueToFind) { return mid; } else if (array[mid] > valueToFind) { @@ -1913,13 +2115,45 @@ public static int ceiling(final char[] array, lo = mid + 1; } } - return -1; + return INDEX_NOT_FOUND; } + /** + * Searches the specified array for the ceiling of the specified float value using binary search + * algorithm. + * The ceiling of an float value is the least element in the array that is greater than or equal to + * the value. + * The input array must be sorted in ascending order. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * + * @param array The sorted array to be searched + * @param valueToFind The float value for which we want to find a ceiling + * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found. + * @throws NullPointerException If array is null + */ public static int ceiling(final float[] array, final float valueToFind) { return ceiling(array, 0, array.length, valueToFind); } + /** + * Searches the specified array for the ceiling of the specified float value using binary search + * algorithm within the specified range. + * The ceiling of an float value within a range is the least element within the range that is greater + * than or equal to the value. + * The input array must be sorted in ascending order within the specified range. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * The range is exclusive from the right end. + * + * @param array The sorted array to be searched + * @param fromIndex The index of the first element (inclusive) to be searched + * @param toIndex The index of the last element (exclusive) to be searched + * @param valueToFind The float value for which we want to find a ceiling + * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found within the range. + * @throws NullPointerException If array is null + * @throws IllegalArgumentException If any of the indices are out of bound + */ public static int ceiling(final float[] array, final int fromIndex, final int toIndex, @@ -1928,18 +2162,18 @@ public static int ceiling(final float[] array, Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { - return -1; + return INDEX_NOT_FOUND; } int lo = fromIndex; int hi = toIndex - 1; if (valueToFind > array[hi]) { - return -1; + return INDEX_NOT_FOUND; } if (valueToFind <= array[lo]) { return lo; } while (lo <= hi) { - final int mid = (lo + hi) / 2; + final int mid = (lo + hi) >>> 1; if (array[mid] == valueToFind) { return mid; } else if (array[mid] > valueToFind) { @@ -1954,13 +2188,45 @@ public static int ceiling(final float[] array, lo = mid + 1; } } - return -1; + return INDEX_NOT_FOUND; } + /** + * Searches the specified array for the ceiling of the specified double value using binary search + * algorithm. + * The ceiling of an double value is the least element in the array that is greater than or equal to + * the value. + * The input array must be sorted in ascending order. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * + * @param array The sorted array to be searched + * @param valueToFind The double value for which we want to find a ceiling + * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found. + * @throws NullPointerException If array is null + */ public static int ceiling(final double[] array, final double valueToFind) { return ceiling(array, 0, array.length, valueToFind); } + /** + * Searches the specified array for the ceiling of the specified double value using binary search + * algorithm within the specified range. + * The ceiling of an double value within a range is the least element within the range that is greater + * than or equal to the value. + * The input array must be sorted in ascending order within the specified range. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * The range is exclusive from the right end. + * + * @param array The sorted array to be searched + * @param fromIndex The index of the first element (inclusive) to be searched + * @param toIndex The index of the last element (exclusive) to be searched + * @param valueToFind The double value for which we want to find a ceiling + * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found within the range. + * @throws NullPointerException If array is null + * @throws IllegalArgumentException If any of the indices are out of bound + */ public static int ceiling(final double[] array, final int fromIndex, final int toIndex, @@ -1969,18 +2235,18 @@ public static int ceiling(final double[] array, Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { - return -1; + return INDEX_NOT_FOUND; } int lo = fromIndex; int hi = toIndex - 1; if (valueToFind > array[hi]) { - return -1; + return INDEX_NOT_FOUND; } if (valueToFind <= array[lo]) { return lo; } while (lo <= hi) { - final int mid = (lo + hi) / 2; + final int mid = (lo + hi) >>> 1; if (array[mid] == valueToFind) { return mid; } else if (array[mid] > valueToFind) { @@ -1995,36 +2261,78 @@ public static int ceiling(final double[] array, lo = mid + 1; } } - return -1; + return INDEX_NOT_FOUND; } + /** + * Searches the specified array for the floor of the specified object using binary search algorithm. + * The floor of a comparable object is the greatest element in the array that is less than or equal to the object. + * The input array must be sorted in ascending order according to the {@linkplain Comparable natural ordering} + * of its element. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * + * @param array The sorted array to be searched + * @param valueToFind A comparable object for which we want to find a floor + * @return The index of the floor if it is found. -1 will be returned if no floor was found. + * @throws ClassCastException If the array elements or valueToFind is not comparable + * @throws NullPointerException If array is null or comparing null values is not allowed + */ @SuppressWarnings({"rawtypes", "unchecked"}) public static int floor(final Object[] array, final Object valueToFind) { return floor(array, 0, array.length, valueToFind, Comparator.comparing(v -> ((Comparable) v))); } + /** + * Searches the specified array for the floor of the specified object using binary search algorithm within + * a specified range. + * The floor of a comparable object is the greatest element within the range that is less than or equal to + * the object. + * The input array must be sorted in ascending order according to the {@linkplain Comparable natural ordering} + * of its element within the specified range (other array elements are not checked). + * Passing an array that is unsorted within the specified range (or an array that is sorted in descending order + * within that range) will lead to undefined behavior. + * The range is exclusive from the right end. + * + * @param the class of the objects in the array + * @param array The sorted array to be searched + * @param fromIndex The index of the first element (inclusive) to be searched + * @param toIndex The index of the last element (exclusive) to be searched + * @param valueToFind A comparable object for which we want to find a floor + * @param comparator The comparator by which the array is ordered. + * A {@code null} value indicates that the elements' {@linkplain Comparable natural ordering} + * should be used. + * @return The index of the floor if it is found; -1 will be returned if no floor was found within the + * specified range. + * @throws ClassCastException If the array elements or valueToFind is not comparable + * @throws NullPointerException If array is null or comparing null values is not allowed + * @throws IllegalArgumentException If any of the indices are out of bound + */ public static int floor(final T[] array, final int fromIndex, final int toIndex, final T valueToFind, final Comparator comparator) { + if (comparator == null) { + return ceiling(array, fromIndex, toIndex, valueToFind, + (v1, v2) -> ((Comparable) v1).compareTo((Comparable) v2)); + } Validate.notNull(array); - Validate.notNull(comparator); Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { - return -1; + return INDEX_NOT_FOUND; } int lo = fromIndex; int hi = toIndex - 1; if (comparator.compare(array[lo], valueToFind) > 0) { - return -1; + return INDEX_NOT_FOUND; } if (comparator.compare(array[hi], valueToFind) <= 0) { return hi; } while (lo <= hi) { - final int mid = (lo + hi) / 2; + final int mid = (lo + hi) >>> 1; final int cmp = comparator.compare(array[mid], valueToFind); if (cmp == 0) { return mid; @@ -2040,13 +2348,45 @@ public static int floor(final T[] array, lo = mid + 1; } } - return -1; + return INDEX_NOT_FOUND; } + /** + * Searches the specified array for the floor of the specified int value using binary search + * algorithm. + * The floor of an int value is the greatest element in the array that is smaller than or equal to + * the value. + * The input array must be sorted in ascending order. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * + * @param array The sorted array to be searched + * @param valueToFind The int value for which we want to find a floor + * @return The index of the floor if it is found. -1 will be returned if no floor was found. + * @throws NullPointerException If array is null + */ public static int floor(final int[] array, final int valueToFind) { return floor(array, 0, array.length, valueToFind); } + /** + * Searches the specified array for the floor of the specified int value using binary search + * algorithm within the specified range. + * The floor of an int value within a range is the greatest element within the range that is smaller + * than or equal to the value. + * The input array must be sorted in ascending order within the specified range. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * The range is exclusive from the right end. + * + * @param array The sorted array to be searched + * @param fromIndex The index of the first element (inclusive) to be searched + * @param toIndex The index of the last element (exclusive) to be searched + * @param valueToFind The int value for which we want to find a floor + * @return The index of the floor if it is found. -1 will be returned if no floor was found within the range. + * @throws NullPointerException If array is null + * @throws IllegalArgumentException If any of the indices are out of bound + */ public static int floor(final int[] array, final int fromIndex, final int toIndex, @@ -2055,18 +2395,18 @@ public static int floor(final int[] array, Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { - return -1; + return INDEX_NOT_FOUND; } int lo = fromIndex; int hi = toIndex - 1; if (array[lo] > valueToFind) { - return -1; + return INDEX_NOT_FOUND; } if (array[hi] <= valueToFind) { return hi; } while (lo <= hi) { - final int mid = (lo + hi) / 2; + final int mid = (lo + hi) >>> 1; if (array[mid] == valueToFind) { return mid; } else if (array[mid] > valueToFind) { @@ -2081,13 +2421,45 @@ public static int floor(final int[] array, lo = mid + 1; } } - return -1; + return INDEX_NOT_FOUND; } + /** + * Searches the specified array for the floor of the specified long value using binary search + * algorithm. + * The floor of an long value is the greatest element in the array that is smaller than or equal to + * the value. + * The input array must be sorted in ascending order. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * + * @param array The sorted array to be searched + * @param valueToFind The long value for which we want to find a floor + * @return The index of the floor if it is found. -1 will be returned if no floor was found. + * @throws NullPointerException If array is null + */ public static int floor(final long[] array, final long valueToFind) { return floor(array, 0, array.length, valueToFind); } + /** + * Searches the specified array for the floor of the specified long value using binary search + * algorithm within the specified range. + * The floor of an long value within a range is the greatest element within the range that is smaller + * than or equal to the value. + * The input array must be sorted in ascending order within the specified range. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * The range is exclusive from the right end. + * + * @param array The sorted array to be searched + * @param fromIndex The index of the first element (inclusive) to be searched + * @param toIndex The index of the last element (exclusive) to be searched + * @param valueToFind The long value for which we want to find a floor + * @return The index of the floor if it is found. -1 will be returned if no floor was found within the range. + * @throws NullPointerException If array is null + * @throws IllegalArgumentException If any of the indices are out of bound + */ public static int floor(final long[] array, final int fromIndex, final int toIndex, @@ -2096,18 +2468,18 @@ public static int floor(final long[] array, Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { - return -1; + return INDEX_NOT_FOUND; } int lo = fromIndex; int hi = toIndex - 1; if (array[lo] > valueToFind) { - return -1; + return INDEX_NOT_FOUND; } if (array[hi] <= valueToFind) { return hi; } while (lo <= hi) { - final int mid = (lo + hi) / 2; + final int mid = (lo + hi) >>> 1; if (array[mid] == valueToFind) { return mid; } else if (array[mid] > valueToFind) { @@ -2122,13 +2494,45 @@ public static int floor(final long[] array, lo = mid + 1; } } - return -1; + return INDEX_NOT_FOUND; } + /** + * Searches the specified array for the floor of the specified float value using binary search + * algorithm. + * The floor of an float value is the greatest element in the array that is smaller than or equal to + * the value. + * The input array must be sorted in ascending order. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * + * @param array The sorted array to be searched + * @param valueToFind The float value for which we want to find a floor + * @return The index of the floor if it is found. -1 will be returned if no floor was found. + * @throws NullPointerException If array is null + */ public static int floor(final float[] array, final float valueToFind) { return floor(array, 0, array.length, valueToFind); } + /** + * Searches the specified array for the floor of the specified float value using binary search + * algorithm within the specified range. + * The floor of an float value within a range is the greatest element within the range that is smaller + * than or equal to the value. + * The input array must be sorted in ascending order within the specified range. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * The range is exclusive from the right end. + * + * @param array The sorted array to be searched + * @param fromIndex The index of the first element (inclusive) to be searched + * @param toIndex The index of the last element (exclusive) to be searched + * @param valueToFind The float value for which we want to find a floor + * @return The index of the floor if it is found. -1 will be returned if no floor was found within the range. + * @throws NullPointerException If array is null + * @throws IllegalArgumentException If any of the indices are out of bound + */ public static int floor(final float[] array, final int fromIndex, final int toIndex, @@ -2137,18 +2541,18 @@ public static int floor(final float[] array, Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { - return -1; + return INDEX_NOT_FOUND; } int lo = fromIndex; int hi = toIndex - 1; if (array[lo] > valueToFind) { - return -1; + return INDEX_NOT_FOUND; } if (array[hi] <= valueToFind) { return hi; } while (lo <= hi) { - final int mid = (lo + hi) / 2; + final int mid = (lo + hi) >>> 1; if (array[mid] == valueToFind) { return mid; } else if (array[mid] > valueToFind) { @@ -2163,13 +2567,45 @@ public static int floor(final float[] array, lo = mid + 1; } } - return -1; + return INDEX_NOT_FOUND; } + /** + * Searches the specified array for the floor of the specified double value using binary search + * algorithm. + * The floor of an double value is the greatest element in the array that is smaller than or equal to + * the value. + * The input array must be sorted in ascending order. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * + * @param array The sorted array to be searched + * @param valueToFind The double value for which we want to find a floor + * @return The index of the floor if it is found. -1 will be returned if no floor was found. + * @throws NullPointerException If array is null + */ public static int floor(final double[] array, final double valueToFind) { return floor(array, 0, array.length, valueToFind); } + /** + * Searches the specified array for the floor of the specified double value using binary search + * algorithm within the specified range. + * The floor of an double value within a range is the greatest element within the range that is smaller + * than or equal to the value. + * The input array must be sorted in ascending order within the specified range. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * The range is exclusive from the right end. + * + * @param array The sorted array to be searched + * @param fromIndex The index of the first element (inclusive) to be searched + * @param toIndex The index of the last element (exclusive) to be searched + * @param valueToFind The double value for which we want to find a floor + * @return The index of the floor if it is found. -1 will be returned if no floor was found within the range. + * @throws NullPointerException If array is null + * @throws IllegalArgumentException If any of the indices are out of bound + */ public static int floor(final double[] array, final int fromIndex, final int toIndex, @@ -2178,18 +2614,18 @@ public static int floor(final double[] array, Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { - return -1; + return INDEX_NOT_FOUND; } int lo = fromIndex; int hi = toIndex - 1; if (array[lo] > valueToFind) { - return -1; + return INDEX_NOT_FOUND; } if (array[hi] <= valueToFind) { return hi; } while (lo <= hi) { - final int mid = (lo + hi) / 2; + final int mid = (lo + hi) >>> 1; if (array[mid] == valueToFind) { return mid; } else if (array[mid] > valueToFind) { @@ -2204,13 +2640,45 @@ public static int floor(final double[] array, lo = mid + 1; } } - return -1; + return INDEX_NOT_FOUND; } + /** + * Searches the specified array for the floor of the specified short value using binary search + * algorithm. + * The floor of an short value is the greatest element in the array that is smaller than or equal to + * the value. + * The input array must be sorted in ascending order. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * + * @param array The sorted array to be searched + * @param valueToFind The short value for which we want to find a floor + * @return The index of the floor if it is found. -1 will be returned if no floor was found. + * @throws NullPointerException If array is null + */ public static int floor(final short[] array, final short valueToFind) { return floor(array, 0, array.length, valueToFind); } + /** + * Searches the specified array for the floor of the specified short value using binary search + * algorithm within the specified range. + * The floor of an short value within a range is the greatest element within the range that is smaller + * than or equal to the value. + * The input array must be sorted in ascending order within the specified range. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * The range is exclusive from the right end. + * + * @param array The sorted array to be searched + * @param fromIndex The index of the first element (inclusive) to be searched + * @param toIndex The index of the last element (exclusive) to be searched + * @param valueToFind The short value for which we want to find a floor + * @return The index of the floor if it is found. -1 will be returned if no floor was found within the range. + * @throws NullPointerException If array is null + * @throws IllegalArgumentException If any of the indices are out of bound + */ public static int floor(final short[] array, final int fromIndex, final int toIndex, @@ -2219,18 +2687,18 @@ public static int floor(final short[] array, Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { - return -1; + return INDEX_NOT_FOUND; } int lo = fromIndex; int hi = toIndex - 1; if (array[lo] > valueToFind) { - return -1; + return INDEX_NOT_FOUND; } if (array[hi] <= valueToFind) { return hi; } while (lo <= hi) { - final int mid = (lo + hi) / 2; + final int mid = (lo + hi) >>> 1; if (array[mid] == valueToFind) { return mid; } else if (array[mid] > valueToFind) { @@ -2245,13 +2713,45 @@ public static int floor(final short[] array, lo = mid + 1; } } - return -1; + return INDEX_NOT_FOUND; } + /** + * Searches the specified array for the floor of the specified byte value using binary search + * algorithm. + * The floor of an byte value is the greatest element in the array that is smaller than or equal to + * the value. + * The input array must be sorted in ascending order. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * + * @param array The sorted array to be searched + * @param valueToFind The byte value for which we want to find a floor + * @return The index of the floor if it is found. -1 will be returned if no floor was found. + * @throws NullPointerException If array is null + */ public static int floor(final byte[] array, final byte valueToFind) { return floor(array, 0, array.length, valueToFind); } + /** + * Searches the specified array for the floor of the specified byte value using binary search + * algorithm within the specified range. + * The floor of an byte value within a range is the greatest element within the range that is smaller + * than or equal to the value. + * The input array must be sorted in ascending order within the specified range. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * The range is exclusive from the right end. + * + * @param array The sorted array to be searched + * @param fromIndex The index of the first element (inclusive) to be searched + * @param toIndex The index of the last element (exclusive) to be searched + * @param valueToFind The byte value for which we want to find a floor + * @return The index of the floor if it is found. -1 will be returned if no floor was found within the range. + * @throws NullPointerException If array is null + * @throws IllegalArgumentException If any of the indices are out of bound + */ public static int floor(final byte[] array, final int fromIndex, final int toIndex, @@ -2260,18 +2760,18 @@ public static int floor(final byte[] array, Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { - return -1; + return INDEX_NOT_FOUND; } int lo = fromIndex; int hi = toIndex - 1; if (array[lo] > valueToFind) { - return -1; + return INDEX_NOT_FOUND; } if (array[hi] <= valueToFind) { return hi; } while (lo <= hi) { - final int mid = (lo + hi) / 2; + final int mid = (lo + hi) >>> 1; if (array[mid] == valueToFind) { return mid; } else if (array[mid] > valueToFind) { @@ -2286,13 +2786,45 @@ public static int floor(final byte[] array, lo = mid + 1; } } - return -1; + return INDEX_NOT_FOUND; } + /** + * Searches the specified array for the floor of the specified char value using binary search + * algorithm. + * The floor of an char value is the greatest element in the array that is smaller than or equal to + * the value. + * The input array must be sorted in ascending order. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * + * @param array The sorted array to be searched + * @param valueToFind The char value for which we want to find a floor + * @return The index of the floor if it is found. -1 will be returned if no floor was found. + * @throws NullPointerException If array is null + */ public static int floor(final char[] array, final char valueToFind) { return floor(array, 0, array.length, valueToFind); } + /** + * Searches the specified array for the floor of the specified char value using binary search + * algorithm within the specified range. + * The floor of an char value within a range is the greatest element within the range that is smaller + * than or equal to the value. + * The input array must be sorted in ascending order within the specified range. + * The behavior of the method when passing an unsorted array (or an array that is sorted in descending order) + * is undefined. + * The range is exclusive from the right end. + * + * @param array The sorted array to be searched + * @param fromIndex The index of the first element (inclusive) to be searched + * @param toIndex The index of the last element (exclusive) to be searched + * @param valueToFind The char value for which we want to find a floor + * @return The index of the floor if it is found. -1 will be returned if no floor was found within the range. + * @throws NullPointerException If array is null + * @throws IllegalArgumentException If any of the indices are out of bound + */ public static int floor(final char[] array, final int fromIndex, final int toIndex, @@ -2301,18 +2833,18 @@ public static int floor(final char[] array, Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { - return -1; + return INDEX_NOT_FOUND; } int lo = fromIndex; int hi = toIndex - 1; if (array[lo] > valueToFind) { - return -1; + return INDEX_NOT_FOUND; } if (array[hi] <= valueToFind) { return hi; } while (lo <= hi) { - final int mid = (lo + hi) / 2; + final int mid = (lo + hi) >>> 1; if (array[mid] == valueToFind) { return mid; } else if (array[mid] > valueToFind) { @@ -2327,7 +2859,7 @@ public static int floor(final char[] array, lo = mid + 1; } } - return -1; + return INDEX_NOT_FOUND; } /** diff --git a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java index a68b1f680dd..b856919fc26 100644 --- a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java @@ -368,17 +368,6 @@ void testCeilingNullArray() { assertTrue(succeed); } - @Test - void testCeilingNullComparator() { - boolean succeed = false; - try { - ArrayUtils.ceiling(new Integer[] {1, 2}, 0, 0, 1, null); - } catch (Exception ignored) { - succeed = true; - } - assertTrue(succeed); - } - @Test void testCeilingBoxedNumbers() { final Integer[] integers = {12, 14, 40, 70, 90}; @@ -432,17 +421,6 @@ void testFloorNullArray() { assertTrue(succeed); } - @Test - void testFloorNullComparator() { - boolean succeed = false; - try { - ArrayUtils.floor(new Integer[] {1, 2}, 0, 0, 1, null); - } catch (Exception ignored) { - succeed = true; - } - assertTrue(succeed); - } - @Test void testFloorBoxedNumbers() { final Integer[] integers = {12, 14, 40, 70, 90}; From 20b240ba47254f22cdc5836871dee0389255d372 Mon Sep 17 00:00:00 2001 From: ali-ghanbari Date: Sun, 26 Sep 2021 02:53:57 -0500 Subject: [PATCH 5/5] Refactor --- .../org/apache/commons/lang3/ArrayUtils.java | 696 ++++++++---------- 1 file changed, 300 insertions(+), 396 deletions(-) diff --git a/src/main/java/org/apache/commons/lang3/ArrayUtils.java b/src/main/java/org/apache/commons/lang3/ArrayUtils.java index e439749c05e..e3b49e89e2a 100644 --- a/src/main/java/org/apache/commons/lang3/ArrayUtils.java +++ b/src/main/java/org/apache/commons/lang3/ArrayUtils.java @@ -1700,23 +1700,23 @@ public static int ceiling(final Object[] array, final Object valueToFind) { * @param array The sorted array to be searched * @param fromIndex The index of the first element (inclusive) to be searched * @param toIndex The index of the last element (exclusive) to be searched - * @param valueToFind A comparable object for which we want to find a ceiling + * @param value A comparable object for which we want to find a ceiling * @param comparator The comparator by which the array is ordered. * A {@code null} value indicates that the elements' {@linkplain Comparable natural ordering} * should be used. * @return The index of the ceiling if it is found; -1 will be returned if no ceiling was found within the * specified range. - * @throws ClassCastException If the array elements or valueToFind is not comparable + * @throws ClassCastException If the array elements or value is not comparable * @throws NullPointerException If array is null or comparing null values is not allowed * @throws IllegalArgumentException If any of the indices are out of bound */ public static int ceiling(final T[] array, final int fromIndex, final int toIndex, - final T valueToFind, + final T value, final Comparator comparator) { if (comparator == null) { - return ceiling(array, fromIndex, toIndex, valueToFind, + return ceiling(array, fromIndex, toIndex, value, (v1, v2) -> ((Comparable) v1).compareTo((Comparable) v2)); } Validate.notNull(array); @@ -1725,32 +1725,26 @@ public static int ceiling(final T[] array, if (fromIndex >= toIndex) { return INDEX_NOT_FOUND; } - int lo = fromIndex; - int hi = toIndex - 1; - if (comparator.compare(valueToFind, array[hi]) > 0) { + if (comparator.compare(value, array[toIndex - 1]) > 0) { return INDEX_NOT_FOUND; } - if (comparator.compare(valueToFind, array[lo]) <= 0) { - return lo; + if (comparator.compare(value, array[fromIndex]) <= 0) { + return fromIndex; } - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - final int cmp = comparator.compare(array[mid], valueToFind); - if (cmp == 0) { + final int mid = (fromIndex + toIndex - 1) >>> 1; + final int cmp = comparator.compare(array[mid], value); + if (cmp == 0) { + return mid; + } else if (cmp > 0) { + if (fromIndex <= mid - 1 && comparator.compare(array[mid - 1], value) < 0) { return mid; - } else if (cmp > 0) { - if (lo <= mid - 1 && comparator.compare(array[mid - 1], valueToFind) < 0) { - return mid; - } - hi = mid - 1; - } else { - if (mid + 1 <= hi && comparator.compare(array[mid + 1], valueToFind) >= 0) { - return mid + 1; - } - lo = mid + 1; } + return ceiling(array, fromIndex, mid, value, comparator); } - return INDEX_NOT_FOUND; + if (mid + 1 <= toIndex - 1 && comparator.compare(array[mid + 1], value) >= 0) { + return mid + 1; + } + return ceiling(array, mid + 1, toIndex, value, comparator); } /** @@ -1763,12 +1757,12 @@ public static int ceiling(final T[] array, * is undefined. * * @param array The sorted array to be searched - * @param valueToFind The int value for which we want to find a ceiling + * @param value The int value for which we want to find a ceiling * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found. * @throws NullPointerException If array is null */ - public static int ceiling(final int[] array, final int valueToFind) { - return ceiling(array, 0, array.length, valueToFind); + public static int ceiling(final int[] array, final int value) { + return ceiling(array, 0, array.length, value); } /** @@ -1784,7 +1778,7 @@ public static int ceiling(final int[] array, final int valueToFind) { * @param array The sorted array to be searched * @param fromIndex The index of the first element (inclusive) to be searched * @param toIndex The index of the last element (exclusive) to be searched - * @param valueToFind The int value for which we want to find a ceiling + * @param value The int value for which we want to find a ceiling * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found within the range. * @throws NullPointerException If array is null * @throws IllegalArgumentException If any of the indices are out of bound @@ -1792,38 +1786,32 @@ public static int ceiling(final int[] array, final int valueToFind) { public static int ceiling(final int[] array, final int fromIndex, final int toIndex, - final int valueToFind) { + final int value) { Validate.notNull(array); Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { return INDEX_NOT_FOUND; } - int lo = fromIndex; - int hi = toIndex - 1; - if (valueToFind > array[hi]) { + if (value > array[toIndex - 1]) { return INDEX_NOT_FOUND; } - if (valueToFind <= array[lo]) { - return lo; + if (value <= array[fromIndex]) { + return fromIndex; } - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - if (array[mid] == valueToFind) { + final int mid = (fromIndex + toIndex - 1) >>> 1; + if (array[mid] == value) { + return mid; + } else if (array[mid] > value) { + if (fromIndex <= mid - 1 && array[mid - 1] < value) { return mid; - } else if (array[mid] > valueToFind) { - if (lo <= mid - 1 && array[mid - 1] < valueToFind) { - return mid; - } - hi = mid - 1; - } else { - if (mid + 1 <= hi && array[mid + 1] >= valueToFind) { - return mid + 1; - } - lo = mid + 1; } + return ceiling(array, fromIndex, mid, value); } - return INDEX_NOT_FOUND; + if (mid + 1 <= toIndex - 1 && array[mid + 1] >= value) { + return mid + 1; + } + return ceiling(array, mid + 1, toIndex, value); } /** @@ -1836,12 +1824,12 @@ public static int ceiling(final int[] array, * is undefined. * * @param array The sorted array to be searched - * @param valueToFind The long value for which we want to find a ceiling + * @param value The long value for which we want to find a ceiling * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found. * @throws NullPointerException If array is null */ - public static int ceiling(final long[] array, final long valueToFind) { - return ceiling(array, 0, array.length, valueToFind); + public static int ceiling(final long[] array, final long value) { + return ceiling(array, 0, array.length, value); } /** @@ -1857,7 +1845,7 @@ public static int ceiling(final long[] array, final long valueToFind) { * @param array The sorted array to be searched * @param fromIndex The index of the first element (inclusive) to be searched * @param toIndex The index of the last element (exclusive) to be searched - * @param valueToFind The long value for which we want to find a ceiling + * @param value The long value for which we want to find a ceiling * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found within the range. * @throws NullPointerException If array is null * @throws IllegalArgumentException If any of the indices are out of bound @@ -1865,38 +1853,32 @@ public static int ceiling(final long[] array, final long valueToFind) { public static int ceiling(final long[] array, final int fromIndex, final int toIndex, - final long valueToFind) { + final long value) { Validate.notNull(array); Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { return INDEX_NOT_FOUND; } - int lo = fromIndex; - int hi = toIndex - 1; - if (valueToFind > array[hi]) { + if (value > array[toIndex - 1]) { return INDEX_NOT_FOUND; } - if (valueToFind <= array[lo]) { - return lo; + if (value <= array[fromIndex]) { + return fromIndex; } - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - if (array[mid] == valueToFind) { + final int mid = (fromIndex + toIndex - 1) >>> 1; + if (array[mid] == value) { + return mid; + } else if (array[mid] > value) { + if (fromIndex <= mid - 1 && array[mid - 1] < value) { return mid; - } else if (array[mid] > valueToFind) { - if (lo <= mid - 1 && array[mid - 1] < valueToFind) { - return mid; - } - hi = mid - 1; - } else { - if (mid + 1 <= hi && array[mid + 1] >= valueToFind) { - return mid + 1; - } - lo = mid + 1; } + return ceiling(array, fromIndex, mid, value); } - return INDEX_NOT_FOUND; + if (mid + 1 <= toIndex - 1 && array[mid + 1] >= value) { + return mid + 1; + } + return ceiling(array, mid + 1, toIndex, value); } /** @@ -1909,12 +1891,12 @@ public static int ceiling(final long[] array, * is undefined. * * @param array The sorted array to be searched - * @param valueToFind The short value for which we want to find a ceiling + * @param value The short value for which we want to find a ceiling * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found. * @throws NullPointerException If array is null */ - public static int ceiling(final short[] array, final short valueToFind) { - return ceiling(array, 0, array.length, valueToFind); + public static int ceiling(final short[] array, final short value) { + return ceiling(array, 0, array.length, value); } /** @@ -1930,7 +1912,7 @@ public static int ceiling(final short[] array, final short valueToFind) { * @param array The sorted array to be searched * @param fromIndex The index of the first element (inclusive) to be searched * @param toIndex The index of the last element (exclusive) to be searched - * @param valueToFind The short value for which we want to find a ceiling + * @param value The short value for which we want to find a ceiling * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found within the range. * @throws NullPointerException If array is null * @throws IllegalArgumentException If any of the indices are out of bound @@ -1938,38 +1920,32 @@ public static int ceiling(final short[] array, final short valueToFind) { public static int ceiling(final short[] array, final int fromIndex, final int toIndex, - final short valueToFind) { + final short value) { Validate.notNull(array); Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { return INDEX_NOT_FOUND; } - int lo = fromIndex; - int hi = toIndex - 1; - if (valueToFind > array[hi]) { + if (value > array[toIndex - 1]) { return INDEX_NOT_FOUND; } - if (valueToFind <= array[lo]) { - return lo; + if (value <= array[fromIndex]) { + return fromIndex; } - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - if (array[mid] == valueToFind) { + final int mid = (fromIndex + toIndex - 1) >>> 1; + if (array[mid] == value) { + return mid; + } else if (array[mid] > value) { + if (fromIndex <= mid - 1 && array[mid - 1] < value) { return mid; - } else if (array[mid] > valueToFind) { - if (lo <= mid - 1 && array[mid - 1] < valueToFind) { - return mid; - } - hi = mid - 1; - } else { - if (mid + 1 <= hi && array[mid + 1] >= valueToFind) { - return mid + 1; - } - lo = mid + 1; } + return ceiling(array, fromIndex, mid, value); } - return INDEX_NOT_FOUND; + if (mid + 1 <= toIndex - 1 && array[mid + 1] >= value) { + return mid + 1; + } + return ceiling(array, mid + 1, toIndex, value); } /** @@ -1982,12 +1958,12 @@ public static int ceiling(final short[] array, * is undefined. * * @param array The sorted array to be searched - * @param valueToFind The byte value for which we want to find a ceiling + * @param value The byte value for which we want to find a ceiling * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found. * @throws NullPointerException If array is null */ - public static int ceiling(final byte[] array, final byte valueToFind) { - return ceiling(array, 0, array.length, valueToFind); + public static int ceiling(final byte[] array, final byte value) { + return ceiling(array, 0, array.length, value); } /** @@ -2003,7 +1979,7 @@ public static int ceiling(final byte[] array, final byte valueToFind) { * @param array The sorted array to be searched * @param fromIndex The index of the first element (inclusive) to be searched * @param toIndex The index of the last element (exclusive) to be searched - * @param valueToFind The byte value for which we want to find a ceiling + * @param value The byte value for which we want to find a ceiling * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found within the range. * @throws NullPointerException If array is null * @throws IllegalArgumentException If any of the indices are out of bound @@ -2011,38 +1987,32 @@ public static int ceiling(final byte[] array, final byte valueToFind) { public static int ceiling(final byte[] array, final int fromIndex, final int toIndex, - final byte valueToFind) { + final byte value) { Validate.notNull(array); Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { return INDEX_NOT_FOUND; } - int lo = fromIndex; - int hi = toIndex - 1; - if (valueToFind > array[hi]) { + if (value > array[toIndex - 1]) { return INDEX_NOT_FOUND; } - if (valueToFind <= array[lo]) { - return lo; + if (value <= array[fromIndex]) { + return fromIndex; } - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - if (array[mid] == valueToFind) { + final int mid = (fromIndex + toIndex - 1) >>> 1; + if (array[mid] == value) { + return mid; + } else if (array[mid] > value) { + if (fromIndex <= mid - 1 && array[mid - 1] < value) { return mid; - } else if (array[mid] > valueToFind) { - if (lo <= mid - 1 && array[mid - 1] < valueToFind) { - return mid; - } - hi = mid - 1; - } else { - if (mid + 1 <= hi && array[mid + 1] >= valueToFind) { - return mid + 1; - } - lo = mid + 1; } + return ceiling(array, fromIndex, mid, value); } - return INDEX_NOT_FOUND; + if (mid + 1 <= toIndex - 1 && array[mid + 1] >= value) { + return mid + 1; + } + return ceiling(array, mid + 1, toIndex, value); } /** @@ -2055,12 +2025,12 @@ public static int ceiling(final byte[] array, * is undefined. * * @param array The sorted array to be searched - * @param valueToFind The char value for which we want to find a ceiling + * @param value The char value for which we want to find a ceiling * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found. * @throws NullPointerException If array is null */ - public static int ceiling(final char[] array, final char valueToFind) { - return ceiling(array, 0, array.length, valueToFind); + public static int ceiling(final char[] array, final char value) { + return ceiling(array, 0, array.length, value); } /** @@ -2076,7 +2046,7 @@ public static int ceiling(final char[] array, final char valueToFind) { * @param array The sorted array to be searched * @param fromIndex The index of the first element (inclusive) to be searched * @param toIndex The index of the last element (exclusive) to be searched - * @param valueToFind The char value for which we want to find a ceiling + * @param value The char value for which we want to find a ceiling * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found within the range. * @throws NullPointerException If array is null * @throws IllegalArgumentException If any of the indices are out of bound @@ -2084,38 +2054,32 @@ public static int ceiling(final char[] array, final char valueToFind) { public static int ceiling(final char[] array, final int fromIndex, final int toIndex, - final char valueToFind) { + final char value) { Validate.notNull(array); Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { return INDEX_NOT_FOUND; } - int lo = fromIndex; - int hi = toIndex - 1; - if (valueToFind > array[hi]) { + if (value > array[toIndex - 1]) { return INDEX_NOT_FOUND; } - if (valueToFind <= array[lo]) { - return lo; + if (value <= array[fromIndex]) { + return fromIndex; } - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - if (array[mid] == valueToFind) { + final int mid = (fromIndex + toIndex - 1) >>> 1; + if (array[mid] == value) { + return mid; + } else if (array[mid] > value) { + if (fromIndex <= mid - 1 && array[mid - 1] < value) { return mid; - } else if (array[mid] > valueToFind) { - if (lo <= mid - 1 && array[mid - 1] < valueToFind) { - return mid; - } - hi = mid - 1; - } else { - if (mid + 1 <= hi && array[mid + 1] >= valueToFind) { - return mid + 1; - } - lo = mid + 1; } + return ceiling(array, fromIndex, mid, value); } - return INDEX_NOT_FOUND; + if (mid + 1 <= toIndex - 1 && array[mid + 1] >= value) { + return mid + 1; + } + return ceiling(array, mid + 1, toIndex, value); } /** @@ -2128,12 +2092,12 @@ public static int ceiling(final char[] array, * is undefined. * * @param array The sorted array to be searched - * @param valueToFind The float value for which we want to find a ceiling + * @param value The float value for which we want to find a ceiling * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found. * @throws NullPointerException If array is null */ - public static int ceiling(final float[] array, final float valueToFind) { - return ceiling(array, 0, array.length, valueToFind); + public static int ceiling(final float[] array, final float value) { + return ceiling(array, 0, array.length, value); } /** @@ -2149,7 +2113,7 @@ public static int ceiling(final float[] array, final float valueToFind) { * @param array The sorted array to be searched * @param fromIndex The index of the first element (inclusive) to be searched * @param toIndex The index of the last element (exclusive) to be searched - * @param valueToFind The float value for which we want to find a ceiling + * @param value The float value for which we want to find a ceiling * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found within the range. * @throws NullPointerException If array is null * @throws IllegalArgumentException If any of the indices are out of bound @@ -2157,38 +2121,32 @@ public static int ceiling(final float[] array, final float valueToFind) { public static int ceiling(final float[] array, final int fromIndex, final int toIndex, - final float valueToFind) { + final float value) { Validate.notNull(array); Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { return INDEX_NOT_FOUND; } - int lo = fromIndex; - int hi = toIndex - 1; - if (valueToFind > array[hi]) { + if (value > array[toIndex - 1]) { return INDEX_NOT_FOUND; } - if (valueToFind <= array[lo]) { - return lo; + if (value <= array[fromIndex]) { + return fromIndex; } - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - if (array[mid] == valueToFind) { + final int mid = (fromIndex + toIndex - 1) >>> 1; + if (array[mid] == value) { + return mid; + } else if (array[mid] > value) { + if (fromIndex <= mid - 1 && array[mid - 1] < value) { return mid; - } else if (array[mid] > valueToFind) { - if (lo <= mid - 1 && array[mid - 1] < valueToFind) { - return mid; - } - hi = mid - 1; - } else { - if (mid + 1 <= hi && array[mid + 1] >= valueToFind) { - return mid + 1; - } - lo = mid + 1; } + return ceiling(array, fromIndex, mid, value); } - return INDEX_NOT_FOUND; + if (mid + 1 <= toIndex - 1 && array[mid + 1] >= value) { + return mid + 1; + } + return ceiling(array, mid + 1, toIndex, value); } /** @@ -2201,12 +2159,12 @@ public static int ceiling(final float[] array, * is undefined. * * @param array The sorted array to be searched - * @param valueToFind The double value for which we want to find a ceiling + * @param value The double value for which we want to find a ceiling * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found. * @throws NullPointerException If array is null */ - public static int ceiling(final double[] array, final double valueToFind) { - return ceiling(array, 0, array.length, valueToFind); + public static int ceiling(final double[] array, final double value) { + return ceiling(array, 0, array.length, value); } /** @@ -2222,7 +2180,7 @@ public static int ceiling(final double[] array, final double valueToFind) { * @param array The sorted array to be searched * @param fromIndex The index of the first element (inclusive) to be searched * @param toIndex The index of the last element (exclusive) to be searched - * @param valueToFind The double value for which we want to find a ceiling + * @param value The double value for which we want to find a ceiling * @return The index of the ceiling if it is found. -1 will be returned if no ceiling was found within the range. * @throws NullPointerException If array is null * @throws IllegalArgumentException If any of the indices are out of bound @@ -2230,38 +2188,32 @@ public static int ceiling(final double[] array, final double valueToFind) { public static int ceiling(final double[] array, final int fromIndex, final int toIndex, - final double valueToFind) { + final double value) { Validate.notNull(array); Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { return INDEX_NOT_FOUND; } - int lo = fromIndex; - int hi = toIndex - 1; - if (valueToFind > array[hi]) { + if (value > array[toIndex - 1]) { return INDEX_NOT_FOUND; } - if (valueToFind <= array[lo]) { - return lo; + if (value <= array[fromIndex]) { + return fromIndex; } - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - if (array[mid] == valueToFind) { + final int mid = (fromIndex + toIndex - 1) >>> 1; + if (array[mid] == value) { + return mid; + } else if (array[mid] > value) { + if (fromIndex <= mid - 1 && array[mid - 1] < value) { return mid; - } else if (array[mid] > valueToFind) { - if (lo <= mid - 1 && array[mid - 1] < valueToFind) { - return mid; - } - hi = mid - 1; - } else { - if (mid + 1 <= hi && array[mid + 1] >= valueToFind) { - return mid + 1; - } - lo = mid + 1; } + return ceiling(array, fromIndex, mid, value); } - return INDEX_NOT_FOUND; + if (mid + 1 <= toIndex - 1 && array[mid + 1] >= value) { + return mid + 1; + } + return ceiling(array, mid + 1, toIndex, value); } /** @@ -2273,14 +2225,14 @@ public static int ceiling(final double[] array, * is undefined. * * @param array The sorted array to be searched - * @param valueToFind A comparable object for which we want to find a floor + * @param value A comparable object for which we want to find a floor * @return The index of the floor if it is found. -1 will be returned if no floor was found. - * @throws ClassCastException If the array elements or valueToFind is not comparable + * @throws ClassCastException If the array elements or value is not comparable * @throws NullPointerException If array is null or comparing null values is not allowed */ @SuppressWarnings({"rawtypes", "unchecked"}) - public static int floor(final Object[] array, final Object valueToFind) { - return floor(array, 0, array.length, valueToFind, Comparator.comparing(v -> ((Comparable) v))); + public static int floor(final Object[] array, final Object value) { + return floor(array, 0, array.length, value, Comparator.comparing(v -> ((Comparable) v))); } /** @@ -2298,23 +2250,23 @@ public static int floor(final Object[] array, final Object valueToFind) { * @param array The sorted array to be searched * @param fromIndex The index of the first element (inclusive) to be searched * @param toIndex The index of the last element (exclusive) to be searched - * @param valueToFind A comparable object for which we want to find a floor + * @param value A comparable object for which we want to find a floor * @param comparator The comparator by which the array is ordered. * A {@code null} value indicates that the elements' {@linkplain Comparable natural ordering} * should be used. * @return The index of the floor if it is found; -1 will be returned if no floor was found within the * specified range. - * @throws ClassCastException If the array elements or valueToFind is not comparable + * @throws ClassCastException If the array elements or value is not comparable * @throws NullPointerException If array is null or comparing null values is not allowed * @throws IllegalArgumentException If any of the indices are out of bound */ public static int floor(final T[] array, final int fromIndex, final int toIndex, - final T valueToFind, + final T value, final Comparator comparator) { if (comparator == null) { - return ceiling(array, fromIndex, toIndex, valueToFind, + return ceiling(array, fromIndex, toIndex, value, (v1, v2) -> ((Comparable) v1).compareTo((Comparable) v2)); } Validate.notNull(array); @@ -2323,32 +2275,26 @@ public static int floor(final T[] array, if (fromIndex >= toIndex) { return INDEX_NOT_FOUND; } - int lo = fromIndex; - int hi = toIndex - 1; - if (comparator.compare(array[lo], valueToFind) > 0) { + if (comparator.compare(array[fromIndex], value) > 0) { return INDEX_NOT_FOUND; } - if (comparator.compare(array[hi], valueToFind) <= 0) { - return hi; + if (comparator.compare(array[toIndex - 1], value) <= 0) { + return toIndex - 1; } - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - final int cmp = comparator.compare(array[mid], valueToFind); - if (cmp == 0) { - return mid; - } else if (cmp > 0) { - if (lo <= mid - 1 && comparator.compare(array[mid - 1], valueToFind) <= 0) { - return mid - 1; - } - hi = mid - 1; - } else { - if (mid + 1 <= hi && comparator.compare(array[mid + 1], valueToFind) > 0) { - return mid; - } - lo = mid + 1; + final int mid = (fromIndex + toIndex - 1) >>> 1; + final int cmp = comparator.compare(array[mid], value); + if (cmp == 0) { + return mid; + } else if (cmp > 0) { + if (fromIndex <= mid - 1 && comparator.compare(array[mid - 1], value) <= 0) { + return mid - 1; } + return floor(array, fromIndex, mid, value, comparator); } - return INDEX_NOT_FOUND; + if (mid + 1 <= toIndex - 1 && comparator.compare(array[mid + 1], value) > 0) { + return mid; + } + return floor(array, mid + 1, toIndex, value, comparator); } /** @@ -2361,12 +2307,12 @@ public static int floor(final T[] array, * is undefined. * * @param array The sorted array to be searched - * @param valueToFind The int value for which we want to find a floor + * @param value The int value for which we want to find a floor * @return The index of the floor if it is found. -1 will be returned if no floor was found. * @throws NullPointerException If array is null */ - public static int floor(final int[] array, final int valueToFind) { - return floor(array, 0, array.length, valueToFind); + public static int floor(final int[] array, final int value) { + return floor(array, 0, array.length, value); } /** @@ -2382,7 +2328,7 @@ public static int floor(final int[] array, final int valueToFind) { * @param array The sorted array to be searched * @param fromIndex The index of the first element (inclusive) to be searched * @param toIndex The index of the last element (exclusive) to be searched - * @param valueToFind The int value for which we want to find a floor + * @param value The int value for which we want to find a floor * @return The index of the floor if it is found. -1 will be returned if no floor was found within the range. * @throws NullPointerException If array is null * @throws IllegalArgumentException If any of the indices are out of bound @@ -2390,38 +2336,32 @@ public static int floor(final int[] array, final int valueToFind) { public static int floor(final int[] array, final int fromIndex, final int toIndex, - final int valueToFind) { + final int value) { Validate.notNull(array); Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { return INDEX_NOT_FOUND; } - int lo = fromIndex; - int hi = toIndex - 1; - if (array[lo] > valueToFind) { + if (array[fromIndex] > value) { return INDEX_NOT_FOUND; } - if (array[hi] <= valueToFind) { - return hi; + if (array[toIndex - 1] <= value) { + return toIndex - 1; } - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - if (array[mid] == valueToFind) { - return mid; - } else if (array[mid] > valueToFind) { - if (lo <= mid - 1 && array[mid - 1] <= valueToFind) { - return mid - 1; - } - hi = mid - 1; - } else { - if (mid + 1 <= hi && array[mid + 1] > valueToFind) { - return mid; - } - lo = mid + 1; + final int mid = (fromIndex + toIndex - 1) >>> 1; + if (array[mid] == value) { + return mid; + } else if (array[mid] > value) { + if (fromIndex <= mid - 1 && array[mid - 1] <= value) { + return mid - 1; } + return floor(array, fromIndex, mid, value); } - return INDEX_NOT_FOUND; + if (mid + 1 <= toIndex - 1 && array[mid + 1] > value) { + return mid; + } + return floor(array, mid + 1, toIndex, value); } /** @@ -2434,12 +2374,12 @@ public static int floor(final int[] array, * is undefined. * * @param array The sorted array to be searched - * @param valueToFind The long value for which we want to find a floor + * @param value The long value for which we want to find a floor * @return The index of the floor if it is found. -1 will be returned if no floor was found. * @throws NullPointerException If array is null */ - public static int floor(final long[] array, final long valueToFind) { - return floor(array, 0, array.length, valueToFind); + public static int floor(final long[] array, final long value) { + return floor(array, 0, array.length, value); } /** @@ -2455,7 +2395,7 @@ public static int floor(final long[] array, final long valueToFind) { * @param array The sorted array to be searched * @param fromIndex The index of the first element (inclusive) to be searched * @param toIndex The index of the last element (exclusive) to be searched - * @param valueToFind The long value for which we want to find a floor + * @param value The long value for which we want to find a floor * @return The index of the floor if it is found. -1 will be returned if no floor was found within the range. * @throws NullPointerException If array is null * @throws IllegalArgumentException If any of the indices are out of bound @@ -2463,38 +2403,32 @@ public static int floor(final long[] array, final long valueToFind) { public static int floor(final long[] array, final int fromIndex, final int toIndex, - final long valueToFind) { + final long value) { Validate.notNull(array); Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { return INDEX_NOT_FOUND; } - int lo = fromIndex; - int hi = toIndex - 1; - if (array[lo] > valueToFind) { + if (array[fromIndex] > value) { return INDEX_NOT_FOUND; } - if (array[hi] <= valueToFind) { - return hi; + if (array[toIndex - 1] <= value) { + return toIndex - 1; } - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - if (array[mid] == valueToFind) { - return mid; - } else if (array[mid] > valueToFind) { - if (lo <= mid - 1 && array[mid - 1] <= valueToFind) { - return mid - 1; - } - hi = mid - 1; - } else { - if (mid + 1 <= hi && array[mid + 1] > valueToFind) { - return mid; - } - lo = mid + 1; + final int mid = (fromIndex + toIndex - 1) >>> 1; + if (array[mid] == value) { + return mid; + } else if (array[mid] > value) { + if (fromIndex <= mid - 1 && array[mid - 1] <= value) { + return mid - 1; } + return floor(array, fromIndex, mid, value); } - return INDEX_NOT_FOUND; + if (mid + 1 <= toIndex - 1 && array[mid + 1] > value) { + return mid; + } + return floor(array, mid + 1, toIndex, value); } /** @@ -2507,12 +2441,12 @@ public static int floor(final long[] array, * is undefined. * * @param array The sorted array to be searched - * @param valueToFind The float value for which we want to find a floor + * @param value The float value for which we want to find a floor * @return The index of the floor if it is found. -1 will be returned if no floor was found. * @throws NullPointerException If array is null */ - public static int floor(final float[] array, final float valueToFind) { - return floor(array, 0, array.length, valueToFind); + public static int floor(final float[] array, final float value) { + return floor(array, 0, array.length, value); } /** @@ -2528,7 +2462,7 @@ public static int floor(final float[] array, final float valueToFind) { * @param array The sorted array to be searched * @param fromIndex The index of the first element (inclusive) to be searched * @param toIndex The index of the last element (exclusive) to be searched - * @param valueToFind The float value for which we want to find a floor + * @param value The float value for which we want to find a floor * @return The index of the floor if it is found. -1 will be returned if no floor was found within the range. * @throws NullPointerException If array is null * @throws IllegalArgumentException If any of the indices are out of bound @@ -2536,38 +2470,32 @@ public static int floor(final float[] array, final float valueToFind) { public static int floor(final float[] array, final int fromIndex, final int toIndex, - final float valueToFind) { + final float value) { Validate.notNull(array); Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { return INDEX_NOT_FOUND; } - int lo = fromIndex; - int hi = toIndex - 1; - if (array[lo] > valueToFind) { + if (array[fromIndex] > value) { return INDEX_NOT_FOUND; } - if (array[hi] <= valueToFind) { - return hi; + if (array[toIndex - 1] <= value) { + return toIndex - 1; } - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - if (array[mid] == valueToFind) { - return mid; - } else if (array[mid] > valueToFind) { - if (lo <= mid - 1 && array[mid - 1] <= valueToFind) { - return mid - 1; - } - hi = mid - 1; - } else { - if (mid + 1 <= hi && array[mid + 1] > valueToFind) { - return mid; - } - lo = mid + 1; + final int mid = (fromIndex + toIndex - 1) >>> 1; + if (array[mid] == value) { + return mid; + } else if (array[mid] > value) { + if (fromIndex <= mid - 1 && array[mid - 1] <= value) { + return mid - 1; } + return floor(array, fromIndex, mid, value); } - return INDEX_NOT_FOUND; + if (mid + 1 <= toIndex - 1 && array[mid + 1] > value) { + return mid; + } + return floor(array, mid + 1, toIndex, value); } /** @@ -2580,12 +2508,12 @@ public static int floor(final float[] array, * is undefined. * * @param array The sorted array to be searched - * @param valueToFind The double value for which we want to find a floor + * @param value The double value for which we want to find a floor * @return The index of the floor if it is found. -1 will be returned if no floor was found. * @throws NullPointerException If array is null */ - public static int floor(final double[] array, final double valueToFind) { - return floor(array, 0, array.length, valueToFind); + public static int floor(final double[] array, final double value) { + return floor(array, 0, array.length, value); } /** @@ -2601,7 +2529,7 @@ public static int floor(final double[] array, final double valueToFind) { * @param array The sorted array to be searched * @param fromIndex The index of the first element (inclusive) to be searched * @param toIndex The index of the last element (exclusive) to be searched - * @param valueToFind The double value for which we want to find a floor + * @param value The double value for which we want to find a floor * @return The index of the floor if it is found. -1 will be returned if no floor was found within the range. * @throws NullPointerException If array is null * @throws IllegalArgumentException If any of the indices are out of bound @@ -2609,38 +2537,32 @@ public static int floor(final double[] array, final double valueToFind) { public static int floor(final double[] array, final int fromIndex, final int toIndex, - final double valueToFind) { + final double value) { Validate.notNull(array); Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { return INDEX_NOT_FOUND; } - int lo = fromIndex; - int hi = toIndex - 1; - if (array[lo] > valueToFind) { + if (array[fromIndex] > value) { return INDEX_NOT_FOUND; } - if (array[hi] <= valueToFind) { - return hi; + if (array[toIndex - 1] <= value) { + return toIndex - 1; } - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - if (array[mid] == valueToFind) { - return mid; - } else if (array[mid] > valueToFind) { - if (lo <= mid - 1 && array[mid - 1] <= valueToFind) { - return mid - 1; - } - hi = mid - 1; - } else { - if (mid + 1 <= hi && array[mid + 1] > valueToFind) { - return mid; - } - lo = mid + 1; + final int mid = (fromIndex + toIndex - 1) >>> 1; + if (array[mid] == value) { + return mid; + } else if (array[mid] > value) { + if (fromIndex <= mid - 1 && array[mid - 1] <= value) { + return mid - 1; } + return floor(array, fromIndex, mid, value); } - return INDEX_NOT_FOUND; + if (mid + 1 <= toIndex - 1 && array[mid + 1] > value) { + return mid; + } + return floor(array, mid + 1, toIndex, value); } /** @@ -2653,12 +2575,12 @@ public static int floor(final double[] array, * is undefined. * * @param array The sorted array to be searched - * @param valueToFind The short value for which we want to find a floor + * @param value The short value for which we want to find a floor * @return The index of the floor if it is found. -1 will be returned if no floor was found. * @throws NullPointerException If array is null */ - public static int floor(final short[] array, final short valueToFind) { - return floor(array, 0, array.length, valueToFind); + public static int floor(final short[] array, final short value) { + return floor(array, 0, array.length, value); } /** @@ -2674,7 +2596,7 @@ public static int floor(final short[] array, final short valueToFind) { * @param array The sorted array to be searched * @param fromIndex The index of the first element (inclusive) to be searched * @param toIndex The index of the last element (exclusive) to be searched - * @param valueToFind The short value for which we want to find a floor + * @param value The short value for which we want to find a floor * @return The index of the floor if it is found. -1 will be returned if no floor was found within the range. * @throws NullPointerException If array is null * @throws IllegalArgumentException If any of the indices are out of bound @@ -2682,38 +2604,32 @@ public static int floor(final short[] array, final short valueToFind) { public static int floor(final short[] array, final int fromIndex, final int toIndex, - final short valueToFind) { + final short value) { Validate.notNull(array); Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { return INDEX_NOT_FOUND; } - int lo = fromIndex; - int hi = toIndex - 1; - if (array[lo] > valueToFind) { + if (array[fromIndex] > value) { return INDEX_NOT_FOUND; } - if (array[hi] <= valueToFind) { - return hi; + if (array[toIndex - 1] <= value) { + return toIndex - 1; } - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - if (array[mid] == valueToFind) { - return mid; - } else if (array[mid] > valueToFind) { - if (lo <= mid - 1 && array[mid - 1] <= valueToFind) { - return mid - 1; - } - hi = mid - 1; - } else { - if (mid + 1 <= hi && array[mid + 1] > valueToFind) { - return mid; - } - lo = mid + 1; + final int mid = (fromIndex + toIndex - 1) >>> 1; + if (array[mid] == value) { + return mid; + } else if (array[mid] > value) { + if (fromIndex <= mid - 1 && array[mid - 1] <= value) { + return mid - 1; } + return floor(array, fromIndex, mid, value); } - return INDEX_NOT_FOUND; + if (mid + 1 <= toIndex - 1 && array[mid + 1] > value) { + return mid; + } + return floor(array, mid + 1, toIndex, value); } /** @@ -2726,12 +2642,12 @@ public static int floor(final short[] array, * is undefined. * * @param array The sorted array to be searched - * @param valueToFind The byte value for which we want to find a floor + * @param value The byte value for which we want to find a floor * @return The index of the floor if it is found. -1 will be returned if no floor was found. * @throws NullPointerException If array is null */ - public static int floor(final byte[] array, final byte valueToFind) { - return floor(array, 0, array.length, valueToFind); + public static int floor(final byte[] array, final byte value) { + return floor(array, 0, array.length, value); } /** @@ -2747,7 +2663,7 @@ public static int floor(final byte[] array, final byte valueToFind) { * @param array The sorted array to be searched * @param fromIndex The index of the first element (inclusive) to be searched * @param toIndex The index of the last element (exclusive) to be searched - * @param valueToFind The byte value for which we want to find a floor + * @param value The byte value for which we want to find a floor * @return The index of the floor if it is found. -1 will be returned if no floor was found within the range. * @throws NullPointerException If array is null * @throws IllegalArgumentException If any of the indices are out of bound @@ -2755,38 +2671,32 @@ public static int floor(final byte[] array, final byte valueToFind) { public static int floor(final byte[] array, final int fromIndex, final int toIndex, - final byte valueToFind) { + final byte value) { Validate.notNull(array); Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { return INDEX_NOT_FOUND; } - int lo = fromIndex; - int hi = toIndex - 1; - if (array[lo] > valueToFind) { + if (array[fromIndex] > value) { return INDEX_NOT_FOUND; } - if (array[hi] <= valueToFind) { - return hi; + if (array[toIndex - 1] <= value) { + return toIndex - 1; } - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - if (array[mid] == valueToFind) { - return mid; - } else if (array[mid] > valueToFind) { - if (lo <= mid - 1 && array[mid - 1] <= valueToFind) { - return mid - 1; - } - hi = mid - 1; - } else { - if (mid + 1 <= hi && array[mid + 1] > valueToFind) { - return mid; - } - lo = mid + 1; + final int mid = (fromIndex + toIndex - 1) >>> 1; + if (array[mid] == value) { + return mid; + } else if (array[mid] > value) { + if (fromIndex <= mid - 1 && array[mid - 1] <= value) { + return mid - 1; } + return floor(array, fromIndex, mid, value); } - return INDEX_NOT_FOUND; + if (mid + 1 <= toIndex - 1 && array[mid + 1] > value) { + return mid; + } + return floor(array, mid + 1, toIndex, value); } /** @@ -2799,12 +2709,12 @@ public static int floor(final byte[] array, * is undefined. * * @param array The sorted array to be searched - * @param valueToFind The char value for which we want to find a floor + * @param value The char value for which we want to find a floor * @return The index of the floor if it is found. -1 will be returned if no floor was found. * @throws NullPointerException If array is null */ - public static int floor(final char[] array, final char valueToFind) { - return floor(array, 0, array.length, valueToFind); + public static int floor(final char[] array, final char value) { + return floor(array, 0, array.length, value); } /** @@ -2820,7 +2730,7 @@ public static int floor(final char[] array, final char valueToFind) { * @param array The sorted array to be searched * @param fromIndex The index of the first element (inclusive) to be searched * @param toIndex The index of the last element (exclusive) to be searched - * @param valueToFind The char value for which we want to find a floor + * @param value The char value for which we want to find a floor * @return The index of the floor if it is found. -1 will be returned if no floor was found within the range. * @throws NullPointerException If array is null * @throws IllegalArgumentException If any of the indices are out of bound @@ -2828,38 +2738,32 @@ public static int floor(final char[] array, final char valueToFind) { public static int floor(final char[] array, final int fromIndex, final int toIndex, - final char valueToFind) { + final char value) { Validate.notNull(array); Validate.inclusiveBetween(0, array.length - 1, fromIndex); Validate.inclusiveBetween(0, array.length, toIndex); if (fromIndex >= toIndex) { return INDEX_NOT_FOUND; } - int lo = fromIndex; - int hi = toIndex - 1; - if (array[lo] > valueToFind) { + if (array[fromIndex] > value) { return INDEX_NOT_FOUND; } - if (array[hi] <= valueToFind) { - return hi; + if (array[toIndex - 1] <= value) { + return toIndex - 1; } - while (lo <= hi) { - final int mid = (lo + hi) >>> 1; - if (array[mid] == valueToFind) { - return mid; - } else if (array[mid] > valueToFind) { - if (lo <= mid - 1 && array[mid - 1] <= valueToFind) { - return mid - 1; - } - hi = mid - 1; - } else { - if (mid + 1 <= hi && array[mid + 1] > valueToFind) { - return mid; - } - lo = mid + 1; + final int mid = (fromIndex + toIndex - 1) >>> 1; + if (array[mid] == value) { + return mid; + } else if (array[mid] > value) { + if (fromIndex <= mid - 1 && array[mid - 1] <= value) { + return mid - 1; } + return floor(array, fromIndex, mid, value); } - return INDEX_NOT_FOUND; + if (mid + 1 <= toIndex - 1 && array[mid + 1] > value) { + return mid; + } + return floor(array, mid + 1, toIndex, value); } /**