[kotlin-tooling-core] Implement generic Interner

^KT-55475 Verification Pending
This commit is contained in:
Sebastian Sellmair
2022-12-16 15:14:27 +01:00
committed by Space Team
parent 84fdc5e3df
commit 71fac797ee
3 changed files with 107 additions and 0 deletions
@@ -142,6 +142,17 @@ public abstract interface class org/jetbrains/kotlin/tooling/core/HasMutableExtr
public abstract fun getExtras ()Lorg/jetbrains/kotlin/tooling/core/MutableExtras;
}
public abstract interface class org/jetbrains/kotlin/tooling/core/Interner {
public abstract fun getOrPut (Ljava/lang/Object;)Ljava/lang/Object;
}
public final class org/jetbrains/kotlin/tooling/core/InternerKt {
public static final fun Interner (Ljava/util/concurrent/locks/Lock;)Lorg/jetbrains/kotlin/tooling/core/Interner;
public static synthetic fun Interner$default (Ljava/util/concurrent/locks/Lock;ILjava/lang/Object;)Lorg/jetbrains/kotlin/tooling/core/Interner;
public static final fun WeakInterner (Ljava/util/concurrent/locks/Lock;)Lorg/jetbrains/kotlin/tooling/core/Interner;
public static synthetic fun WeakInterner$default (Ljava/util/concurrent/locks/Lock;ILjava/lang/Object;)Lorg/jetbrains/kotlin/tooling/core/Interner;
}
public final class org/jetbrains/kotlin/tooling/core/KotlinToolingVersion : java/io/Serializable, java/lang/Comparable {
public fun <init> (IIILjava/lang/String;)V
public synthetic fun compareTo (Ljava/lang/Object;)I
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.tooling.core
import org.jetbrains.kotlin.tooling.core.InternerImpl.Store.Strong
import org.jetbrains.kotlin.tooling.core.InternerImpl.Store.Weak
import java.lang.ref.WeakReference
import java.util.*
import java.util.concurrent.locks.Lock
import kotlin.concurrent.withLock
fun WeakInterner(lock: Lock? = null): Interner = InternerImpl(Weak(), lock)
fun Interner(lock: Lock? = null): Interner = InternerImpl(Strong(), lock)
interface Interner {
fun <T : Any> getOrPut(value: T): T
}
private class InternerImpl(
private val store: Store,
private val lock: Lock? = null
) : Interner {
interface Store {
fun <T : Any> getOrPut(value: T): T
class Weak : Store {
private val references = WeakHashMap<Any, WeakReference<Any>>()
override fun <T : Any> getOrPut(value: T): T {
@Suppress("unchecked_cast")
return (references.getOrPut(value) { WeakReference(value) }.get() ?: run {
references[value] = WeakReference(value)
value
}) as T
}
}
@Suppress("UNCHECKED_CAST")
class Strong : Store {
private val references = hashMapOf<Any, Any>()
override fun <T : Any> getOrPut(value: T): T {
return references.getOrPut(value) { value } as T
}
}
}
override fun <T : Any> getOrPut(value: T): T {
return lock?.withLock { store.getOrPut(value) } ?: store.getOrPut(value)
}
}
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("UNUSED_VALUE")
package org.jetbrains.kotlin.tooling.core
import org.junit.Test
import kotlin.test.assertSame
class InternerTest {
data class Sample(val value: Int)
@Test
fun `test - weak interner`() {
doTest(WeakInterner())
}
@Test
fun `test - strong interner`() {
doTest(Interner())
}
private fun doTest(interner: Interner) {
val sample0A = Sample(0)
val sample0B = Sample(0)
val sample1A = Sample(1)
val sample1B = Sample(1)
assertSame(sample0A, interner.getOrPut(sample0A))
assertSame(sample0A, interner.getOrPut(sample0B))
assertSame(sample1A, interner.getOrPut(sample1A))
assertSame(sample1A, interner.getOrPut(sample1B))
assertSame(sample0A, interner.getOrPut(sample0A))
assertSame(sample0A, interner.getOrPut(sample0B))
}
}