All Downloads are FREE. Search and download functionalities are using the official Maven repository.

kotlin.collections.JUtil.kt Maven / Gradle / Ivy

There is a newer version: 1.0.7
Show newest version
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