Implement binarySearch method for UArrays (KT-27262)
This commit is contained in:
committed by
Ilya Gorbunov
parent
6cd9858147
commit
550c74bb6b
@@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:kotlin.jvm.JvmMultifileClass
|
||||||
|
@file:kotlin.jvm.JvmName("UArraysKt")
|
||||||
|
|
||||||
|
package kotlin.collections
|
||||||
|
|
||||||
|
//
|
||||||
|
// NOTE: THIS FILE IS AUTO-GENERATED by the GenerateStandardLib.kt
|
||||||
|
// See: https://github.com/JetBrains/kotlin/tree/master/libraries/stdlib
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches the array or the range of the array for the provided [element] using the binary search algorithm.
|
||||||
|
* The array is expected to be sorted, otherwise the result is undefined.
|
||||||
|
*
|
||||||
|
* If the array contains multiple elements equal to the specified [element], there is no guarantee which one will be found.
|
||||||
|
*
|
||||||
|
* @return the index of the element, if it is contained in the array within the specified range;
|
||||||
|
* otherwise, the inverted insertion point `(-insertion point - 1)`.
|
||||||
|
* The insertion point is defined as the index at which the element should be inserted,
|
||||||
|
* so that the array (or the specified subrange of array) still remains sorted.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
public fun UIntArray.binarySearch(element: UInt, fromIndex: Int = 0, toIndex: Int = size): Int {
|
||||||
|
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||||
|
val signedElement = element.toInt()
|
||||||
|
var low = fromIndex
|
||||||
|
var high = toIndex - 1
|
||||||
|
while (low <= high) {
|
||||||
|
val mid = (low + high).ushr(1) // safe from overflows
|
||||||
|
val midVal = storage[mid]
|
||||||
|
val cmp = uintCompare(midVal, signedElement)
|
||||||
|
if (cmp < 0)
|
||||||
|
low = mid + 1
|
||||||
|
else if (cmp > 0)
|
||||||
|
high = mid - 1
|
||||||
|
else
|
||||||
|
return mid // key found
|
||||||
|
}
|
||||||
|
return -(low + 1) // key not found
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches the array or the range of the array for the provided [element] using the binary search algorithm.
|
||||||
|
* The array is expected to be sorted, otherwise the result is undefined.
|
||||||
|
*
|
||||||
|
* If the array contains multiple elements equal to the specified [element], there is no guarantee which one will be found.
|
||||||
|
*
|
||||||
|
* @return the index of the element, if it is contained in the array within the specified range;
|
||||||
|
* otherwise, the inverted insertion point `(-insertion point - 1)`.
|
||||||
|
* The insertion point is defined as the index at which the element should be inserted,
|
||||||
|
* so that the array (or the specified subrange of array) still remains sorted.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
public fun ULongArray.binarySearch(element: ULong, fromIndex: Int = 0, toIndex: Int = size): Int {
|
||||||
|
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||||
|
val signedElement = element.toLong()
|
||||||
|
var low = fromIndex
|
||||||
|
var high = toIndex - 1
|
||||||
|
while (low <= high) {
|
||||||
|
val mid = (low + high).ushr(1) // safe from overflows
|
||||||
|
val midVal = storage[mid]
|
||||||
|
val cmp = ulongCompare(midVal, signedElement)
|
||||||
|
if (cmp < 0)
|
||||||
|
low = mid + 1
|
||||||
|
else if (cmp > 0)
|
||||||
|
high = mid - 1
|
||||||
|
else
|
||||||
|
return mid // key found
|
||||||
|
}
|
||||||
|
return -(low + 1) // key not found
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches the array or the range of the array for the provided [element] using the binary search algorithm.
|
||||||
|
* The array is expected to be sorted, otherwise the result is undefined.
|
||||||
|
*
|
||||||
|
* If the array contains multiple elements equal to the specified [element], there is no guarantee which one will be found.
|
||||||
|
*
|
||||||
|
* @return the index of the element, if it is contained in the array within the specified range;
|
||||||
|
* otherwise, the inverted insertion point `(-insertion point - 1)`.
|
||||||
|
* The insertion point is defined as the index at which the element should be inserted,
|
||||||
|
* so that the array (or the specified subrange of array) still remains sorted.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
public fun UByteArray.binarySearch(element: UByte, fromIndex: Int = 0, toIndex: Int = size): Int {
|
||||||
|
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||||
|
val signedElement = element.toInt()
|
||||||
|
var low = fromIndex
|
||||||
|
var high = toIndex - 1
|
||||||
|
while (low <= high) {
|
||||||
|
val mid = (low + high).ushr(1) // safe from overflows
|
||||||
|
val midVal = storage[mid]
|
||||||
|
val cmp = uintCompare(midVal.toInt(), signedElement)
|
||||||
|
if (cmp < 0)
|
||||||
|
low = mid + 1
|
||||||
|
else if (cmp > 0)
|
||||||
|
high = mid - 1
|
||||||
|
else
|
||||||
|
return mid // key found
|
||||||
|
}
|
||||||
|
return -(low + 1) // key not found
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches the array or the range of the array for the provided [element] using the binary search algorithm.
|
||||||
|
* The array is expected to be sorted, otherwise the result is undefined.
|
||||||
|
*
|
||||||
|
* If the array contains multiple elements equal to the specified [element], there is no guarantee which one will be found.
|
||||||
|
*
|
||||||
|
* @return the index of the element, if it is contained in the array within the specified range;
|
||||||
|
* otherwise, the inverted insertion point `(-insertion point - 1)`.
|
||||||
|
* The insertion point is defined as the index at which the element should be inserted,
|
||||||
|
* so that the array (or the specified subrange of array) still remains sorted.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@ExperimentalUnsignedTypes
|
||||||
|
public fun UShortArray.binarySearch(element: UShort, fromIndex: Int = 0, toIndex: Int = size): Int {
|
||||||
|
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||||
|
val signedElement = element.toInt()
|
||||||
|
var low = fromIndex
|
||||||
|
var high = toIndex - 1
|
||||||
|
while (low <= high) {
|
||||||
|
val mid = (low + high).ushr(1) // safe from overflows
|
||||||
|
val midVal = storage[mid]
|
||||||
|
val cmp = uintCompare(midVal.toInt(), signedElement)
|
||||||
|
if (cmp < 0)
|
||||||
|
low = mid + 1
|
||||||
|
else if (cmp > 0)
|
||||||
|
high = mid - 1
|
||||||
|
else
|
||||||
|
return mid // key found
|
||||||
|
}
|
||||||
|
return -(low + 1) // key not found
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package test.collections
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
|
||||||
|
class UArrayJVMTest {
|
||||||
|
@Test
|
||||||
|
fun binarySearch() {
|
||||||
|
|
||||||
|
fun <A, E> testFailures(array: A, binarySearch: A.(E, Int, Int) -> Int, element: E, arraySize: Int) {
|
||||||
|
assertFailsWith<IllegalArgumentException> {
|
||||||
|
array.binarySearch(element, 1, 0)
|
||||||
|
}
|
||||||
|
assertFailsWith<IndexOutOfBoundsException> {
|
||||||
|
array.binarySearch(element, 1, arraySize + 1)
|
||||||
|
}
|
||||||
|
assertFailsWith<IndexOutOfBoundsException> {
|
||||||
|
array.binarySearch(element, -1, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val array = uintArrayOf(1u, 0u, 4u, 5u, 8u, 12u, 2u, 3u, 7u, 7u, 7u, 9u, 2u)
|
||||||
|
|
||||||
|
testFailures(array.toUByteArray(), UByteArray::binarySearch, 0u, array.size)
|
||||||
|
testFailures(array.toUShortArray(), UShortArray::binarySearch, 0u, array.size)
|
||||||
|
testFailures(array, UIntArray::binarySearch, 0u, array.size)
|
||||||
|
testFailures(array.toULongArray(), ULongArray::binarySearch, 0u, array.size)
|
||||||
|
|
||||||
|
fun <A, E> test(
|
||||||
|
array: A,
|
||||||
|
binarySearch: A.(E, Int, Int) -> Int,
|
||||||
|
operations: List<OperationOnRange<UInt, Int>>,
|
||||||
|
transform: UInt.() -> E
|
||||||
|
) {
|
||||||
|
operations.forEach { o ->
|
||||||
|
val result = array.binarySearch(o.element.transform(), o.fromIndex, o.toIndex)
|
||||||
|
assertEquals(o.expectedResult, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val operations = listOf(
|
||||||
|
OperationOnRange(0u, 1, 6, 1),
|
||||||
|
OperationOnRange(12u, 1, 6, 5),
|
||||||
|
OperationOnRange(8u, 1, 6, 4),
|
||||||
|
OperationOnRange(4u, 1, 6, 2),
|
||||||
|
OperationOnRange(5u, 2, 6, 3),
|
||||||
|
OperationOnRange(8u, 2, 5, 4),
|
||||||
|
OperationOnRange(5u, 3, 4, 3),
|
||||||
|
|
||||||
|
OperationOnRange(5u, 3, 3, -4),
|
||||||
|
OperationOnRange(7u, 1, 6, -5),
|
||||||
|
OperationOnRange(8u, 6, 12, -12),
|
||||||
|
OperationOnRange(5u, 6, 12, -9),
|
||||||
|
|
||||||
|
OperationOnRange(7u, 6, 12, 8)
|
||||||
|
)
|
||||||
|
|
||||||
|
test(array.toUByteArray(), UByteArray::binarySearch, operations, UInt::toUByte)
|
||||||
|
test(array.toUShortArray(), UShortArray::binarySearch, operations, UInt::toUShort)
|
||||||
|
test(array, UIntArray::binarySearch, operations, UInt::toUInt)
|
||||||
|
test(array.toULongArray(), ULongArray::binarySearch, operations, UInt::toULong)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class OperationOnRange<E, R>(
|
||||||
|
val element: E,
|
||||||
|
val fromIndex: Int,
|
||||||
|
val toIndex: Int,
|
||||||
|
val expectedResult: R
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
private fun UIntArray.toUByteArray(): UByteArray {
|
||||||
|
return UByteArray(size) { get(it).toUByte() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun UIntArray.toUShortArray(): UShortArray {
|
||||||
|
return UShortArray(size) { get(it).toUShort() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun UIntArray.toULongArray(): ULongArray {
|
||||||
|
return ULongArray(size) { get(it).toULong() }
|
||||||
|
}
|
||||||
+8
@@ -2287,6 +2287,14 @@ public abstract class kotlin/collections/ShortIterator : java/util/Iterator, kot
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class kotlin/collections/UArraysKt {
|
public final class kotlin/collections/UArraysKt {
|
||||||
|
public static final fun binarySearch-2fe2U9s ([IIII)I
|
||||||
|
public static synthetic fun binarySearch-2fe2U9s$default ([IIIIILjava/lang/Object;)I
|
||||||
|
public static final fun binarySearch-EtDCXyQ ([SSII)I
|
||||||
|
public static synthetic fun binarySearch-EtDCXyQ$default ([SSIIILjava/lang/Object;)I
|
||||||
|
public static final fun binarySearch-K6DWlUc ([JJII)I
|
||||||
|
public static synthetic fun binarySearch-K6DWlUc$default ([JJIIILjava/lang/Object;)I
|
||||||
|
public static final fun binarySearch-WpHrYlw ([BBII)I
|
||||||
|
public static synthetic fun binarySearch-WpHrYlw$default ([BBIIILjava/lang/Object;)I
|
||||||
public static final fun contentEquals-ctEhBpI ([I[I)Z
|
public static final fun contentEquals-ctEhBpI ([I[I)Z
|
||||||
public static final fun contentEquals-kdPth3s ([B[B)Z
|
public static final fun contentEquals-kdPth3s ([B[B)Z
|
||||||
public static final fun contentEquals-mazbYpA ([S[S)Z
|
public static final fun contentEquals-mazbYpA ([S[S)Z
|
||||||
|
|||||||
@@ -1218,7 +1218,7 @@ object ArrayOps : TemplateGroupBase() {
|
|||||||
|
|
||||||
val f_binarySearch = fn("binarySearch(element: T, fromIndex: Int = 0, toIndex: Int = size)") {
|
val f_binarySearch = fn("binarySearch(element: T, fromIndex: Int = 0, toIndex: Int = size)") {
|
||||||
platforms(Platform.JVM)
|
platforms(Platform.JVM)
|
||||||
include(ArraysOfObjects, ArraysOfPrimitives)
|
include(ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned)
|
||||||
exclude(PrimitiveType.Boolean)
|
exclude(PrimitiveType.Boolean)
|
||||||
} builder {
|
} builder {
|
||||||
doc {
|
doc {
|
||||||
@@ -1238,6 +1238,55 @@ object ArrayOps : TemplateGroupBase() {
|
|||||||
body {
|
body {
|
||||||
"return java.util.Arrays.binarySearch(this, fromIndex, toIndex, element)"
|
"return java.util.Arrays.binarySearch(this, fromIndex, toIndex, element)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
specialFor(ArraysOfUnsigned) {
|
||||||
|
val elementConversion: String
|
||||||
|
val midValConversion: String
|
||||||
|
val compareFunction: String
|
||||||
|
when (primitive!!) {
|
||||||
|
PrimitiveType.UByte, PrimitiveType.UShort -> {
|
||||||
|
elementConversion = ".toInt()"
|
||||||
|
midValConversion = ".toInt()"
|
||||||
|
compareFunction = "uintCompare"
|
||||||
|
}
|
||||||
|
PrimitiveType.UInt -> {
|
||||||
|
elementConversion = ".toInt()"
|
||||||
|
midValConversion = ""
|
||||||
|
compareFunction = "uintCompare"
|
||||||
|
}
|
||||||
|
PrimitiveType.ULong -> {
|
||||||
|
elementConversion = ".toLong()"
|
||||||
|
midValConversion = ""
|
||||||
|
compareFunction = "ulongCompare"
|
||||||
|
}
|
||||||
|
else -> error(primitive!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
body {
|
||||||
|
"""
|
||||||
|
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
|
||||||
|
|
||||||
|
val signedElement = element$elementConversion
|
||||||
|
var low = fromIndex
|
||||||
|
var high = toIndex - 1
|
||||||
|
|
||||||
|
while (low <= high) {
|
||||||
|
val mid = (low + high).ushr(1) // safe from overflows
|
||||||
|
val midVal = storage[mid]
|
||||||
|
val cmp = $compareFunction(midVal$midValConversion, signedElement)
|
||||||
|
|
||||||
|
if (cmp < 0)
|
||||||
|
low = mid + 1
|
||||||
|
else if (cmp > 0)
|
||||||
|
high = mid - 1
|
||||||
|
else
|
||||||
|
return mid // key found
|
||||||
|
}
|
||||||
|
return -(low + 1) // key not found
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val f_binarySearch_comparator = fn("binarySearch(element: T, comparator: Comparator<in T>, fromIndex: Int = 0, toIndex: Int = size)") {
|
val f_binarySearch_comparator = fn("binarySearch(element: T, comparator: Comparator<in T>, fromIndex: Int = 0, toIndex: Int = size)") {
|
||||||
|
|||||||
Reference in New Issue
Block a user