
kotlin.collections.JUtil.kt Maven / Gradle / Ivy
package kotlin
import java.io.Serializable
import java.util.*
private object EmptyIterator : ListIterator {
override fun hasNext(): Boolean = false
override fun hasPrevious(): Boolean = false
override fun nextIndex(): Int = 0
override fun previousIndex(): Int = -1
override fun next(): Nothing = throw NoSuchElementException()
override fun previous(): Nothing = throw NoSuchElementException()
}
private object EmptyList : List, Serializable {
override fun equals(other: Any?): Boolean = other is List<*> && other.isEmpty()
override fun hashCode(): Int = 1
override fun toString(): String = "[]"
override fun size(): Int = 0
override fun isEmpty(): Boolean = true
override fun contains(o: Any?): Boolean = false
override fun containsAll(c: Collection): Boolean = c.isEmpty()
override fun get(index: Int): Nothing = throw IndexOutOfBoundsException("Index $index is out of bound of empty list.")
override fun indexOf(o: Any?): Int = -1
override fun lastIndexOf(o: Any?): Int = -1
override fun iterator(): Iterator = EmptyIterator
override fun listIterator(): ListIterator = EmptyIterator
override fun listIterator(index: Int): ListIterator {
if (index != 0) throw IndexOutOfBoundsException("Index: $index")
return EmptyIterator
}
override fun subList(fromIndex: Int, toIndex: Int): List {
if (fromIndex == 0 && toIndex == 0) return this
throw IndexOutOfBoundsException("fromIndex: $fromIndex, toIndex: $toIndex")
}
private fun readResolve(): Any = EmptyList
}
private object EmptySet : Set, Serializable {
override fun equals(other: Any?): Boolean = other is Set<*> && other.isEmpty()
override fun hashCode(): Int = 0
override fun toString(): String = "[]"
override fun size(): Int = 0
override fun isEmpty(): Boolean = true
override fun contains(o: Any?): Boolean = false
override fun containsAll(c: Collection): Boolean = c.isEmpty()
override fun iterator(): Iterator = EmptyIterator
private fun readResolve(): Any = EmptySet
}
/** Returns an empty read-only list. The returned list is serializable (JVM). */
public fun emptyList(): List = EmptyList
/** Returns an empty read-only set. The returned set is serializable (JVM). */
public fun emptySet(): Set = EmptySet
/** Returns a new read-only list of given elements. The returned list is serializable (JVM). */
public fun listOf(vararg values: T): List = if (values.size() > 0) arrayListOf(*values) else emptyList()
/** Returns an empty read-only list. The returned list is serializable (JVM). */
public fun listOf(): List = emptyList()
/** Returns a new read-only ordered set with the given elements. The returned set is serializable (JVM). */
public fun setOf(vararg values: T): Set = if (values.size() > 0) values.toSet() else emptySet()
/** Returns an empty read-only set. The returned set is serializable (JVM). */
public fun setOf(): Set = emptySet()
/** Returns a new [LinkedList] with the given elements. */
public fun linkedListOf(vararg values: T): LinkedList = values.toCollection(LinkedList())
/** Returns a new [ArrayList] with the given elements. */
public fun arrayListOf(vararg values: T): ArrayList = values.toCollection(ArrayList(values.size()))
/** Returns a new [HashSet] with the given elements. */
public fun hashSetOf(vararg values: T): HashSet = values.toCollection(HashSet(mapCapacity(values.size())))
/** Returns a new [LinkedHashSet] with the given elements. */
public fun linkedSetOf(vararg values: T): LinkedHashSet = values.toCollection(LinkedHashSet(mapCapacity(values.size())))
/** Returns a new read-only list either of single given element, if it is not null, or empty list it the element is null. The returned list is serializable (JVM). */
public fun listOfNotNull(value: T?): List = if (value != null) listOf(value) else emptyList()
/** Returns a new read-only list only of those given elements, that are not null. The returned list is serializable (JVM). */
public fun listOfNotNull(vararg values: T?): List = values.filterNotNull()
/**
* Returns an [IntRange] of the valid indices for this collection.
*/
public val Collection<*>.indices: IntRange
get() = 0..size() - 1
/**
* Returns an [IntRange] that starts with zero and ends at the value of this number but does not include it.
*/
deprecated("Use 0..n-1 range instead.", ReplaceWith("0..this - 1"))
public val Int.indices: IntRange
get() = 0..this - 1
/**
* Returns the index of the last item in the list or -1 if the list is empty.
*
* @sample test.collections.ListSpecificTest.lastIndex
*/
public val List.lastIndex: Int
get() = this.size() - 1
/** Returns `true` if the collection is not empty. */
public fun Collection.isNotEmpty(): Boolean = !isEmpty()
/** Returns this Collection if it's not `null` and the empty list otherwise. */
public fun Collection?.orEmpty(): Collection = this ?: emptyList()
/** Returns this List if it's not `null` and the empty list otherwise. */
public fun List?.orEmpty(): List = this ?: emptyList()
/** Returns this Set if it's not `null` and the empty set otherwise. */
public fun Set?.orEmpty(): Set = this ?: emptySet()
/**
* Returns the size of this iterable if it is known, or `null` otherwise.
*/
public fun Iterable.collectionSizeOrNull(): Int? = if (this is Collection<*>) size() else null
/**
* Returns the size of this iterable if it is known, or the specified [default] value otherwise.
*/
public fun Iterable.collectionSizeOrDefault(default: Int): Int = if (this is Collection<*>) size() else default
/** Returns true when it's safe to convert this collection to a set without changing contains method behavior. */
private fun Collection.safeToConvertToSet() = size() > 2 && this is ArrayList
/** Converts this collection to a set, when it's worth so and it doesn't change contains method behavior. */
private fun Iterable.convertToSetForSetOperationWith(source: Iterable): Collection =
when(this) {
is Set -> this
is Collection ->
when {
source is Collection && source.size() < 2 -> this
else -> if (this.safeToConvertToSet()) toHashSet() else this
}
else -> toHashSet()
}
/** Converts this collection to a set, when it's worth so and it doesn't change contains method behavior. */
private fun Iterable.convertToSetForSetOperation(): Collection =
when(this) {
is Set -> this
is Collection -> if (this.safeToConvertToSet()) toHashSet() else this
else -> toHashSet()
}
/**
* Searches this list or its range for the provided [element] index using binary search algorithm.
* The list is expected to be sorted into ascending order according to the Comparable natural ordering of its elements.
*
* If the list contains multiple elements equal to the specified object, there is no guarantee which one will be found.
*/
public fun > List.binarySearch(element: T?, fromIndex: Int = 0, toIndex: Int = size()): Int {
rangeCheck(size(), fromIndex, toIndex)
var low = fromIndex
var high = toIndex - 1
while (low <= high) {
val mid = (low + high).ushr(1) // safe from overflows
val midVal = get(mid)
val cmp = compareValues(midVal, element)
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 this list or its range for the provided [element] index using binary search algorithm.
* The list is expected to be sorted into ascending order according to the specified [comparator].
*
* If the list contains multiple elements equal to the specified object, there is no guarantee which one will be found.
*/
public fun List.binarySearch(element: T, comparator: Comparator, fromIndex: Int = 0, toIndex: Int = size()): Int {
rangeCheck(size(), fromIndex, toIndex)
var low = fromIndex
var high = toIndex - 1
while (low <= high) {
val mid = (low + high).ushr(1) // safe from overflows
val midVal = get(mid)
val cmp = comparator.compare(midVal, element)
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 this list or its range for an index of an element with the provided [key] using binary search algorithm.
* The list is expected to be sorted into ascending order according to the Comparable natural ordering of keys of its elements.
*
* If the list contains multiple elements with the specified [key], there is no guarantee which one will be found.
*/
public inline fun > List.binarySearchBy(key: K?, fromIndex: Int = 0, toIndex: Int = size(), inlineOptions(InlineOption.ONLY_LOCAL_RETURN) selector: (T) -> K?): Int =
binarySearch(fromIndex, toIndex) { compareValues(selector(it), key) }
// do not introduce this overload --- too rare
//public fun List.binarySearchBy(key: K, comparator: Comparator, fromIndex: Int = 0, toIndex: Int = size(), selector: (T) -> K): Int =
// binarySearch(fromIndex, toIndex) { comparator.compare(selector(it), key) }
/**
* Searches this list or its range for an index of an element for which [comparison] function returns zero.
* The list is expected to be sorted into ascending order according to the provided [comparison].
*
* @param comparison function that compares an element of the list with the element being searched.
*/
public fun List.binarySearch(fromIndex: Int = 0, toIndex: Int = size(), comparison: (T) -> Int): Int {
rangeCheck(size(), fromIndex, toIndex)
var low = fromIndex
var high = toIndex - 1
while (low <= high) {
val mid = (low + high).ushr(1) // safe from overflows
val midVal = get(mid)
val cmp = comparison(midVal)
if (cmp < 0)
low = mid + 1
else if (cmp > 0)
high = mid - 1
else
return mid // key found
}
return -(low + 1) // key not found
}
/**
* Checks that `from` and `to` are in
* the range of [0..size] and throws an appropriate exception, if they aren't.
*/
private fun rangeCheck(size: Int, fromIndex: Int, toIndex: Int) {
when {
fromIndex > toIndex -> throw IllegalArgumentException("fromIndex ($fromIndex) is greater than toIndex ($toIndex)")
fromIndex < 0 -> throw IndexOutOfBoundsException("fromIndex ($fromIndex) is less than zero.")
toIndex > size -> throw IndexOutOfBoundsException("toIndex ($toIndex) is greater than size ($size).")
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy