Map.getOrPut: treat nulls as missing values.
This commit is contained in:
@@ -2,5 +2,5 @@ fun box(): String {
|
|||||||
val m = hashMapOf<String, String?>()
|
val m = hashMapOf<String, String?>()
|
||||||
m.put("b", null)
|
m.put("b", null)
|
||||||
val oldValue = m.getOrPut("b", { "Foo" })
|
val oldValue = m.getOrPut("b", { "Foo" })
|
||||||
return if (oldValue == null) "OK" else "fail: $oldValue"
|
return if (oldValue == "Foo") "OK" else "fail: $oldValue"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,18 @@ fun <K> Iterable<K>.mapToIndex(): Map<K, Int> {
|
|||||||
return map
|
return map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public inline fun <K, V> MutableMap<K, V>.getOrPutNullable(key: K, defaultValue: () -> V): V {
|
||||||
|
return if (!containsKey(key)) {
|
||||||
|
val answer = defaultValue()
|
||||||
|
put(key, answer)
|
||||||
|
answer
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
get(key) as V
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline fun <T, C: Collection<T>> C.ifEmpty(body: () -> C): C = if (isEmpty()) body() else this
|
inline fun <T, C: Collection<T>> C.ifEmpty(body: () -> C): C = if (isEmpty()) body() else this
|
||||||
|
|
||||||
inline fun <T> Array<out T>.ifEmpty(body: () -> Array<out T>): Array<out T> = if (isEmpty()) body() else this
|
inline fun <T> Array<out T>.ifEmpty(body: () -> Array<out T>): Array<out T> = if (isEmpty()) body() else this
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.types.TypeUtils
|
|||||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext
|
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext
|
||||||
import org.jetbrains.kotlin.types.expressions.ForLoopConventionsChecker
|
import org.jetbrains.kotlin.types.expressions.ForLoopConventionsChecker
|
||||||
import org.jetbrains.kotlin.util.isValidOperator
|
import org.jetbrains.kotlin.util.isValidOperator
|
||||||
|
import org.jetbrains.kotlin.utils.getOrPutNullable
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class IterableTypesDetection(
|
class IterableTypesDetection(
|
||||||
@@ -62,7 +63,7 @@ class IterableTypesDetection(
|
|||||||
= isIterable(FuzzyType(type, emptyList()), loopVarType)
|
= isIterable(FuzzyType(type, emptyList()), loopVarType)
|
||||||
|
|
||||||
private fun elementType(type: FuzzyType): FuzzyType? {
|
private fun elementType(type: FuzzyType): FuzzyType? {
|
||||||
return cache.getOrPut(type, { elementTypeNoCache(type) })
|
return cache.getOrPutNullable(type, { elementTypeNoCache(type) })
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun elementType(type: KotlinType): FuzzyType?
|
override fun elementType(type: KotlinType): FuzzyType?
|
||||||
|
|||||||
+2
-1
@@ -23,6 +23,7 @@ import com.intellij.psi.PsiManager
|
|||||||
import com.intellij.refactoring.PackageWrapper
|
import com.intellij.refactoring.PackageWrapper
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.utils.getOrPutNullable
|
||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
|
|
||||||
interface KotlinMoveTarget {
|
interface KotlinMoveTarget {
|
||||||
@@ -64,7 +65,7 @@ class KotlinMoveTargetForDeferredFile(
|
|||||||
|
|
||||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement): PsiFile? {
|
override fun getOrCreateTargetPsi(originalPsi: PsiElement): PsiFile? {
|
||||||
val originalFile = originalPsi.containingFile as? KtFile ?: return null
|
val originalFile = originalPsi.containingFile as? KtFile ?: return null
|
||||||
return createdFiles.getOrPut(originalFile) { createFile(originalFile) }
|
return createdFiles.getOrPutNullable(originalFile) { createFile(originalFile) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTargetPsiIfExists(originalPsi: PsiElement) = null
|
override fun getTargetPsiIfExists(originalPsi: PsiElement) = null
|
||||||
|
|||||||
@@ -35,15 +35,3 @@ public fun <T> setOf(element: T): Set<T> = hashSetOf(element)
|
|||||||
* specified value.
|
* specified value.
|
||||||
*/
|
*/
|
||||||
public fun <K, V> mapOf(pair: Pair<K, V>): Map<K, V> = hashMapOf(pair)
|
public fun <K, V> mapOf(pair: Pair<K, V>): Map<K, V> = hashMapOf(pair)
|
||||||
|
|
||||||
|
|
||||||
public inline fun <K, V> MutableMap<K, V>.getOrPut(key: K, defaultValue: () -> V): V {
|
|
||||||
val value = get(key)
|
|
||||||
return if (value == null && !containsKey(key)) {
|
|
||||||
val answer = defaultValue()
|
|
||||||
put(key, answer)
|
|
||||||
answer
|
|
||||||
} else {
|
|
||||||
value as V
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -196,8 +196,7 @@ internal inline fun <K, V> Map<K, V>.getOrElseNullable(key: K, defaultValue: ()
|
|||||||
*
|
*
|
||||||
* @sample test.collections.MapTest.getOrPut
|
* @sample test.collections.MapTest.getOrPut
|
||||||
*/
|
*/
|
||||||
@kotlin.jvm.JvmVersion
|
public inline fun <K, V> MutableMap<K, V>.getOrPut(key: K, defaultValue: () -> V): V {
|
||||||
public inline fun <K, V: Any> MutableMap<K, V>.getOrPut(key: K, defaultValue: () -> V): V {
|
|
||||||
val value = get(key)
|
val value = get(key)
|
||||||
return if (value == null) {
|
return if (value == null) {
|
||||||
val answer = defaultValue()
|
val answer = defaultValue()
|
||||||
@@ -208,21 +207,6 @@ public inline fun <K, V: Any> MutableMap<K, V>.getOrPut(key: K, defaultValue: ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@kotlin.jvm.JvmName("getOrPutNullable")
|
|
||||||
@kotlin.jvm.JvmVersion
|
|
||||||
@Deprecated("This function will change its behavior soon not to distinguish missing keys and keys mapped to nulls.")
|
|
||||||
@kotlin.internal.LowPriorityInOverloadResolution
|
|
||||||
public inline fun <K, V> MutableMap<K, V>.getOrPut(key: K, defaultValue: () -> V): V {
|
|
||||||
val value = get(key)
|
|
||||||
return if (value == null && !containsKey(key)) {
|
|
||||||
val answer = defaultValue()
|
|
||||||
put(key, answer)
|
|
||||||
answer
|
|
||||||
} else {
|
|
||||||
value as V
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an [Iterator] over the entries in the [Map].
|
* Returns an [Iterator] over the entries in the [Map].
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -18,15 +18,6 @@ public operator fun <K, V> MutableMap<K, V>.set(key: K, value: V): Unit {
|
|||||||
put(key, value)
|
put(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* getOrPut is not supported on [ConcurrentMap] since it cannot be implemented correctly in terms of concurrency.
|
|
||||||
* Use [concurrentGetOrPut] instead, or cast this to a [MutableMap] if you want to sacrifice the concurrent-safety.
|
|
||||||
*/
|
|
||||||
@Deprecated("Use concurrentGetOrPut instead or cast this map to MutableMap.", level = DeprecationLevel.ERROR)
|
|
||||||
@kotlin.internal.LowPriorityInOverloadResolution
|
|
||||||
public inline fun <K, V> ConcurrentMap<K, V>.getOrPut(key: K, defaultValue: () -> V): Nothing =
|
|
||||||
throw UnsupportedOperationException("getOrPut is not supported on ConcurrentMap.")
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Concurrent getOrPut, that is safe for concurrent maps.
|
* Concurrent getOrPut, that is safe for concurrent maps.
|
||||||
*
|
*
|
||||||
@@ -36,14 +27,14 @@ public inline fun <K, V> ConcurrentMap<K, V>.getOrPut(key: K, defaultValue: () -
|
|||||||
* This method guarantees not to put the value into the map if the key is already there,
|
* This method guarantees not to put the value into the map if the key is already there,
|
||||||
* but the [defaultValue] function may be invoked even if the key is already in the map.
|
* but the [defaultValue] function may be invoked even if the key is already in the map.
|
||||||
*/
|
*/
|
||||||
public inline fun <K, V: Any> ConcurrentMap<K, V>.getOrPut(key: K, defaultValue: () -> V): V {
|
public inline fun <K, V> ConcurrentMap<K, V>.getOrPut(key: K, defaultValue: () -> V): V {
|
||||||
// Do not use computeIfAbsent on JVM8 as it would change locking behavior
|
// Do not use computeIfAbsent on JVM8 as it would change locking behavior
|
||||||
return this.get(key) ?:
|
return this.get(key) ?:
|
||||||
defaultValue().let { default -> this.putIfAbsent(key, default) ?: default }
|
defaultValue().let { default -> this.putIfAbsent(key, default) ?: default }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("Use getOrPut instead", ReplaceWith("getOrPut(key, defaultValue)"))
|
@Deprecated("Use getOrPut instead", ReplaceWith("getOrPut(key, defaultValue)"), level = DeprecationLevel.ERROR)
|
||||||
public inline fun <K, V: Any> ConcurrentMap<K, V>.concurrentGetOrPut(key: K, defaultValue: () -> V): V {
|
public inline fun <K, V: Any> ConcurrentMap<K, V>.concurrentGetOrPut(key: K, defaultValue: () -> V): V {
|
||||||
// Do not use computeIfAbsent on JVM8 as it would change locking behavior
|
// Do not use computeIfAbsent on JVM8 as it would change locking behavior
|
||||||
return this.get(key) ?:
|
return this.get(key) ?:
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ class MapTest {
|
|||||||
assertEquals(null, c)
|
assertEquals(null, c)
|
||||||
|
|
||||||
val d = empty.getOrPut("") { 1 }
|
val d = empty.getOrPut("") { 1 }
|
||||||
assertEquals(null, d) // soon will change to 1
|
assertEquals(1, d)
|
||||||
}
|
}
|
||||||
|
|
||||||
@test fun sizeAndEmpty() {
|
@test fun sizeAndEmpty() {
|
||||||
|
|||||||
Reference in New Issue
Block a user