[syntax] use multiplatform fastutil from util module instead of syntax one

GitOrigin-RevId: 4ac9294d8b91707464780b7be52d60a51dbe5632
This commit is contained in:
Alexander Zolotov
2025-06-04 23:17:12 -04:00
committed by intellij-monorepo-bot
parent bdf54c4ac9
commit 68f50bd8a3
28 changed files with 12 additions and 2373 deletions

View File

@@ -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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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
}

View File

@@ -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
}
}

View File

@@ -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> , = (&#x221A;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> , = (&#x221A;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())
}
}

View File

@@ -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.

View File

@@ -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
}
}

View File

@@ -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)
}
}
}

View File

@@ -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)
}
}

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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())
}

View File

@@ -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)
}
}
}

View File

@@ -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
}

View File

@@ -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?
}

View File

@@ -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
}
}
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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)
}
}

View File

@@ -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
}

View File

@@ -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 }

View File

@@ -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
/**