KT-15363 Fix failing test: missing capacity parameter check in JS
Partially restore JVM map capacity implementation
This commit is contained in:
@@ -187,5 +187,15 @@ internal actual fun checkCountOverflow(count: Int): Int {
|
||||
* JS map and set implementations do not make use of capacities or load factors.
|
||||
*/
|
||||
@PublishedApi
|
||||
@kotlin.internal.InlineOnly
|
||||
internal actual inline fun mapCapacity(expectedSize: Int) = expectedSize
|
||||
internal actual fun mapCapacity(expectedSize: Int) = expectedSize
|
||||
|
||||
/**
|
||||
* Checks a collection builder function capacity argument.
|
||||
* In JS no validation is made in Map/Set constructor yet.
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalStdlibApi
|
||||
@PublishedApi
|
||||
internal actual fun checkBuilderCapacity(capacity: Int) {
|
||||
require(capacity >= 0) { "capacity must be non-negative." }
|
||||
}
|
||||
@@ -97,19 +97,27 @@ internal actual fun <K, V> Map<out K, V>.toSingletonMap(): Map<K, V> =
|
||||
|
||||
/**
|
||||
* Calculate the initial capacity of a map, based on Guava's
|
||||
* [com.google.common.collect.Maps.capacity](https://github.com/google/guava/blob/master/guava/src/com/google/common/collect/Maps.java)
|
||||
* approach. This is similar to [java.util.HashMap.putMapEntries] (JDK8+) but provides further optimizations for small or large sizes.
|
||||
* [com.google.common.collect.Maps.capacity](https://github.com/google/guava/blob/v28.2/guava/src/com/google/common/collect/Maps.java#L325)
|
||||
* approach.
|
||||
*/
|
||||
@PublishedApi
|
||||
internal actual fun mapCapacity(expectedSize: Int): Int = when {
|
||||
// We are not coercing the value to a valid one and not throwing an exception. It is up to the receiving class to
|
||||
// properly handle negative values. Note that all built-in classes do exactly that and will throw.
|
||||
// We are not coercing the value to a valid one and not throwing an exception. It is up to the caller to
|
||||
// properly handle negative values.
|
||||
expectedSize < 0 -> expectedSize
|
||||
expectedSize < MIN_CAPACITY -> expectedSize + 1
|
||||
expectedSize < MAX_CAPACITY -> ((expectedSize / 0.75F) + 1.0F).toInt()
|
||||
else -> MAX_CAPACITY
|
||||
expectedSize < 3 -> expectedSize + 1
|
||||
expectedSize < INT_MAX_POWER_OF_TWO -> ((expectedSize / 0.75F) + 1.0F).toInt()
|
||||
// any large value
|
||||
else -> Int.MAX_VALUE
|
||||
}
|
||||
private const val INT_MAX_POWER_OF_TWO: Int = 1 shl (Int.SIZE_BITS - 2)
|
||||
|
||||
// java.util.HashMap.MAX_CAPACITY
|
||||
private const val MAX_CAPACITY = 1 shl 30
|
||||
private const val MIN_CAPACITY = 3
|
||||
/**
|
||||
* Checks a collection builder function capacity argument.
|
||||
* Does nothing, capacity is validated in List/Set/Map constructor
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalStdlibApi
|
||||
@PublishedApi
|
||||
@kotlin.internal.InlineOnly
|
||||
internal actual inline fun checkBuilderCapacity(capacity: Int) {}
|
||||
@@ -178,6 +178,7 @@ public inline fun <E> buildList(@BuilderInference builderAction: MutableList<E>.
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun <E> buildList(expectedSize: Int, @BuilderInference builderAction: MutableList<E>.() -> Unit): List<E> {
|
||||
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
|
||||
checkBuilderCapacity(expectedSize)
|
||||
return ArrayList<E>(expectedSize).apply(builderAction)
|
||||
}
|
||||
|
||||
|
||||
@@ -148,6 +148,7 @@ public inline fun <K, V> buildMap(@BuilderInference builderAction: MutableMap<K,
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun <K, V> buildMap(expectedSize: Int, @BuilderInference builderAction: MutableMap<K, V>.() -> Unit): Map<K, V> {
|
||||
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
|
||||
checkBuilderCapacity(expectedSize)
|
||||
return LinkedHashMap<K, V>(mapCapacity(expectedSize)).apply(builderAction)
|
||||
}
|
||||
|
||||
@@ -157,6 +158,14 @@ public inline fun <K, V> buildMap(expectedSize: Int, @BuilderInference builderAc
|
||||
@PublishedApi
|
||||
internal expect fun mapCapacity(expectedSize: Int): Int
|
||||
|
||||
/**
|
||||
* Checks a collection builder function capacity argument.
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalStdlibApi
|
||||
@PublishedApi
|
||||
internal expect fun checkBuilderCapacity(capacity: Int)
|
||||
|
||||
/** Returns `true` if this map is not empty. */
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun <K, V> Map<out K, V>.isNotEmpty(): Boolean = !isEmpty()
|
||||
|
||||
@@ -115,6 +115,7 @@ public inline fun <E> buildSet(@BuilderInference builderAction: MutableSet<E>.()
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun <E> buildSet(expectedSize: Int, @BuilderInference builderAction: MutableSet<E>.() -> Unit): Set<E> {
|
||||
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
|
||||
checkBuilderCapacity(expectedSize)
|
||||
return LinkedHashSet<E>(mapCapacity(expectedSize)).apply(builderAction)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ class ContainerBuilderTest {
|
||||
|
||||
assertEquals(listOf('a', 'b', 'c', 'd'), y)
|
||||
|
||||
assertEquals(listOf(1), buildList(0) { add(1) })
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
buildList(-1) { add(0) }
|
||||
}
|
||||
@@ -38,6 +39,7 @@ class ContainerBuilderTest {
|
||||
|
||||
assertEquals(setOf('c', 'b', 'd'), y)
|
||||
|
||||
assertEquals(setOf(1), buildSet(0) { add(1) })
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
buildSet(-1) { add(0) }
|
||||
}
|
||||
@@ -59,6 +61,7 @@ class ContainerBuilderTest {
|
||||
|
||||
assertEquals(mapOf('a' to 1, 'c' to 3, 'b' to 2, 'd' to 4), y)
|
||||
|
||||
assertEquals(mapOf("a" to 1), buildMap<String, Int>(0) { put("a", 1) })
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
buildMap<String, Int>(-1) { put("x", 1) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user