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 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-kdPth3s ([B[B)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)") {
|
||||
platforms(Platform.JVM)
|
||||
include(ArraysOfObjects, ArraysOfPrimitives)
|
||||
include(ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned)
|
||||
exclude(PrimitiveType.Boolean)
|
||||
} builder {
|
||||
doc {
|
||||
@@ -1238,6 +1238,55 @@ object ArrayOps : TemplateGroupBase() {
|
||||
body {
|
||||
"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)") {
|
||||
|
||||
Reference in New Issue
Block a user