mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-16 14:23:28 +07:00
[syntax] use multiplatform fastutil from util module instead of syntax one
GitOrigin-RevId: 4ac9294d8b91707464780b7be52d60a51dbe5632
This commit is contained in:
committed by
intellij-monorepo-bot
parent
bdf54c4ac9
commit
68f50bd8a3
@@ -5,10 +5,10 @@ import com.intellij.java.syntax.element.JavaDocSyntaxElementType
|
||||
import com.intellij.java.syntax.element.JavaSyntaxTokenType
|
||||
import com.intellij.platform.syntax.SyntaxElementType
|
||||
import com.intellij.platform.syntax.element.SyntaxTokenTypes.WHITE_SPACE
|
||||
import com.intellij.platform.syntax.impl.fastutil.ints.IntArrayList
|
||||
import com.intellij.platform.syntax.lexer.Lexer
|
||||
import com.intellij.platform.syntax.lexer.LexerPosition
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.util.fastutil.ints.IntArrayList
|
||||
import com.intellij.util.text.CharArrayUtilKmp.fromSequenceWithoutCopying
|
||||
|
||||
class JavaLexer(level: LanguageLevel) : Lexer {
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
package com.intellij.platform.syntax
|
||||
|
||||
import com.intellij.platform.syntax.impl.fastutil.ints.IntArrayList
|
||||
import com.intellij.platform.syntax.impl.util.BitSet
|
||||
import com.intellij.util.fastutil.ints.IntArrayList
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.syntax.impl.builder
|
||||
|
||||
import com.intellij.platform.syntax.impl.fastutil.ints.*
|
||||
import com.intellij.platform.syntax.impl.util.MutableBitSet
|
||||
import com.intellij.platform.syntax.parser.WhitespacesAndCommentsBinder
|
||||
import com.intellij.platform.syntax.parser.WhitespacesBinders
|
||||
import com.intellij.util.fastutil.ints.*
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.Nls
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.syntax.impl.builder
|
||||
|
||||
import com.intellij.platform.syntax.impl.fastutil.ints.IntArrayList
|
||||
import com.intellij.platform.syntax.impl.fastutil.ints.isEmpty
|
||||
import com.intellij.util.fastutil.ints.IntArrayList
|
||||
import com.intellij.util.fastutil.ints.isEmpty
|
||||
|
||||
internal open class MarkerPool(
|
||||
private val builder: SyntaxTreeBuilderImpl,
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
package com.intellij.platform.syntax.impl.builder
|
||||
|
||||
import com.intellij.platform.syntax.Logger
|
||||
import com.intellij.platform.syntax.impl.fastutil.ints.IntArrayList
|
||||
import com.intellij.platform.syntax.impl.fastutil.ints.IntList
|
||||
import com.intellij.platform.syntax.impl.fastutil.ints.lastIndexOf
|
||||
import com.intellij.util.fastutil.ints.IntArrayList
|
||||
import com.intellij.util.fastutil.ints.IntList
|
||||
import com.intellij.util.fastutil.ints.lastIndexOf
|
||||
import fleet.util.multiplatform.linkToActual
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
|
||||
@@ -6,11 +6,11 @@ import com.intellij.platform.syntax.Logger
|
||||
import com.intellij.platform.syntax.Logger.Attachment
|
||||
import com.intellij.platform.syntax.SyntaxElementType
|
||||
import com.intellij.platform.syntax.SyntaxElementTypeSet
|
||||
import com.intellij.platform.syntax.impl.fastutil.ints.isEmpty
|
||||
import com.intellij.platform.syntax.lexer.TokenList
|
||||
import com.intellij.platform.syntax.lexer.TokenListImpl
|
||||
import com.intellij.platform.syntax.parser.*
|
||||
import com.intellij.platform.syntax.parser.SyntaxTreeBuilder.Production
|
||||
import com.intellij.util.fastutil.ints.isEmpty
|
||||
import org.jetbrains.annotations.Nls
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import kotlin.math.abs
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.syntax.impl.fastutil
|
||||
|
||||
import com.intellij.platform.syntax.impl.fastutil.ints.IntList
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
object Arrays {
|
||||
|
||||
const val MAX_ARRAY_SIZE: Int = Int.MAX_VALUE - 8
|
||||
|
||||
fun ensureOffsetLength(arrayLength: Int, offset: Int, length: Int) {
|
||||
check(arrayLength >= 0)
|
||||
|
||||
if (offset < 0) throw IndexOutOfBoundsException("Offset ($offset) is negative")
|
||||
if (length < 0) throw IllegalArgumentException("Length ($length) is negative")
|
||||
if (length > arrayLength - offset) throw IndexOutOfBoundsException("Last index (" + (offset.toLong() + length) + ") is greater than array length (" + arrayLength + ")")
|
||||
}
|
||||
|
||||
fun ensureOffsetLength(a: IntList, offset: Int, length: Int) {
|
||||
ensureOffsetLength(a.size, offset, length)
|
||||
}
|
||||
|
||||
fun ensureOffsetLength(a: IntArray, offset: Int, length: Int) {
|
||||
ensureOffsetLength(a.size, offset, length)
|
||||
}
|
||||
|
||||
fun ensureFromTo(arrayLength: Int, from: Int, to: Int) {
|
||||
check(arrayLength >= 0)
|
||||
if (from < 0) throw IndexOutOfBoundsException("Start index ($from) is negative")
|
||||
if (from > to) throw IllegalArgumentException("Start index ($from) is greater than end index ($to)")
|
||||
if (to > arrayLength) throw IndexOutOfBoundsException("End index ($to) is greater than array length ($arrayLength)")
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun <T> Iterator<T>.skip(n: Int): Int {
|
||||
if (n < 0) throw IllegalArgumentException("Argument must be nonnegative: $n")
|
||||
var i = n
|
||||
while (i-- != 0 && hasNext()) next()
|
||||
return n - i - 1
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.syntax.impl.fastutil
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
/** Basic data for all hash-based classes. */
|
||||
@ApiStatus.Internal
|
||||
interface Hash {
|
||||
/** A generic hash strategy.
|
||||
*
|
||||
*
|
||||
* Custom hash structures (e.g., [ ]) allow to hash objects
|
||||
* using arbitrary functions, a typical example being that of [ ][fleet.fastutil.ints.IntArrays.HASH_STRATEGY]. Of course,
|
||||
* one has to compare objects for equality consistently with the chosen
|
||||
* function. A *hash strategy*, thus, specifies an [ ][.equals] and a [ ][.hashCode], with the obvious property that
|
||||
* equal objects must have the same hash code.
|
||||
*
|
||||
*
|
||||
* Note that the [equals()][.equals] method of a strategy must
|
||||
* be able to handle `null`, too.
|
||||
*/
|
||||
interface Strategy<K> {
|
||||
/** Returns the hash code of the specified object with respect to this hash strategy.
|
||||
*
|
||||
* @param o an object (or `null`).
|
||||
* @return the hash code of the given object with respect to this hash strategy.
|
||||
*/
|
||||
fun hashCode(o: K?): Int
|
||||
|
||||
/** Returns true if the given objects are equal with respect to this hash strategy.
|
||||
*
|
||||
* @param a an object (or `null`).
|
||||
* @param b another object (or `null`).
|
||||
* @return true if the two specified objects are equal with respect to this hash strategy.
|
||||
*/
|
||||
fun equals(a: K?, b: K?): Boolean
|
||||
}
|
||||
|
||||
companion object {
|
||||
/** The initial default size of a hash table. */
|
||||
const val DEFAULT_INITIAL_SIZE: Int = 16
|
||||
|
||||
/** The default load factor of a hash table. */
|
||||
const val DEFAULT_LOAD_FACTOR: Float = .75f
|
||||
}
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2024 Sebastiano Vigna
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.intellij.platform.syntax.impl.fastutil
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
/** Common code for all hash-based classes. */
|
||||
@ApiStatus.Internal
|
||||
object HashCommon {
|
||||
/** 2<sup>32</sup> , = (√5 1)/2. */
|
||||
private const val INT_PHI = -0x61c88647
|
||||
|
||||
/** The reciprocal of [.INT_PHI] modulo 2<sup>32</sup>. */
|
||||
private const val INV_INT_PHI = 0x144cbc89
|
||||
|
||||
/** 2<sup>64</sup> , = (√5 1)/2. */
|
||||
private const val LONG_PHI = -0x61c8864680b583ebL
|
||||
|
||||
/** The reciprocal of [.LONG_PHI] modulo 2<sup>64</sup>. */
|
||||
private const val INV_LONG_PHI = -0xe217c1e66c88cc3L
|
||||
|
||||
/** Avalanches the bits of an integer by applying the finalisation step of MurmurHash3.
|
||||
*
|
||||
*
|
||||
* This method implements the finalisation step of Austin Appleby's [MurmurHash3](http://code.google.com/p/smhasher/).
|
||||
* Its purpose is to avalanche the bits of the argument to within 0.25% bias.
|
||||
*
|
||||
* @param x an integer.
|
||||
* @return a hash value with good avalanching properties.
|
||||
*/
|
||||
fun murmurHash3(x: Int): Int {
|
||||
var x = x
|
||||
x = x xor (x ushr 16)
|
||||
x *= -0x7a143595
|
||||
x = x xor (x ushr 13)
|
||||
x *= -0x3d4d51cb
|
||||
x = x xor (x ushr 16)
|
||||
return x
|
||||
}
|
||||
|
||||
|
||||
/** Avalanches the bits of a long integer by applying the finalisation step of MurmurHash3.
|
||||
*
|
||||
*
|
||||
* This method implements the finalisation step of Austin Appleby's [MurmurHash3](http://code.google.com/p/smhasher/).
|
||||
* Its purpose is to avalanche the bits of the argument to within 0.25% bias.
|
||||
*
|
||||
* @param x a long integer.
|
||||
* @return a hash value with good avalanching properties.
|
||||
*/
|
||||
fun murmurHash3(x: Long): Long {
|
||||
var x = x
|
||||
x = x xor (x ushr 33)
|
||||
x *= -0xae502812aa7333L
|
||||
x = x xor (x ushr 33)
|
||||
x *= -0x3b314601e57a13adL
|
||||
x = x xor (x ushr 33)
|
||||
return x
|
||||
}
|
||||
|
||||
/** Quickly mixes the bits of an integer.
|
||||
*
|
||||
*
|
||||
* This method mixes the bits of the argument by multiplying by the golden ratio and
|
||||
* xorshifting the result. It is borrowed from [Koloboke](https://github.com/leventov/Koloboke), and
|
||||
* it has slightly worse behaviour than [.murmurHash3] (in open-addressing hash tables the average number of probes
|
||||
* is slightly larger), but it's much faster.
|
||||
*
|
||||
* @param x an integer.
|
||||
* @return a hash value obtained by mixing the bits of `x`.
|
||||
* @see .invMix
|
||||
*/
|
||||
fun mix(x: Int): Int {
|
||||
val h: Int = x * INT_PHI
|
||||
return h xor (h ushr 16)
|
||||
}
|
||||
|
||||
/** The inverse of [.mix]. This method is mainly useful to create unit tests.
|
||||
*
|
||||
* @param x an integer.
|
||||
* @return a value that passed through [.mix] would give `x`.
|
||||
*/
|
||||
fun invMix(x: Int): Int {
|
||||
return (x xor (x ushr 16)) * INV_INT_PHI
|
||||
}
|
||||
|
||||
/** Quickly mixes the bits of a long integer.
|
||||
*
|
||||
*
|
||||
* This method mixes the bits of the argument by multiplying by the golden ratio and
|
||||
* xorshifting twice the result. It is borrowed from [Koloboke](https://github.com/leventov/Koloboke), and
|
||||
* it has slightly worse behaviour than [.murmurHash3] (in open-addressing hash tables the average number of probes
|
||||
* is slightly larger), but it's much faster.
|
||||
*
|
||||
* @param x a long integer.
|
||||
* @return a hash value obtained by mixing the bits of `x`.
|
||||
*/
|
||||
fun mix(x: Long): Long {
|
||||
var h: Long = x * LONG_PHI
|
||||
h = h xor (h ushr 32)
|
||||
return h xor (h ushr 16)
|
||||
}
|
||||
|
||||
/** The inverse of [.mix]. This method is mainly useful to create unit tests.
|
||||
*
|
||||
* @param x a long integer.
|
||||
* @return a value that passed through [.mix] would give `x`.
|
||||
*/
|
||||
fun invMix(x: Long): Long {
|
||||
var x = x
|
||||
x = x xor (x ushr 32)
|
||||
x = x xor (x ushr 16)
|
||||
return (x xor (x ushr 32)) * INV_LONG_PHI
|
||||
}
|
||||
|
||||
|
||||
/** Returns the hash code that would be returned by [Float.hashCode].
|
||||
*
|
||||
* @param f a float.
|
||||
* @return the same code as [new Float(f).hashCode()][Float.hashCode].
|
||||
*/
|
||||
fun float2int(f: Float): Int {
|
||||
return f.toRawBits()
|
||||
}
|
||||
|
||||
/** Returns the hash code that would be returned by [Double.hashCode].
|
||||
*
|
||||
* @param d a double.
|
||||
* @return the same code as [new Double(f).hashCode()][Double.hashCode].
|
||||
*/
|
||||
fun double2int(d: Double): Int {
|
||||
val l: Long = d.toRawBits()
|
||||
return (l xor (l ushr 32)).toInt()
|
||||
}
|
||||
|
||||
/** Returns the hash code that would be returned by [Long.hashCode].
|
||||
*
|
||||
* @param l a long.
|
||||
* @return the same code as [new Long(f).hashCode()][Long.hashCode].
|
||||
*/
|
||||
fun long2int(l: Long): Int {
|
||||
return (l xor (l ushr 32)).toInt()
|
||||
}
|
||||
|
||||
/** Returns the least power of two greater than or equal to the specified value.
|
||||
*
|
||||
*
|
||||
* Note that this function will return 1 when the argument is 0.
|
||||
*
|
||||
* @param x an integer smaller than or equal to 2<sup>30</sup>.
|
||||
* @return the least power of two greater than or equal to the specified value.
|
||||
*/
|
||||
fun nextPowerOfTwo(x: Int): Int {
|
||||
return 1 shl (32 - (x - 1).countLeadingZeroBits())
|
||||
}
|
||||
|
||||
/** Returns the least power of two greater than or equal to the specified value.
|
||||
*
|
||||
*
|
||||
* Note that this function will return 1 when the argument is 0.
|
||||
*
|
||||
* @param x a long integer smaller than or equal to 2<sup>62</sup>.
|
||||
* @return the least power of two greater than or equal to the specified value.
|
||||
*/
|
||||
fun nextPowerOfTwo(x: Long): Long {
|
||||
return 1L shl (64 - (x - 1).countLeadingZeroBits())
|
||||
}
|
||||
|
||||
|
||||
/** Returns the maximum number of entries that can be filled before rehashing.
|
||||
*
|
||||
* @param n the size of the backing array.
|
||||
* @param f the load factor.
|
||||
* @return the maximum number of entries before rehashing.
|
||||
*/
|
||||
fun maxFill(n: Int, f: Float): Int {/* We must guarantee that there is always at least
|
||||
* one free entry (even with pathological load factors). */
|
||||
return min(ceil((n * f).toDouble()).toInt().toDouble(), (n - 1).toDouble()).toInt()
|
||||
}
|
||||
|
||||
/** Returns the maximum number of entries that can be filled before rehashing.
|
||||
*
|
||||
* @param n the size of the backing array.
|
||||
* @param f the load factor.
|
||||
* @return the maximum number of entries before rehashing.
|
||||
*/
|
||||
fun maxFill(n: Long, f: Float): Long {/* We must guarantee that there is always at least
|
||||
* one free entry (even with pathological load factors). */
|
||||
return min(ceil((n * f).toDouble()).toLong().toDouble(), (n - 1).toDouble()).toLong()
|
||||
}
|
||||
|
||||
/** Returns the least power of two smaller than or equal to 2<sup>30</sup> and larger than or equal to `Math.ceil(expected / f)`.
|
||||
*
|
||||
* @param expected the expected number of elements in a hash table.
|
||||
* @param f the load factor.
|
||||
* @return the minimum possible size for a backing array.
|
||||
* @throws IllegalArgumentException if the necessary size is larger than 2<sup>30</sup>.
|
||||
*/
|
||||
fun arraySize(expected: Int, f: Float): Int {
|
||||
val s = max(2.0, nextPowerOfTwo(ceil((expected / f).toDouble()).toLong()).toDouble()).toLong()
|
||||
if (s > (1 shl 30)) throw IllegalArgumentException("Too large ($expected expected elements with load factor $f)")
|
||||
return s.toInt()
|
||||
}
|
||||
|
||||
/** Returns the least power of two larger than or equal to `Math.ceil(expected / f)`.
|
||||
*
|
||||
* @param expected the expected number of elements in a hash table.
|
||||
* @param f the load factor.
|
||||
* @return the minimum possible size for a backing big array.
|
||||
*/
|
||||
fun bigArraySize(expected: Long, f: Float): Long {
|
||||
return nextPowerOfTwo(ceil((expected / f).toDouble()).toLong())
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
This package is copied from `fleet.fastutil` module.
|
||||
It's tricky to make `fleet.fastutil` module compile with Java8 which
|
||||
is the requirement for `intellij.platform.syntax.impl`.
|
||||
This is a temporary solution until the compatibility with `fleet.fastutil` id not resolved.
|
||||
Thus, please don't make the declarations in this package public.
|
||||
@@ -1,598 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2024 Sebastiano Vigna
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.intellij.platform.syntax.impl.fastutil.ints
|
||||
|
||||
import com.intellij.platform.syntax.impl.fastutil.Hash
|
||||
import com.intellij.platform.syntax.impl.fastutil.HashCommon
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
/** A type-specific hash map with a fast, small-footprint implementation.
|
||||
*
|
||||
*
|
||||
* Instances of this class use a hash table to represent a map. The table is
|
||||
* filled up to a specified *load factor*, and then doubled in size to
|
||||
* accommodate new entries. If the table is emptied below *one fourth*
|
||||
* of the load factor, it is halved in size; however, the table is never reduced to a
|
||||
* size smaller than that at creation time: this approach makes it
|
||||
* possible to create maps with a large capacity in which insertions and
|
||||
* deletions do not cause immediately rehashing. Moreover, halving is
|
||||
* not performed when deleting entries from an iterator, as it would interfere
|
||||
* with the iteration process.
|
||||
*
|
||||
*
|
||||
* Note that [.clear] does not modify the hash table size.
|
||||
* Rather, a family of [trimming][.trim] lets you control the size of the table; this is particularly useful
|
||||
* if you reuse instances of this class.
|
||||
*
|
||||
*
|
||||
* @see Hash
|
||||
*
|
||||
* @see HashCommon
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
class Int2ObjectOpenHashMap<V> : Hash, MutableIntMap<V> {
|
||||
/** The array of keys. */
|
||||
private var key: IntArray
|
||||
|
||||
/** The array of values. */
|
||||
private var value: Array<V?>
|
||||
|
||||
/** The mask for wrapping a position counter. */
|
||||
private var mask: Int
|
||||
|
||||
/** Whether this map contains the key zero. */
|
||||
private var containsNullKey: Boolean = false
|
||||
|
||||
/** The current table size. */
|
||||
private var n: Int
|
||||
|
||||
/** Threshold after which we rehash. It must be the table size times [.f]. */
|
||||
private var maxFill: Int
|
||||
|
||||
/** We never resize below this threshold, which is the construction-time {#n}. */
|
||||
private var minN: Int
|
||||
|
||||
/** Number of entries in the set (including the key zero, if present). */
|
||||
override var size: Int = 0
|
||||
|
||||
/** The acceptable load factor. */
|
||||
private var f: Float
|
||||
|
||||
private var defaultValue: V? = null
|
||||
|
||||
/** Iterator over entries. */
|
||||
override val entries: Iterator<IntEntry<V>>
|
||||
get() {
|
||||
return EntryIterator()
|
||||
}
|
||||
|
||||
/** Iterator over keys*/
|
||||
override val keys: IntIterator
|
||||
get() {
|
||||
return KeyIterator()
|
||||
}
|
||||
|
||||
/** Iterator over values. */
|
||||
override val values: Iterator<V>
|
||||
get() {
|
||||
return ValueIterator()
|
||||
}
|
||||
|
||||
constructor(expected: Int, f: Float) {
|
||||
if (f <= 0 || f >= 1) throw IllegalArgumentException("Load factor must be greater than 0 and smaller than 1")
|
||||
if (expected < 0) throw IllegalArgumentException("The expected number of elements must be nonnegative")
|
||||
this.f = f
|
||||
n = HashCommon.arraySize(expected, f)
|
||||
minN = n
|
||||
mask = n - 1
|
||||
maxFill = HashCommon.maxFill(n, f)
|
||||
key = IntArray(n + 1)
|
||||
value = arrayOfNulls<Any>(n + 1) as Array<V?>
|
||||
}
|
||||
|
||||
constructor() : this(Hash.DEFAULT_INITIAL_SIZE, Hash.DEFAULT_LOAD_FACTOR)
|
||||
|
||||
constructor(expected: Int) : this(expected, Hash.DEFAULT_LOAD_FACTOR)
|
||||
|
||||
/** Creates a new hash map with [Hash.DEFAULT_LOAD_FACTOR] as load factor copying a given one.
|
||||
*
|
||||
* @param m a [Map] to be copied into the new hash map.
|
||||
*/
|
||||
constructor(m: Int2ObjectOpenHashMap<V>, f: Float = Hash.DEFAULT_LOAD_FACTOR) : this(m.size, f) {
|
||||
putAll(m)
|
||||
}
|
||||
|
||||
/** Creates a new hash map with [Hash.DEFAULT_LOAD_FACTOR] as load factor using the elements of two parallel arrays.
|
||||
*
|
||||
* @param k the array of keys of the new hash map.
|
||||
* @param v the array of corresponding values in the new hash map.
|
||||
* @throws IllegalArgumentException if `k` and `v` have different lengths.
|
||||
*/
|
||||
constructor(k: IntArrayList, v: Array<V>, f: Float = Hash.DEFAULT_LOAD_FACTOR) : this(k.size, f) {
|
||||
if (k.size != v.size) throw IllegalArgumentException("The key array and the value array have different lengths (" + k.size + " and " + v.size + ")")
|
||||
for (i in k.indices) this[k[i]] = v[i]
|
||||
}
|
||||
|
||||
constructor(k: IntArray, v: Array<V>, f: Float = Hash.DEFAULT_LOAD_FACTOR) : this(k.size, f) {
|
||||
if (k.size != v.size) throw IllegalArgumentException("The key array and the value array have different lengths (" + k.size + " and " + v.size + ")")
|
||||
for (i in k.indices) this[k[i]] = v[i]
|
||||
}
|
||||
|
||||
fun isEmpty(): Boolean {
|
||||
return size == 0
|
||||
}
|
||||
|
||||
private fun realSize(): Int {
|
||||
return if (containsNullKey) size - 1 else size
|
||||
}
|
||||
|
||||
/** Ensures that this map can hold a certain number of keys without rehashing.
|
||||
*
|
||||
* @param capacity a number of keys; there will be no rehashing unless
|
||||
* the map [size][.size] exceeds this number.
|
||||
*/
|
||||
private fun ensureCapacity(capacity: Int) {
|
||||
val needed: Int = HashCommon.arraySize(capacity, f)
|
||||
if (needed > n) rehash(needed)
|
||||
}
|
||||
|
||||
private fun tryCapacity(capacity: Long) {
|
||||
val needed = min(1 shl 30, max(2, HashCommon.nextPowerOfTwo(ceil(capacity / f).toInt())))
|
||||
if (needed > n) rehash(needed)
|
||||
}
|
||||
|
||||
private fun removeEntry(pos: Int): V? {
|
||||
val oldValue = value[pos]
|
||||
value[pos] = null
|
||||
size--
|
||||
shiftKeys(pos)
|
||||
if (n > minN && size < maxFill / 4 && n > Hash.DEFAULT_INITIAL_SIZE) rehash(n / 2)
|
||||
return oldValue
|
||||
}
|
||||
|
||||
private fun removeNullEntry(): V {
|
||||
containsNullKey = false
|
||||
val oldValue = value[n]
|
||||
value[n] = null
|
||||
size--
|
||||
if (n > minN && size < maxFill / 4 && n > Hash.DEFAULT_INITIAL_SIZE) rehash(n / 2)
|
||||
return oldValue!!
|
||||
}
|
||||
|
||||
|
||||
fun putAll(from: Int2ObjectOpenHashMap<V>) {
|
||||
if (f <= .5) ensureCapacity(from.size) // The resulting map will be sized for m.size() elements
|
||||
else tryCapacity((size + from.size).toLong()) // The resulting map will be tentatively sized for size() + m.size() elements
|
||||
|
||||
var n = from.size
|
||||
val i = from.entries.iterator()
|
||||
var e: IntEntry<V>
|
||||
while (n-- != 0) {
|
||||
e = i.next()
|
||||
put(e.key, e.value)
|
||||
}
|
||||
}
|
||||
|
||||
private fun find(k: Int): Int {
|
||||
if (k == 0) return if (containsNullKey) n else -(n + 1)
|
||||
var curr: Int
|
||||
val key = this.key
|
||||
var pos: Int // The starting point.
|
||||
if (key[(HashCommon.mix(k) and mask).also {
|
||||
pos = it
|
||||
}].also { curr = it } == 0) return -(pos + 1)
|
||||
if (k == curr) return pos // There's always an unused entry.
|
||||
while (true) {
|
||||
if (key[((pos + 1) and mask).also { pos = it }].also {
|
||||
curr = it
|
||||
} == 0) return -(pos + 1)
|
||||
if (k == curr) return pos
|
||||
}
|
||||
}
|
||||
|
||||
private fun insert(pos: Int, k: Int, v: V) {
|
||||
if (pos == n) containsNullKey = true
|
||||
key[pos] = k
|
||||
value[pos] = v
|
||||
if (size++ >= maxFill) rehash(HashCommon.arraySize(size + 1, f))
|
||||
}
|
||||
|
||||
override fun put(key: Int, value: V): V? {
|
||||
val pos = find(key)
|
||||
if (pos < 0) {
|
||||
insert(-pos - 1, key, value)
|
||||
return defaultReturnValue()
|
||||
}
|
||||
val oldValue = this.value[pos]
|
||||
this.value[pos] = value
|
||||
this.key[pos] = key
|
||||
return oldValue
|
||||
}
|
||||
|
||||
/** Shifts left entries with the specified hash code, starting at the specified position,
|
||||
* and empties the resulting free entry.
|
||||
*
|
||||
* @param pos a starting position.
|
||||
*/
|
||||
private fun shiftKeys(pos: Int) { // Shift entries with the same hash.
|
||||
var pos = pos
|
||||
var last: Int
|
||||
var slot: Int
|
||||
var curr: Int
|
||||
val key = this.key
|
||||
val value: Array<V?> = this.value
|
||||
while (true) {
|
||||
pos = (pos.also { last = it } + 1) and mask
|
||||
while (true) {
|
||||
if (key[pos].also { curr = it } == 0) {
|
||||
key[last] = 0
|
||||
value[last] = null
|
||||
return
|
||||
}
|
||||
slot = HashCommon.mix(curr) and mask
|
||||
if (if (last <= pos) last >= slot || slot > pos else slot in (pos + 1)..last) break
|
||||
pos = (pos + 1) and mask
|
||||
}
|
||||
key[last] = curr
|
||||
value[last] = value[pos]
|
||||
}
|
||||
}
|
||||
|
||||
override fun remove(k: Int): V? {
|
||||
if (k == 0) {
|
||||
if (containsNullKey) return removeNullEntry()
|
||||
return defaultReturnValue()
|
||||
}
|
||||
var curr: Int
|
||||
val key = this.key
|
||||
var pos: Int // The starting point.
|
||||
if (key[(HashCommon.mix(k) and mask).also {
|
||||
pos = it
|
||||
}].also { curr = it } == 0) return defaultReturnValue()
|
||||
if (k == curr) return removeEntry(pos)
|
||||
while (true) {
|
||||
if (key[((pos + 1) and mask).also { pos = it }].also {
|
||||
curr = it
|
||||
} == 0) return defaultReturnValue()
|
||||
if (k == curr) return removeEntry(pos)
|
||||
}
|
||||
}
|
||||
|
||||
override operator fun get(k: Int): V? {
|
||||
if (k == 0) return if (containsNullKey) value[n] else defaultReturnValue()
|
||||
var curr: Int
|
||||
val key = this.key
|
||||
var pos: Int // The starting point.
|
||||
if (key[(HashCommon.mix(k) and mask).also {
|
||||
pos = it
|
||||
}].also { curr = it } == 0) return defaultReturnValue()
|
||||
if (k == curr) return value[pos] // There's always an unused entry.
|
||||
while (true) {
|
||||
if (key[((pos + 1) and mask).also { pos = it }].also {
|
||||
curr = it
|
||||
} == 0) return defaultReturnValue()
|
||||
if (k == curr) return value[pos]
|
||||
}
|
||||
}
|
||||
|
||||
fun containsKey(k: Int): Boolean {
|
||||
if (k == 0) return containsNullKey
|
||||
var curr: Int
|
||||
val key = this.key
|
||||
var pos: Int // The starting point.
|
||||
if (key[(HashCommon.mix(k) and mask).also {
|
||||
pos = it
|
||||
}].also { curr = it } == 0) return false
|
||||
if (k == curr) return true // There's always an unused entry.
|
||||
while (true) {
|
||||
if (key[((pos + 1) and mask).also { pos = it }].also {
|
||||
curr = it
|
||||
} == 0) return false
|
||||
if (k == curr) return true
|
||||
}
|
||||
}
|
||||
|
||||
fun containsValue(v: V): Boolean {
|
||||
if (containsNullKey && value[n] == v) return true
|
||||
var i = n
|
||||
while (i-- != 0) {
|
||||
if (key[i] != 0 && value[i] == v) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
fun getOrDefault(k: Int, defaultValue: V): V {
|
||||
if (k == 0) return if (containsNullKey) value[n]!! else defaultValue
|
||||
var curr: Int
|
||||
val key = this.key
|
||||
var pos: Int // The starting point.
|
||||
if (key[HashCommon.mix(k) and mask].also { pos = it }.also { curr = it } == 0) return defaultValue
|
||||
if (k == curr) return value[pos]!! // There's always an unused entry.
|
||||
while (true) {
|
||||
if (key[(pos + 1) and mask].also { pos = it }.also { curr = it } == 0) return defaultValue
|
||||
if (k == curr) return value[pos]!!
|
||||
}
|
||||
}
|
||||
|
||||
fun remove(k: Int, v: Any): Boolean {
|
||||
if (k == 0) {
|
||||
if (containsNullKey && v == value[n]) {
|
||||
removeNullEntry()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
var curr: Int
|
||||
val key = this.key
|
||||
var pos: Int // The starting point.
|
||||
if (key[HashCommon.mix(k) and mask].also { pos = it }.also { curr = it } == 0) return false
|
||||
if (k == curr && v == value[pos]) {
|
||||
removeEntry(pos)
|
||||
return true
|
||||
}
|
||||
while (true) {
|
||||
if (key[(pos + 1) and mask].also { pos = it }.also { curr = it } == 0) return false
|
||||
if (k == curr && v == value[pos]) {
|
||||
removeEntry(pos)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun defaultReturnValue(): V? {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
fun defaultReturnValue(rv: V) {
|
||||
defaultValue = rv
|
||||
}
|
||||
|
||||
fun replace(k: Int, oldValue: V, v: V): Boolean {
|
||||
val pos = find(k)
|
||||
if (pos < 0 || oldValue != value[pos]) return false
|
||||
value[pos] = v
|
||||
return true
|
||||
}
|
||||
|
||||
fun replace(k: Int, v: V): V {
|
||||
val pos = find(k)
|
||||
if (pos < 0) return defaultReturnValue()!!
|
||||
val oldValue = value[pos]
|
||||
value[pos] = v
|
||||
return oldValue!!
|
||||
}
|
||||
|
||||
|
||||
/** Removes all elements from this map.
|
||||
*
|
||||
* <p>To increase object reuse, this method does not change the table size.
|
||||
* If you want to reduce the table size, you must use {@link #trim()}.
|
||||
*
|
||||
*/
|
||||
fun clear() {
|
||||
if (size == 0) return
|
||||
size = 0
|
||||
containsNullKey = false
|
||||
key.fill(0)
|
||||
value.fill(null)
|
||||
}
|
||||
|
||||
/** An iterator over a hash map. */
|
||||
private abstract inner class MapIterator {
|
||||
/** The index of the last entry returned, if positive or zero; initially, [.n]. If negative, the last
|
||||
* entry returned was that of the key of index `- pos - 1` from the [.wrapped] list. */
|
||||
var pos: Int = n
|
||||
|
||||
/** The index of the last entry that has been returned (more precisely, the value of [.pos] if [.pos] is positive,
|
||||
* or [Int.MIN_VALUE] if [.pos] is negative). It is -1 if either
|
||||
* we did not return an entry yet, or the last returned entry has been removed. */
|
||||
var last: Int = -1
|
||||
|
||||
/** A downward counter measuring how many entries must still be returned. */
|
||||
var c: Int = size
|
||||
|
||||
/** A boolean telling us whether we should return the entry with the null key. */
|
||||
var mustReturnNullKey: Boolean = this@Int2ObjectOpenHashMap.containsNullKey
|
||||
|
||||
/** A lazily allocated list containing keys of entries that have wrapped around the table because of removals. */
|
||||
var wrapped: IntArrayList? = null
|
||||
|
||||
|
||||
fun hasNext(): Boolean {
|
||||
return c != 0
|
||||
}
|
||||
|
||||
fun nextEntry(): Int {
|
||||
if (!hasNext()) throw NoSuchElementException()
|
||||
c--
|
||||
if (mustReturnNullKey) {
|
||||
mustReturnNullKey = false
|
||||
return n.also { last = it }
|
||||
}
|
||||
val key = this@Int2ObjectOpenHashMap.key
|
||||
while (true) {
|
||||
if (--pos < 0) { // We are just enumerating elements from the wrapped list.
|
||||
last = Int.MIN_VALUE
|
||||
if (wrapped == null) throw IllegalStateException()
|
||||
val k: Int = wrapped!!.get(-pos - 1)
|
||||
var p: Int = HashCommon.mix(k) and mask
|
||||
while (k != key[p]) p = (p + 1) and mask
|
||||
return p
|
||||
}
|
||||
if (key[pos] != 0) return pos.also { last = it }
|
||||
}
|
||||
}
|
||||
|
||||
/** Shifts left entries with the specified hash code, starting at the specified position,
|
||||
* and empties the resulting free entry.
|
||||
*
|
||||
* @param pos a starting position.
|
||||
*/
|
||||
private fun shiftKeys(pos: Int) { // Shift entries with the same hash.
|
||||
var pos = pos
|
||||
var last: Int
|
||||
var slot: Int
|
||||
var curr: Int
|
||||
val key = this@Int2ObjectOpenHashMap.key
|
||||
val value: Array<V?> = this@Int2ObjectOpenHashMap.value
|
||||
while (true) {
|
||||
pos = (pos.also { last = it } + 1) and mask
|
||||
while (true) {
|
||||
if ((key[pos].also { curr = it }) == 0) {
|
||||
key[last] = (0)
|
||||
value[last] = null
|
||||
return
|
||||
}
|
||||
slot = HashCommon.mix(curr) and mask
|
||||
if (if (last <= pos) last >= slot || slot > pos else slot in (pos + 1)..last) break
|
||||
pos = (pos + 1) and mask
|
||||
}
|
||||
if (pos < last) { // Wrapped entry.
|
||||
if (wrapped == null) wrapped = IntArrayList(2)
|
||||
wrapped!!.add(key[pos])
|
||||
}
|
||||
key[last] = curr
|
||||
value[last] = value[pos]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Iterator on entries
|
||||
private inner class EntryIterator : MapIterator(), Iterator<IntEntry<V>> {
|
||||
override fun next(): IntEntry<V> {
|
||||
val nextIndex = nextEntry()
|
||||
return IntEntry(key[nextIndex], value[nextIndex]!!)
|
||||
}
|
||||
}
|
||||
|
||||
// Iterator on keys
|
||||
private inner class KeyIterator : MapIterator(), IntIterator {
|
||||
override fun next(): Int {
|
||||
return key[nextEntry()]
|
||||
}
|
||||
}
|
||||
|
||||
// An iterator on values.
|
||||
private inner class ValueIterator : MapIterator(), Iterator<V> {
|
||||
override fun next(): V {
|
||||
return value[nextEntry()]!!
|
||||
}
|
||||
}
|
||||
|
||||
/** Rehashes the map, making the table as small as possible.
|
||||
*
|
||||
*
|
||||
* This method rehashes the table to the smallest size satisfying the
|
||||
* load factor. It can be used when the set will not be changed anymore, so
|
||||
* to optimize access speed and size.
|
||||
*
|
||||
*
|
||||
* If the table size is already the minimum possible, this method
|
||||
* does nothing.
|
||||
*
|
||||
* @return true if there was enough memory to trim the map.
|
||||
* @see .trim
|
||||
*/
|
||||
fun trim(n: Int = size): Boolean {
|
||||
val l: Int = HashCommon.nextPowerOfTwo(ceil((n / f)).toInt())
|
||||
if (l >= this.n || size > HashCommon.maxFill(l, f)) return true
|
||||
try {
|
||||
rehash(l)
|
||||
}
|
||||
catch (cantDoIt: Exception) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/** Rehashes the map.
|
||||
*
|
||||
*
|
||||
* This method implements the basic rehashing strategy, and may be
|
||||
* overridden by subclasses implementing different rehashing strategies (e.g.,
|
||||
* disk-based rehashing). However, you should not override this method
|
||||
* unless you understand the internal workings of this class.
|
||||
*
|
||||
* @param newN the new size
|
||||
*/
|
||||
private fun rehash(newN: Int) {
|
||||
val key = this.key
|
||||
val value = this.value
|
||||
val mask = newN - 1 // Note that this is used by the hashing macro
|
||||
val newKey = IntArray(newN + 1)
|
||||
val newValue = arrayOfNulls<Any>(newN + 1) as Array<V?>
|
||||
var i = n
|
||||
var pos: Int
|
||||
var j = realSize()
|
||||
while (j-- != 0) {
|
||||
while (key[--i] == 0);
|
||||
if (newKey[(HashCommon.mix(key[i]) and mask).also { pos = it }] != 0) while (newKey[(pos + 1 and mask).also { pos = it }] != 0);
|
||||
newKey[pos] = key[i]
|
||||
newValue[pos] = value[i]
|
||||
}
|
||||
newValue[newN] = value[n]
|
||||
n = newN
|
||||
this.mask = mask
|
||||
maxFill = HashCommon.maxFill(n, f)
|
||||
this.key = newKey
|
||||
this.value = newValue
|
||||
}
|
||||
|
||||
override fun equals(o: Any?): Boolean {
|
||||
if (o === this) return true
|
||||
if (o !is IntMap<*>) return false
|
||||
|
||||
if (this.size != o.size) return false
|
||||
|
||||
for ((key, value) in this.entries) {
|
||||
if (o[key] != value) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/** Returns a hash code for this map.
|
||||
*
|
||||
* This method overrides the generic method provided by the superclass.
|
||||
* Since `equals()` is not overriden, it is important
|
||||
* that the value returned by this method is the same value as
|
||||
* the one returned by the overriden method.
|
||||
*
|
||||
* @return a hash code for this map.
|
||||
*/
|
||||
override fun hashCode(): Int {
|
||||
var h = 0
|
||||
val key = this.key
|
||||
val value: Array<V?> = this.value
|
||||
var j = realSize()
|
||||
var i = 0
|
||||
var t: Int
|
||||
while (j-- != 0) {
|
||||
while (key[i] == 0) i++
|
||||
t = key[i]
|
||||
if (this !== value[i]) t = t xor (if (value[i] == null) 0 else value[i].hashCode())
|
||||
h += t
|
||||
i++
|
||||
} // Zero / null keys have hash zero.
|
||||
if (containsNullKey) h += if (value[n] == null) 0 else value[n].hashCode()
|
||||
return h
|
||||
}
|
||||
}
|
||||
@@ -1,372 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2024 Sebastiano Vigna
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.platform.syntax.impl.fastutil.ints
|
||||
|
||||
import com.intellij.platform.syntax.impl.fastutil.Arrays
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
/** A type-specific array-based list; provides some additional methods that use polymorphism to avoid (un)boxing.
|
||||
*
|
||||
*
|
||||
* This class implements a lightweight, fast, open, optimized,
|
||||
* reuse-oriented version of array-based lists. Instances of this class
|
||||
* represent a list with an array that is enlarged as needed when new entries
|
||||
* are created (by increasing its current length by 50%), but is
|
||||
* *never* made smaller (even on a [.clear]). A family of
|
||||
* [trimming methods][.trim] lets you control the size of the
|
||||
* backing array; this is particularly useful if you reuse instances of this class.
|
||||
* Range checks are equivalent to those of `java.util`'s classes, but
|
||||
* they are delayed as much as possible. The backing array is exposed by the
|
||||
* [.elements] method.
|
||||
*
|
||||
*
|
||||
* This class implements the bulk methods `removeElements()`,
|
||||
* `addElements()` and `getElements()` using
|
||||
* high-performance system calls (e.g., [ ][copyInto]) instead of
|
||||
* expensive loops.
|
||||
*/
|
||||
|
||||
@ApiStatus.Internal
|
||||
class IntArrayList: MutableIntList, Comparable<IntList> {
|
||||
/** The backing array. */
|
||||
private lateinit var a: IntArray
|
||||
|
||||
/** The current actual size of the list (never greater than the backing-array length). */
|
||||
override var size = 0
|
||||
|
||||
/** Creates a new array list using a given array.
|
||||
*
|
||||
* This constructor is only meant to be used by the wrapping methods.
|
||||
*
|
||||
* @param a the array that will be used to back this array list.
|
||||
*/
|
||||
private constructor(a: IntArray, @Suppress("unused") wrapped: Boolean) {
|
||||
this.a = a
|
||||
}
|
||||
|
||||
/** Creates a new array list and fills it with the elements of a given array.
|
||||
*
|
||||
* @param a an array whose elements will be used to fill the array list.
|
||||
* @param offset the first element to use.
|
||||
* @param length the number of elements to use.
|
||||
**/
|
||||
constructor(a: IntArray, offset: Int = 0, length: Int = a.size) : this(length) {
|
||||
a.copyInto(this.a, 0, offset, offset + length)
|
||||
size = length
|
||||
}
|
||||
|
||||
private fun initArrayFromCapacity(capacity: Int) {
|
||||
if (capacity < 0) throw IllegalArgumentException("Initial capacity ($capacity) is negative")
|
||||
a = if (capacity == 0) IntArray(0)
|
||||
else IntArray(capacity)
|
||||
}
|
||||
|
||||
|
||||
/** Creates a new array list with [.DEFAULT_INITIAL_CAPACITY] capacity. */
|
||||
constructor() {
|
||||
a = IntArrays.DEFAULT_EMPTY_ARRAY // We delay allocation
|
||||
}
|
||||
|
||||
/** Creates a new array list and fills it with the elements returned by an iterator..
|
||||
*
|
||||
* @param i an iterator whose returned elements will fill the array list.
|
||||
*/
|
||||
constructor(i: Iterator<Int>) : this() {
|
||||
while (i.hasNext()) this.add((i.next()))
|
||||
}
|
||||
|
||||
constructor(list: IntList): this() {
|
||||
for (i in list.indices) this.add(list[i])
|
||||
}
|
||||
|
||||
/** Creates a new array list with given capacity.
|
||||
*
|
||||
* @param capacity the initial capacity of the array list (may be 0).
|
||||
*/
|
||||
constructor(capacity: Int) {
|
||||
initArrayFromCapacity(capacity)
|
||||
}
|
||||
|
||||
/** Returns the backing array of this list.
|
||||
*
|
||||
* @return the backing array.
|
||||
*/
|
||||
fun elements(): IntArray {
|
||||
return a
|
||||
}
|
||||
|
||||
/** Ensures that this array list can contain the given number of entries without resizing.
|
||||
*
|
||||
* @param capacity the new minimum capacity for this array list.
|
||||
*/
|
||||
fun ensureCapacity(capacity: Int) {
|
||||
if (capacity <= a.size || (a.contentEquals(IntArrays.DEFAULT_EMPTY_ARRAY) && capacity <= DEFAULT_INITIAL_CAPACITY)) return
|
||||
a = IntArrays.ensureCapacity(a, capacity, size)
|
||||
check(size <= a.size)
|
||||
}
|
||||
|
||||
/** Grows this array list, ensuring that it can contain the given number of entries without resizing,
|
||||
* and in case increasing the current capacity at least by a factor of 50%.
|
||||
*
|
||||
* @param capacity the new minimum capacity for this array list.
|
||||
*/
|
||||
private fun grow(capacity: Int) {
|
||||
@Suppress("NAME_SHADOWING") var capacity = capacity
|
||||
if (capacity <= a.size) return
|
||||
if (!a.contentEquals(IntArrays.DEFAULT_EMPTY_ARRAY)) capacity = max(min((a.size + (a.size shr 1)), Arrays.MAX_ARRAY_SIZE), capacity)
|
||||
else if (capacity < DEFAULT_INITIAL_CAPACITY) capacity = DEFAULT_INITIAL_CAPACITY
|
||||
a = IntArrays.forceCapacity(a, capacity, size)
|
||||
check(size <= a.size)
|
||||
}
|
||||
|
||||
override fun add(index: Int, element: Int) {
|
||||
ensureIndex(index)
|
||||
grow(size + 1)
|
||||
if (index != size) a.copyInto(a, index + 1, index, size)
|
||||
a[index] = element
|
||||
size++
|
||||
check(size <= a.size)
|
||||
}
|
||||
|
||||
override fun add(element: Int) {
|
||||
grow(size + 1)
|
||||
a[size++] = element
|
||||
check(size <= a.size)
|
||||
}
|
||||
|
||||
override fun addAll(index: Int, elements: IntList): Boolean {
|
||||
ensureIndex(index)
|
||||
var index = index
|
||||
var n: Int = elements.size
|
||||
if (n == 0) return false
|
||||
grow(size + n)
|
||||
a.copyInto(a, destinationOffset = index + n, startIndex = index, endIndex = index + (size - index))
|
||||
var i = elements.indices.first
|
||||
size += n
|
||||
while (n-- != 0) a[index++] = elements[i++]
|
||||
check(size <= a.size)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun set(index: Int, element: Int): Int {
|
||||
if (index >= size || index < 0) throw IndexOutOfBoundsException("Index ($index) is out of bounds for size ($size)")
|
||||
val old = a[index]
|
||||
a[index] = element
|
||||
return old
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
size = 0
|
||||
check(size <= a.size)
|
||||
}
|
||||
|
||||
override operator fun get(index: Int): Int {
|
||||
if (index >= size || index < 0) throw IndexOutOfBoundsException("Index $index out of bounds for length $size")
|
||||
return a[index]
|
||||
}
|
||||
|
||||
|
||||
override fun removeAt(index: Int): Int {
|
||||
if (index >= size || index < 0) throw IndexOutOfBoundsException("Index ($index) out of bounds for length ($size)")
|
||||
val a = this.a
|
||||
val old = a[index]
|
||||
size -= 1
|
||||
if (index != size) a.copyInto(a, index, index + 1, size + 1)
|
||||
check(size <= a.size)
|
||||
return old
|
||||
}
|
||||
|
||||
override fun resize(size: Int) {
|
||||
if (size > a.size) a = IntArrays.forceCapacity(a, size, this.size)
|
||||
if (size > this.size) a.fill(0, this.size, size)
|
||||
this.size = size
|
||||
}
|
||||
|
||||
/** Trims the backing array if it is too large.
|
||||
*
|
||||
* If the current array length is smaller than or equal to
|
||||
* `n`, this method does nothing. Otherwise, it trims the
|
||||
* array length to the maximum between `n` and [.size].
|
||||
*
|
||||
*
|
||||
* This method is useful when reusing lists. [Clearing a][.clear] leaves the array length untouched. If you are reusing a list
|
||||
* many times, you can call this method with a typical
|
||||
* size to avoid keeping around a very large array just
|
||||
* because of a few large transient lists.
|
||||
*
|
||||
* @param n the threshold for the trimming.
|
||||
*/
|
||||
/** Trims this array list so that the capacity is equal to the size.
|
||||
*
|
||||
*/
|
||||
fun trim(n: Int = 0) {
|
||||
if (n >= a.size || size == a.size) return
|
||||
val t = IntArray(max(n, size))
|
||||
a.copyInto(t, 0, 0, size)
|
||||
a = t
|
||||
check(size <= a.size)
|
||||
}
|
||||
|
||||
override fun sort() {
|
||||
this.a.sort(0, this.size)
|
||||
}
|
||||
|
||||
/** Copies element of this type-specific list into the given array using optimized system calls.
|
||||
*
|
||||
* @param from the start index (inclusive).
|
||||
* @param a the destination array.
|
||||
* @param offset the offset into the destination array where to store the first element copied.
|
||||
* @param length the number of elements to be copied.
|
||||
*/
|
||||
override fun toArray(from: Int, a: IntArray, offset: Int, length: Int): IntArray {
|
||||
ensureIndex(from)
|
||||
Arrays.ensureOffsetLength(a, offset, length)
|
||||
this.a.copyInto(a, destinationOffset = offset, startIndex = from, endIndex = from + length)
|
||||
return a;
|
||||
}
|
||||
|
||||
fun getElements(from: Int, targetList: IntArrayList, offset: Int, length: Int) {
|
||||
ensureIndex(from)
|
||||
Arrays.ensureOffsetLength(a, offset, length)
|
||||
this.a.copyInto(targetList.a, destinationOffset = offset, startIndex = from, endIndex = from + length)
|
||||
}
|
||||
|
||||
/** Removes elements of this type-specific list using optimized system calls.
|
||||
*
|
||||
* @param from the start index (inclusive).
|
||||
* @param to the end index (exclusive).
|
||||
*/
|
||||
override fun removeElements(from: Int, to: Int) {
|
||||
Arrays.ensureFromTo(size, from, to)
|
||||
a.copyInto(a, destinationOffset = from, startIndex = to, endIndex = size)
|
||||
size -= (to - from)
|
||||
}
|
||||
|
||||
|
||||
/** Adds elements to this type-specific list using optimized system calls.
|
||||
*
|
||||
* @param index the index at which to add elements.
|
||||
* @param a the array containing the elements.
|
||||
* @param offset the offset of the first element to add.
|
||||
* @param length the number of elements to add.
|
||||
*/
|
||||
override fun addElements(index: Int, a: IntArray, offset: Int, length: Int) {
|
||||
ensureIndex(index)
|
||||
Arrays.ensureOffsetLength(a, offset, length)
|
||||
grow(size + length)
|
||||
this.a.copyInto(destination = this.a, destinationOffset = index + length, startIndex = index, endIndex = index + (size - index))
|
||||
a.copyInto(destination = this.a, destinationOffset = index, startIndex = offset, endIndex = offset + length)
|
||||
size += length
|
||||
}
|
||||
|
||||
override fun equals(o: Any?): Boolean {
|
||||
return o === this || (o is IntList && compareTo(o) == 0)
|
||||
}
|
||||
|
||||
/** Compares this array list to another array list.
|
||||
*
|
||||
* @apiNote This method exists only for sake of efficiency. The implementation
|
||||
* inherited from the abstract implementation would already work.
|
||||
*
|
||||
* @param l an array list.
|
||||
* @return a negative integer,
|
||||
* zero, or a positive integer as this list is lexicographically less than, equal
|
||||
* to, or greater than the argument.
|
||||
*/
|
||||
override fun compareTo(l: IntList): Int {
|
||||
val s1 = length()
|
||||
val s2 = l.length()
|
||||
var e1: Int
|
||||
var e2: Int
|
||||
var r: Int
|
||||
var i = 0
|
||||
while (i < s1 && i < s2) {
|
||||
e1 = this[i]
|
||||
e2 = l[i]
|
||||
r = when {
|
||||
e1 > e2 -> 1
|
||||
e1 < e2 -> -1
|
||||
else -> 0
|
||||
}
|
||||
if (r != 0) return r
|
||||
i++
|
||||
}
|
||||
return if (i < s2) -1 else (if (i < s1) 1 else 0)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var i = indices.first
|
||||
var h = 1
|
||||
var s = size
|
||||
while (s-- != 0) {
|
||||
val k = get(i++)
|
||||
h = 31 * h + (k)
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
fun clone(): IntArrayList {
|
||||
val clone = IntArrayList()
|
||||
clone.size = size
|
||||
clone.a = this.a.copyOf()
|
||||
return clone
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val s = StringBuilder()
|
||||
var i = indices.first
|
||||
var n = size
|
||||
var k: Int
|
||||
var first = true
|
||||
s.append("[")
|
||||
while (n-- != 0) {
|
||||
if (first) first = false
|
||||
else s.append(", ")
|
||||
k = get(i)
|
||||
i += 1
|
||||
s.append(k.toString())
|
||||
}
|
||||
s.append("]")
|
||||
return s.toString()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val DEFAULT_INITIAL_CAPACITY: Int = 10
|
||||
|
||||
fun wrap(a: IntArray): IntArrayList {
|
||||
return wrap(a, a.size)
|
||||
}
|
||||
|
||||
fun wrap(a: IntArray, length: Int): IntArrayList {
|
||||
if (length > a.size) throw IllegalArgumentException("The specified length (" + length + ") is greater than the array size (" + a.size + ")")
|
||||
val l = IntArrayList(a, true)
|
||||
l.size = length
|
||||
return l
|
||||
}
|
||||
|
||||
fun of(): IntArrayList {
|
||||
return IntArrayList()
|
||||
}
|
||||
|
||||
fun of(vararg init: Int): IntArrayList {
|
||||
return wrap(init)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
package com.intellij.platform.syntax.impl.fastutil.ints
|
||||
|
||||
import com.intellij.platform.syntax.impl.fastutil.Arrays
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
@ApiStatus.Internal
|
||||
object IntArrays {
|
||||
val EMPTY_ARRAY: IntArray = intArrayOf()
|
||||
|
||||
val DEFAULT_EMPTY_ARRAY: IntArray = intArrayOf()
|
||||
|
||||
fun forceCapacity(array: IntArray, length: Int, preserve: Int): IntArray {
|
||||
val t = IntArray(length)
|
||||
array.copyInto(t, 0, 0, preserve)
|
||||
return t
|
||||
}
|
||||
|
||||
fun ensureCapacity(array: IntArray, length: Int, preserve: Int): IntArray {
|
||||
return if (length > array.size) forceCapacity(array, length, preserve)
|
||||
else array
|
||||
}
|
||||
|
||||
/** Grows the given array to the maximum between the given length and
|
||||
* the current length increased by 50%, provided that the given
|
||||
* length is larger than the current length.
|
||||
*
|
||||
*
|
||||
* If you want complete control on the array growth, you
|
||||
* should probably use `ensureCapacity()` instead.
|
||||
*
|
||||
* @param array an array.
|
||||
* @param length the new minimum length for this array.
|
||||
* @return `array`, if it can contain `length`
|
||||
* entries; otherwise, an array with
|
||||
* max(`length`,`array.length`/) entries whose first
|
||||
* `array.length` entries are the same as those of `array`.
|
||||
*/
|
||||
fun grow(array: IntArray, length: Int): IntArray {
|
||||
return grow(array, length, array.size)
|
||||
}
|
||||
|
||||
/** Grows the given array to the maximum between the given length and
|
||||
* the current length increased by 50%, provided that the given
|
||||
* length is larger than the current length, preserving just a part of the array.
|
||||
*
|
||||
* If you want complete control on the array growth, you
|
||||
* should probably use `ensureCapacity()` instead.
|
||||
*
|
||||
* @param array an array.
|
||||
* @param length the new minimum length for this array.
|
||||
* @param preserve the number of elements of the array that must be preserved in case a new allocation is necessary.
|
||||
* @return `array`, if it can contain `length`
|
||||
* entries; otherwise, an array with
|
||||
* max(`length`,`array.length`/) entries whose first
|
||||
* `preserve` entries are the same as those of `array`.
|
||||
*/
|
||||
fun grow(array: IntArray, length: Int, preserve: Int): IntArray {
|
||||
if (length > array.size) {
|
||||
val newLength = max(min((array.size + (array.size shr 1)), Arrays.MAX_ARRAY_SIZE), length)
|
||||
val t = IntArray(newLength)
|
||||
array.copyInto(t, destinationOffset = 0, startIndex = 0, endIndex = preserve)
|
||||
return t
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
/** Trims the given array to the given length.
|
||||
*
|
||||
* @param array an array.
|
||||
* @param length the new maximum length for the array.
|
||||
* @return `array`, if it contains `length`
|
||||
* entries or less; otherwise, an array with
|
||||
* `length` entries whose entries are the same as
|
||||
* the first `length` entries of `array`.
|
||||
*/
|
||||
fun trim(array: IntArray, length: Int): IntArray {
|
||||
if (length >= array.size) return array
|
||||
val t = if (length == 0) EMPTY_ARRAY else IntArray(length)
|
||||
array.copyInto(t, destinationOffset = 0, startIndex = 0, endIndex = length)
|
||||
return t
|
||||
}
|
||||
|
||||
|
||||
fun unwrap(i: IntIterator): IntArray {
|
||||
return unwrap(i, Int.MAX_VALUE)
|
||||
}
|
||||
|
||||
/** Unwraps an iterator into an array starting at a given offset for a given number of elements.
|
||||
*
|
||||
*
|
||||
* This method iterates over the given type-specific iterator and stores the elements
|
||||
* returned, up to a maximum of `length`, in the given array starting at `offset`.
|
||||
* The number of actually unwrapped elements is returned (it may be less than `max` if
|
||||
* the iterator emits less than `max` elements).
|
||||
*
|
||||
* @param i a type-specific iterator.
|
||||
* @param array an array to contain the output of the iterator.
|
||||
* @param offset the first element of the array to be returned.
|
||||
* @param max the maximum number of elements to unwrap.
|
||||
* @return the number of elements unwrapped.
|
||||
*/
|
||||
fun unwrap(i: IntIterator, array: IntArray, offset: Int, max: Int): Int {
|
||||
var offset = offset
|
||||
if (max < 0) throw IllegalArgumentException("The maximum number of elements ($max) is negative")
|
||||
if (offset < 0 || offset + max > array.size) throw IllegalArgumentException()
|
||||
var j = max
|
||||
while (j-- != 0 && i.hasNext()) array[offset++] = i.next()
|
||||
return max - j - 1
|
||||
}
|
||||
|
||||
/** Unwraps an iterator into an array.
|
||||
*
|
||||
*
|
||||
* This method iterates over the given type-specific iterator and stores the
|
||||
* elements returned in the given array. The iteration will stop when the
|
||||
* iterator has no more elements or when the end of the array has been reached.
|
||||
*
|
||||
* @param i a type-specific iterator.
|
||||
* @param array an array to contain the output of the iterator.
|
||||
* @return the number of elements unwrapped.
|
||||
*/
|
||||
fun unwrap(i: IntIterator, array: IntArray): Int {
|
||||
return unwrap(i, array, 0, array.size)
|
||||
}
|
||||
|
||||
/** Unwraps an iterator, returning an array, with a limit on the number of elements.
|
||||
*
|
||||
*
|
||||
* This method iterates over the given type-specific iterator and returns an array
|
||||
* containing the elements returned by the iterator. At most `max` elements
|
||||
* will be returned.
|
||||
*
|
||||
* @param i a type-specific iterator.
|
||||
* @param max the maximum number of elements to be unwrapped.
|
||||
* @return an array containing the elements returned by the iterator (at most `max`).
|
||||
*/
|
||||
fun unwrap(i: IntIterator, max: Int): IntArray {
|
||||
var max = max
|
||||
if (max < 0) throw IllegalArgumentException("The maximum number of elements ($max) is negative")
|
||||
var array = IntArray(16)
|
||||
var j = 0
|
||||
while (max-- != 0 && i.hasNext()) {
|
||||
if (j == array.size) array = grow(array, j + 1)
|
||||
array[j++] = i.next()
|
||||
}
|
||||
return trim(array, j)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.syntax.impl.fastutil.ints
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
data class IntEntry<T>(var key: Int, val value: T)
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.syntax.impl.fastutil.ints
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
interface IntIterator {
|
||||
fun next(): Int
|
||||
fun hasNext(): Boolean
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.syntax.impl.fastutil.ints
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
inline fun IntIterator.forEach(action: (Int) -> Unit) {
|
||||
while(this.hasNext()) action(this.next())
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package com.intellij.platform.syntax.impl.fastutil.ints
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
interface IntList {
|
||||
|
||||
val size: Int
|
||||
|
||||
/** Returns the element at the specified position in this list. */
|
||||
operator fun get(index: Int): Int
|
||||
|
||||
/** Copies (hopefully quickly) elements of this type-specific list into the given array.
|
||||
*
|
||||
* @param from the start index (inclusive).
|
||||
* @param a the destination array. is an IntArray, so that we can use copyInto
|
||||
* @param offset the offset into the destination array where to store the first element copied.
|
||||
* @param length the number of elements to be copied.
|
||||
*/
|
||||
fun toArray(from: Int, a: IntArray, offset: Int, length: Int): IntArray
|
||||
|
||||
companion object {
|
||||
/** Returns an immutable empty list.
|
||||
*
|
||||
* @return an immutable empty list.
|
||||
*/
|
||||
fun of(): IntList {
|
||||
return IntArrayList.of()
|
||||
}
|
||||
|
||||
/** Returns an immutable list with the element given.
|
||||
*
|
||||
* @param e the element that the returned list will contain.
|
||||
* @return an immutable list containing `e`.
|
||||
*/
|
||||
fun of(e: Int): IntList {
|
||||
return IntArrayList.of(e)
|
||||
}
|
||||
|
||||
/** Returns an immutable list with the elements given.
|
||||
*
|
||||
* @param e0 the first element.
|
||||
* @param e1 the second element.
|
||||
* @return an immutable list containing `e0` and `e1`.
|
||||
*/
|
||||
fun of(e0: Int, e1: Int): IntList {
|
||||
return IntArrayList.of(e0, e1)
|
||||
}
|
||||
|
||||
/** Returns an immutable list with the elements given.
|
||||
*
|
||||
* @param e0 the first element.
|
||||
* @param e1 the second element.
|
||||
* @param e2 the third element.
|
||||
* @return an immutable list containing `e0`, `e1`, and `e2`.
|
||||
*/
|
||||
fun of(e0: Int, e1: Int, e2: Int): IntList {
|
||||
return IntArrayList.of(e0, e1, e2)
|
||||
}
|
||||
|
||||
/** Returns an immutable list with the elements given.
|
||||
*
|
||||
*
|
||||
* Note that this method does not perform a defensive copy.
|
||||
*
|
||||
* @param a a list of elements that will be used to initialize the immutable list.
|
||||
* @return an immutable list containing the elements of `a`.
|
||||
*/
|
||||
fun of(vararg a: Int): IntList {
|
||||
when (a.size) {
|
||||
0 -> return of()
|
||||
1 -> return of(a[0])
|
||||
else -> {}
|
||||
}
|
||||
return IntArrayList.of(*a)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.syntax.impl.fastutil.ints
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun IntList.containsAll(elements: Collection<Int>): Boolean {
|
||||
for (element in elements) if (!contains(element)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
internal fun IntList.ensureIndex(index: Int) {
|
||||
if (index < 0) throw IndexOutOfBoundsException("Index ($index) is negative")
|
||||
if (index > size) throw IndexOutOfBoundsException("Index ($index) is greater than list size ($size)")
|
||||
}
|
||||
|
||||
internal inline fun IntList.forEach(action: (Int) -> Unit) {for(index in indices) action(get(index))}
|
||||
|
||||
internal fun IntList.contains(element: Int): Boolean {
|
||||
return indexOf(element) != -1
|
||||
}
|
||||
|
||||
internal fun IntList.isEmpty(): Boolean {
|
||||
return size == 0
|
||||
}
|
||||
|
||||
internal fun IntList.isNotEmpty(): Boolean {
|
||||
return size != 0
|
||||
}
|
||||
|
||||
internal fun IntList.sum(): Int {
|
||||
var sum = 0
|
||||
for (i in indices) sum += get(i)
|
||||
return sum
|
||||
}
|
||||
|
||||
internal val IntList.indices: IntRange
|
||||
get() = 0 ..<size
|
||||
|
||||
internal fun IntList.length(): Int {
|
||||
return size
|
||||
}
|
||||
|
||||
internal fun IntList.toArray(): IntArray {
|
||||
val size = size
|
||||
if (size == 0) return IntArrays.EMPTY_ARRAY
|
||||
val ret = IntArray(size)
|
||||
toArray(0, ret, 0, size)
|
||||
return ret
|
||||
}
|
||||
|
||||
internal fun IntList.indexOf(element: Int): Int {
|
||||
for(i in 0 until size) {
|
||||
if (element == get(i)) return i
|
||||
}
|
||||
return -1
|
||||
|
||||
}
|
||||
|
||||
internal fun IntList.toArray(from: Int, to: Int, a: IntArray): IntArray {
|
||||
@Suppress("NAME_SHADOWING") var a = a
|
||||
if (a.size < size) a = a.copyOf(size)
|
||||
toArray(from, a, 0, to)
|
||||
return a
|
||||
}
|
||||
|
||||
|
||||
internal fun IntList.lastIndexOf(element: Int): Int {
|
||||
var i = size
|
||||
while (i-- != 0) {
|
||||
if (element == get(i)) return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
internal fun <R> IntList.firstNotNullOfOrNull(transform: (Int) -> R?): R? {
|
||||
for (index in this.indices) {
|
||||
val result = transform(this[index])
|
||||
if (result != null) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.syntax.impl.fastutil.ints
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
interface IntMap<V> {
|
||||
val size: Int
|
||||
val keys: IntIterator
|
||||
val values: Iterator<V>
|
||||
val entries: Iterator<IntEntry<V>>
|
||||
|
||||
operator fun get(key: Int): V?
|
||||
}
|
||||
|
||||
@@ -1,550 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2024 Sebastiano Vigna
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.platform.syntax.impl.fastutil.ints
|
||||
|
||||
import com.intellij.platform.syntax.impl.fastutil.Arrays
|
||||
import com.intellij.platform.syntax.impl.fastutil.Hash
|
||||
import com.intellij.platform.syntax.impl.fastutil.HashCommon
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
/** A type-specific hash set with with a fast, small-footprint implementation.
|
||||
*
|
||||
*
|
||||
* Instances of this class use a hash table to represent a set. The table is
|
||||
* filled up to a specified *load factor*, and then doubled in size to
|
||||
* accommodate new entries. If the table is emptied below *one fourth*
|
||||
* of the load factor, it is halved in size; however, the table is never reduced to a
|
||||
* size smaller than that at creation time: this approach makes it
|
||||
* possible to create sets with a large capacity in which insertions and
|
||||
* deletions do not cause immediately rehashing. Moreover, halving is
|
||||
* not performed when deleting entries from an iterator, as it would interfere
|
||||
* with the iteration process.
|
||||
*
|
||||
*
|
||||
* Note that [.clear] does not modify the hash table size.
|
||||
* Rather, a family of [trimming][.trim] lets you control the size of the table; this is particularly useful
|
||||
* if you reuse instances of this class.
|
||||
*
|
||||
* @see Hash
|
||||
*
|
||||
* @see HashCommon
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
class IntOpenHashSet(
|
||||
expected: Int = Hash.DEFAULT_INITIAL_SIZE,
|
||||
f: Float = Hash.DEFAULT_LOAD_FACTOR,
|
||||
): MutableIntSet {
|
||||
/** The array of keys. */
|
||||
private var key: IntArray
|
||||
|
||||
/** The mask for wrapping a position counter. */
|
||||
private var mask = 0
|
||||
|
||||
/** Whether this set contains the null key. */
|
||||
private var containsNull = false
|
||||
|
||||
/** The current table size. Note that an additional element is allocated for storing the null key. */
|
||||
private var n = 0
|
||||
|
||||
/** Threshold after which we rehash. It must be the table size times [.f]. */
|
||||
private var maxFill = 0
|
||||
|
||||
/** We never resize below this threshold, which is the construction-time {#n}. */
|
||||
private val minN: Int
|
||||
|
||||
/** Number of entries in the set (including the null key, if present). */
|
||||
override var size = 0
|
||||
|
||||
/** The acceptable load factor. */
|
||||
private val f: Float
|
||||
|
||||
override val values: MutableIntIterator
|
||||
get() = SetIterator()
|
||||
|
||||
/** Creates a new hash set.
|
||||
* The actual table size will be the least power of two greater than `expected`/`f`.
|
||||
*/
|
||||
init {
|
||||
if (f <= 0 || f >= 1) throw IllegalArgumentException("Load factor must be greater than 0 and smaller than 1")
|
||||
if (expected < 0) throw IllegalArgumentException("The expected number of elements must be nonnegative")
|
||||
this.f = f
|
||||
n = HashCommon.arraySize(expected, f)
|
||||
minN = n
|
||||
mask = n - 1
|
||||
maxFill = HashCommon.maxFill(n, f)
|
||||
key = IntArray(n + 1)
|
||||
}
|
||||
|
||||
/** Creates a new hash set copying a given collection.
|
||||
*
|
||||
* @param c a [IntList] to be copied into the new hash set.
|
||||
* @param f the load factor.
|
||||
*/
|
||||
constructor(c: IntList, f: Float = Hash.DEFAULT_LOAD_FACTOR) : this(c.size, f) {
|
||||
addAll(c)
|
||||
}
|
||||
|
||||
constructor(c: Collection<Int>, f:Float = Hash.DEFAULT_LOAD_FACTOR) : this(c.size, f) {
|
||||
addAll(c)
|
||||
}
|
||||
|
||||
/** Creates a new hash set using elements provided by a type-specific iterator.
|
||||
*
|
||||
* @param i a type-specific iterator whose elements will fill the set.
|
||||
* @param f the load factor.
|
||||
*/
|
||||
constructor(
|
||||
i: IntIterator,
|
||||
f: Float = Hash.DEFAULT_LOAD_FACTOR,
|
||||
) : this(Hash.DEFAULT_INITIAL_SIZE, f) {
|
||||
while (i.hasNext()) add(i.next())
|
||||
}
|
||||
|
||||
/** Creates a new hash set with [Hash.DEFAULT_LOAD_FACTOR] as load factor and fills it with the elements of a given array.
|
||||
*
|
||||
* @param a an array whose elements will be used to fill the set.
|
||||
* @param offset the first element to use.
|
||||
* @param length the number of elements to use.
|
||||
* @param f the load factor
|
||||
*/
|
||||
constructor(
|
||||
a: IntList,
|
||||
offset: Int,
|
||||
length: Int,
|
||||
f: Float = Hash.DEFAULT_LOAD_FACTOR,
|
||||
) : this(if (length < 0) 0 else length, f) {
|
||||
Arrays.ensureOffsetLength(a, offset, length)
|
||||
for (i in 0 until length) add(a[offset + i])
|
||||
}
|
||||
|
||||
private fun realSize(): Int {
|
||||
return if (containsNull) size - 1 else size
|
||||
}
|
||||
|
||||
/** Ensures that this set can hold a certain number of elements without rehashing.
|
||||
*
|
||||
* @param capacity a number of elements; there will be no rehashing unless
|
||||
* the set [size][.size] exceeds this number.
|
||||
*/
|
||||
private fun ensureCapacity(capacity: Int) {
|
||||
val needed: Int = HashCommon.arraySize(capacity, f)
|
||||
if (needed > n) rehash(needed)
|
||||
}
|
||||
|
||||
private fun tryCapacity(capacity: Long) {
|
||||
val needed = min(1 shl 30, max(2, HashCommon.nextPowerOfTwo(ceil(capacity / f).toLong()).toInt()))
|
||||
if (needed > n) rehash(needed)
|
||||
}
|
||||
|
||||
fun addAll(elements: Collection<Int>): Boolean {
|
||||
if (f <= .5) ensureCapacity(elements.size) // The resulting collection will be sized for c.size() elements
|
||||
else tryCapacity((size + elements.size).toLong()) // The resulting collection will be tentatively sized for size() + c.size() elements
|
||||
var retVal = false
|
||||
|
||||
val i = elements.iterator()
|
||||
while (i.hasNext()) {
|
||||
if (add(i.next())) retVal = true
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
fun addAll(elements: IntList): Boolean {
|
||||
if (f <= .5) ensureCapacity(elements.size) // The resulting collection will be sized for c.size() elements
|
||||
else tryCapacity((size + elements.size).toLong()) // The resulting collection will be tentatively sized for size() + c.size() elements
|
||||
|
||||
var modified = false
|
||||
for (index in elements.indices) {
|
||||
if (add(elements[index])) modified = true
|
||||
}
|
||||
return modified
|
||||
}
|
||||
|
||||
override fun add(element: Int): Boolean {
|
||||
var pos: Int
|
||||
if (element == 0) {
|
||||
if (containsNull) return false
|
||||
containsNull = true
|
||||
}
|
||||
else {
|
||||
var curr: Int
|
||||
val key = this.key // The starting point.
|
||||
if (key[(HashCommon.mix(element) and mask).also {
|
||||
pos = it
|
||||
}].also { curr = it } != 0) {
|
||||
if (curr == element) return false
|
||||
while (key[((pos + 1) and mask).also { pos = it }].also {
|
||||
curr = it
|
||||
} != 0) if (curr == element) return false
|
||||
}
|
||||
key[pos] = element
|
||||
}
|
||||
|
||||
if (size++ >= maxFill) rehash(HashCommon.arraySize(size + 1, f))
|
||||
return true
|
||||
}
|
||||
|
||||
/** Shifts left entries with the specified hash code, starting at the specified position,
|
||||
* and empties the resulting free entry.
|
||||
*
|
||||
* @param pos a starting position.
|
||||
*/
|
||||
private fun shiftKeys(pos: Int) { // Shift entries with the same hash.
|
||||
@Suppress("NAME_SHADOWING") var pos = pos
|
||||
var last: Int
|
||||
var slot: Int
|
||||
var curr: Int
|
||||
val key = this.key
|
||||
while (true) {
|
||||
pos = ((pos.also { last = it }) + 1) and mask
|
||||
while (true) {
|
||||
if ((key[pos].also { curr = it }) == 0) {
|
||||
key[last] = 0
|
||||
return
|
||||
}
|
||||
slot = HashCommon.mix(curr) and mask
|
||||
if (if (last <= pos) last >= slot || slot > pos else slot in (pos + 1)..last) break
|
||||
pos = (pos + 1) and mask
|
||||
}
|
||||
key[last] = curr
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeEntry(pos: Int): Boolean {
|
||||
size--
|
||||
shiftKeys(pos)
|
||||
if (n > minN && size < maxFill / 4 && n > Hash.DEFAULT_INITIAL_SIZE) rehash(n / 2)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun removeNullEntry(): Boolean {
|
||||
containsNull = false
|
||||
key[n] = 0
|
||||
size--
|
||||
if (n > minN && size < maxFill / 4 && n > Hash.DEFAULT_INITIAL_SIZE) rehash(n / 2)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun remove(element: Int): Boolean {
|
||||
if (element == 0) {
|
||||
if (containsNull) return removeNullEntry()
|
||||
return false
|
||||
}
|
||||
var curr: Int
|
||||
val key = this.key
|
||||
var pos: Int // The starting point.
|
||||
if (key[(HashCommon.mix(element) and mask).also {
|
||||
pos = it
|
||||
}].also { curr = it } == 0) return false
|
||||
if (element == curr) return removeEntry(pos)
|
||||
while (true) {
|
||||
if (key[(pos + 1 and mask).also { pos = it }].also {
|
||||
curr = it
|
||||
} == 0) return false
|
||||
if (element == curr) return removeEntry(pos)
|
||||
}
|
||||
}
|
||||
|
||||
override fun contains(element: Int): Boolean {
|
||||
if (element == 0) return containsNull
|
||||
var curr: Int
|
||||
val key = this.key
|
||||
var pos: Int // The starting point.
|
||||
if (key[(HashCommon.mix(element) and mask).also {
|
||||
pos = it
|
||||
}].also { curr = it } == 0) return false
|
||||
if (element == curr) return true
|
||||
while (true) {
|
||||
if (key[(pos + 1 and mask).also { pos = it }].also {
|
||||
curr = it
|
||||
} == 0) return false
|
||||
if (element == curr) return true
|
||||
}
|
||||
}
|
||||
|
||||
/* Removes all elements from this set.
|
||||
* To increase object reuse, this method does not change the table size.
|
||||
* If you want to reduce the table size, you must use trim().
|
||||
*/
|
||||
fun clear() {
|
||||
if (size == 0) return
|
||||
size = 0
|
||||
containsNull = false
|
||||
key.fill(0)
|
||||
}
|
||||
|
||||
/** An iterator over a hash set. */
|
||||
private inner class SetIterator : MutableIntIterator {
|
||||
/** The index of the last entry returned, if positive or zero; initially, [.n]. If negative, the last
|
||||
* element returned was that of index `- pos - 1` from the [.wrapped] list. */
|
||||
var pos = n
|
||||
|
||||
/** The index of the last entry that has been returned (more precisely, the value of [.pos] if [.pos] is positive,
|
||||
* or [Int.MIN_VALUE] if [.pos] is negative). It is -1 if either
|
||||
* we did not return an entry yet, or the last returned entry has been removed. */
|
||||
var last = -1
|
||||
|
||||
/** A downward counter measuring how many entries must still be returned. */
|
||||
var c: Int = size
|
||||
|
||||
/** A boolean telling us whether we should return the null key. */
|
||||
var mustReturnNull: Boolean = this@IntOpenHashSet.containsNull
|
||||
|
||||
/** A lazily allocated list containing elements that have wrapped around the table because of removals. */
|
||||
lateinit var wrapped: IntArrayList
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return c != 0
|
||||
}
|
||||
|
||||
override fun next(): Int {
|
||||
if (!hasNext()) throw NoSuchElementException()
|
||||
c--
|
||||
val key = this@IntOpenHashSet.key
|
||||
if (mustReturnNull) {
|
||||
mustReturnNull = false
|
||||
last = n
|
||||
return key[n]
|
||||
}
|
||||
while (true) {
|
||||
if (--pos < 0) { // We are just enumerating elements from the wrapped list.
|
||||
last = Int.MIN_VALUE
|
||||
return wrapped.get(-pos - 1)
|
||||
}
|
||||
if (key[pos] != 0) return key[pos.also {
|
||||
last = it
|
||||
}]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun remove() {
|
||||
if (last == -1) throw IllegalStateException()
|
||||
if (last == n) {
|
||||
this@IntOpenHashSet.containsNull = false
|
||||
key[n] = 0
|
||||
}
|
||||
else if (pos >= 0) shiftKeys(last)
|
||||
else { // We're removing wrapped entries.
|
||||
this@IntOpenHashSet.remove(wrapped.get(-pos - 1))
|
||||
last = -1 // Note that we must not decrement size
|
||||
return
|
||||
}
|
||||
size--
|
||||
last = -1 // You can no longer remove this entry.
|
||||
}
|
||||
|
||||
/** Shifts left entries with the specified hash code, starting at the specified position,
|
||||
* and empties the resulting free entry.
|
||||
*
|
||||
* @param pos a starting position.
|
||||
*/
|
||||
private fun shiftKeys(pos: Int) { // Shift entries with the same hash.
|
||||
@Suppress("NAME_SHADOWING") var pos = pos
|
||||
var last: Int
|
||||
var slot: Int
|
||||
var curr: Int
|
||||
val key = this@IntOpenHashSet.key
|
||||
while (true) {
|
||||
pos = (pos.also { last = it } + 1) and mask
|
||||
while (true) {
|
||||
if (key[pos].also { curr = it } == 0) {
|
||||
key[last] = 0
|
||||
return
|
||||
}
|
||||
slot = HashCommon.mix(curr) and mask
|
||||
if (if (last <= pos) last >= slot || slot > pos else slot in (pos + 1)..last) break
|
||||
pos = (pos + 1) and mask
|
||||
}
|
||||
if (pos < last) { // Wrapped entry.
|
||||
if (!::wrapped.isInitialized) wrapped = IntArrayList(2)
|
||||
wrapped.add(key[pos])
|
||||
}
|
||||
key[last] = curr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method rehashes the table to the smallest size satisfying the
|
||||
* load factor. It can be used when the set will not be changed anymore, so
|
||||
* to optimize access speed and size.
|
||||
*
|
||||
*
|
||||
* If the table size is already the minimum possible, this method
|
||||
* does nothing.
|
||||
*
|
||||
* @return true if there was enough memory to trim the set.
|
||||
* @see .trim
|
||||
*/
|
||||
fun trim(n: Int = size): Boolean {
|
||||
val l = HashCommon.nextPowerOfTwo(ceil(n / f).toInt())
|
||||
if (l >= this.n || size > HashCommon.maxFill(l, f)) return true
|
||||
try {
|
||||
rehash(l)
|
||||
}
|
||||
catch (cantDoIt: Throwable) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/** Rehashes the set.
|
||||
*
|
||||
* This method implements the basic rehashing strategy, and may be
|
||||
* overriden by subclasses implementing different rehashing strategies (e.g.,
|
||||
* disk-based rehashing). However, you should not override this method
|
||||
* unless you understand the internal workings of this class.
|
||||
*
|
||||
* @param newN the new size
|
||||
*/
|
||||
private fun rehash(newN: Int) {
|
||||
val key = this.key
|
||||
val mask = newN - 1 // Note that this is used by the hashing macro
|
||||
val newKey = IntArray(newN + 1)
|
||||
var i = n
|
||||
var pos: Int
|
||||
var j = realSize()
|
||||
while (j-- != 0) {
|
||||
while (key[--i] == 0);
|
||||
if (newKey[(HashCommon.mix(key[i]) and mask).also {
|
||||
pos = it
|
||||
}] != 0) while (newKey[((pos + 1) and mask).also {
|
||||
pos = it
|
||||
}] != 0);
|
||||
newKey[pos] = key[i]
|
||||
}
|
||||
n = newN
|
||||
this.mask = mask
|
||||
maxFill = HashCommon.maxFill(n, f)
|
||||
this.key = newKey
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other == null) return false
|
||||
if (super.equals(other)) return true
|
||||
if (other is IntSet) {
|
||||
if (other.size != this.size) return false
|
||||
return containsAll(other)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** Returns a hash code for this set.
|
||||
*
|
||||
* This method overrides the generic method provided by the superclass.
|
||||
* Since `equals()` is not overriden, it is important
|
||||
* that the value returned by this method is the same value as
|
||||
* the one returned by the overriden method.
|
||||
*
|
||||
* @return a hash code for this set.
|
||||
*/
|
||||
override fun hashCode(): Int {
|
||||
var h = 0
|
||||
val key = this@IntOpenHashSet.key
|
||||
var j = realSize()
|
||||
var i = 0
|
||||
while (j-- != 0) {
|
||||
while (key[i] == 0) i++
|
||||
h += key[i]
|
||||
i++
|
||||
} // Zero / null have hash zero.
|
||||
return h
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
/** Creates a new empty hash set.
|
||||
*
|
||||
* @return a new empty hash set.
|
||||
*/
|
||||
fun of(): IntOpenHashSet {
|
||||
return IntOpenHashSet()
|
||||
}
|
||||
|
||||
/** Creates a new hash set with [Hash.DEFAULT_LOAD_FACTOR] as load factor
|
||||
* using the given element.
|
||||
*
|
||||
* @param e the element that the returned set will contain.
|
||||
* @return a new hash set with [Hash.DEFAULT_LOAD_FACTOR] as load factor containing `e`.
|
||||
*/
|
||||
fun of(e: Int): IntOpenHashSet {
|
||||
val result = IntOpenHashSet(1, Hash.DEFAULT_LOAD_FACTOR)
|
||||
result.add(e)
|
||||
return result
|
||||
}
|
||||
|
||||
/** Creates a new hash set with [Hash.DEFAULT_LOAD_FACTOR] as load factor
|
||||
* using the elements given.
|
||||
*
|
||||
* @param e0 the first element.
|
||||
* @param e1 the second element.
|
||||
* @return a new hash set with [Hash.DEFAULT_LOAD_FACTOR] as load factor containing `e0` and `e1`.
|
||||
* @throws IllegalArgumentException if there were duplicate entries.
|
||||
*/
|
||||
fun of(e0: Int, e1: Int): IntOpenHashSet {
|
||||
val result = IntOpenHashSet(2, Hash.DEFAULT_LOAD_FACTOR)
|
||||
result.add(e0)
|
||||
if (!result.add(e1)) {
|
||||
throw IllegalArgumentException("Duplicate element: $e1")
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/** Creates a new hash set with [Hash.DEFAULT_LOAD_FACTOR] as load factor
|
||||
* using the elements given.
|
||||
*
|
||||
* @param e0 the first element.
|
||||
* @param e1 the second element.
|
||||
* @param e2 the third element.
|
||||
* @return a new hash set with [Hash.DEFAULT_LOAD_FACTOR] as load factor containing `e0`, `e1`, and `e2`.
|
||||
* @throws IllegalArgumentException if there were duplicate entries.
|
||||
*/
|
||||
fun of(e0: Int, e1: Int, e2: Int): IntOpenHashSet {
|
||||
val result = IntOpenHashSet(3, Hash.DEFAULT_LOAD_FACTOR)
|
||||
result.add(e0)
|
||||
if (!result.add(e1)) {
|
||||
throw IllegalArgumentException("Duplicate element: $e1")
|
||||
}
|
||||
if (!result.add(e2)) {
|
||||
throw IllegalArgumentException("Duplicate element: $e2")
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/** Creates a new hash set with [Hash.DEFAULT_LOAD_FACTOR] as load factor
|
||||
* using a list of elements.
|
||||
*
|
||||
* @param a a list of elements that will be used to initialize the new hash set.
|
||||
* @return a new hash set with [Hash.DEFAULT_LOAD_FACTOR] as load factor containing the elements of `a`.
|
||||
* @throws IllegalArgumentException if a duplicate entry was encountered.
|
||||
*/
|
||||
fun of(vararg a: Int): IntOpenHashSet {
|
||||
val result = IntOpenHashSet(a.size, Hash.DEFAULT_LOAD_FACTOR)
|
||||
for (element in a) {
|
||||
if (!result.add(element)) {
|
||||
throw IllegalArgumentException("Duplicate element $element")
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.syntax.impl.fastutil.ints
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
interface IntSet {
|
||||
val size: Int
|
||||
val values: IntIterator
|
||||
operator fun contains(value: Int): Boolean
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
@file:ApiStatus.Internal
|
||||
|
||||
package com.intellij.platform.syntax.impl.fastutil.ints
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
fun IntSet.toIntArray(): IntArray {
|
||||
val size = size
|
||||
if (size == 0) return IntArrays.EMPTY_ARRAY
|
||||
val a = IntArray(size)
|
||||
IntArrays.unwrap(values, a)
|
||||
return a
|
||||
}
|
||||
|
||||
fun <V> IntSet.map(transform: (Int) -> V): List<V> {
|
||||
val res = ArrayList<V>()
|
||||
val iter = this.values
|
||||
while (iter.hasNext()) {
|
||||
val element = iter.next()
|
||||
res.add(transform(element))
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
fun <V> IntSet.mapNotNull(transform: (Int) -> V?): List<V> {
|
||||
val res = ArrayList<V>()
|
||||
val iter = this.values
|
||||
while (iter.hasNext()) {
|
||||
val element = iter.next()
|
||||
val transformed = transform(element)
|
||||
if (transformed != null) {
|
||||
res.add(transformed)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
fun IntSet.isEmpty(): Boolean {
|
||||
return size == 0
|
||||
}
|
||||
|
||||
fun IntSet.isNotEmpty(): Boolean {
|
||||
return size != 0
|
||||
}
|
||||
|
||||
inline fun IntSet.forEach(transform: (Int) -> Unit) {
|
||||
val iter = values
|
||||
while (iter.hasNext()) {
|
||||
transform(iter.next())
|
||||
}
|
||||
}
|
||||
|
||||
fun IntSet.containsAll(other: IntSet): Boolean {
|
||||
val iter = other.values
|
||||
while(iter.hasNext()) {
|
||||
if (!contains(iter.next())) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
inline fun IntSet.partition(predicate: (Int) -> Boolean): Pair<List<Int>, List<Int>> {
|
||||
val first = ArrayList<Int>()
|
||||
val second = ArrayList<Int>()
|
||||
this.values.forEach {
|
||||
if (predicate(it)) {
|
||||
first.add(it)
|
||||
} else {
|
||||
second.add(it)
|
||||
}
|
||||
}
|
||||
return Pair(first, second)
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.syntax.impl.fastutil.ints
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
interface MutableIntIterator: IntIterator {
|
||||
fun remove()
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.syntax.impl.fastutil.ints
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
interface MutableIntList: IntList {
|
||||
fun removeAt(index: Int): Int
|
||||
|
||||
fun add(element: Int)
|
||||
|
||||
fun add(index: Int, element: Int)
|
||||
|
||||
/** Sets the size of this list.
|
||||
*
|
||||
*
|
||||
* If the specified size is smaller than the current size, the last elements are
|
||||
* discarded. Otherwise, they are filled with 0/`null`/`false`.
|
||||
*
|
||||
* @param size the new size.
|
||||
*/
|
||||
fun resize(size: Int)
|
||||
|
||||
operator fun set(index: Int, element: Int): Int
|
||||
|
||||
/** Removes (hopefully quickly) elements of this type-specific list.
|
||||
*
|
||||
* @param from the start index (inclusive).
|
||||
* @param to the end index (exclusive).
|
||||
*/
|
||||
fun removeElements(from: Int, to: Int)
|
||||
|
||||
/** Add (hopefully quickly) elements to this type-specific list.
|
||||
*
|
||||
* @param index the index at which to add elements.
|
||||
* @param a the array containing the elements.
|
||||
* @param offset the offset of the first element to add.
|
||||
* @param length the number of elements to add.
|
||||
*/
|
||||
fun addElements(index: Int, a: IntArray, offset: Int, length: Int)
|
||||
|
||||
fun addAll(index: Int, elements: IntList): Boolean
|
||||
|
||||
fun clear()
|
||||
|
||||
fun sort()
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.syntax.impl.fastutil.ints
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
interface MutableIntMap<V>: IntMap<V> {
|
||||
fun put(key: Int, value: V): V?
|
||||
fun remove(key: Int): V?
|
||||
|
||||
operator fun set(key: Int, value: V): V? {
|
||||
return put(key, value)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.syntax.impl.fastutil.ints
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
interface MutableIntSet: IntSet {
|
||||
fun add(key: Int): Boolean
|
||||
fun remove(key: Int): Boolean
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.syntax.impl.util
|
||||
|
||||
import com.intellij.platform.syntax.impl.fastutil.ints.IntList
|
||||
import com.intellij.platform.syntax.impl.fastutil.ints.isEmpty
|
||||
import com.intellij.util.fastutil.ints.IntList
|
||||
import com.intellij.util.fastutil.ints.isEmpty
|
||||
|
||||
internal class MutableBitSet {
|
||||
private var bitset = LongArray(16) { 0 }
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
package com.intellij.platform.syntax.psi
|
||||
|
||||
import com.intellij.platform.syntax.SyntaxElementType
|
||||
import com.intellij.platform.syntax.impl.fastutil.ints.Int2ObjectOpenHashMap
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import com.intellij.util.fastutil.ints.Int2ObjectOpenHashMap
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user