ScriptDependenciesCache, refactor: use delegated properties

This commit is contained in:
Pavel V. Talanov
2017-10-13 18:00:09 +03:00
parent 896dacc835
commit 1cdac78b32
2 changed files with 32 additions and 21 deletions
@@ -29,36 +29,40 @@ import org.jetbrains.kotlin.idea.core.util.EDT
import java.util.concurrent.locks.ReentrantReadWriteLock import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read import kotlin.concurrent.read
import kotlin.concurrent.write import kotlin.concurrent.write
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty0
import kotlin.reflect.jvm.isAccessible
import kotlin.script.experimental.dependencies.ScriptDependencies import kotlin.script.experimental.dependencies.ScriptDependencies
internal class ScriptDependenciesCache(private val project: Project) { class ScriptDependenciesCache(private val project: Project) {
private val cacheLock = ReentrantReadWriteLock() private val cacheLock = ReentrantReadWriteLock()
private val cache = hashMapOf<String, ScriptDependencies>() private val cache = hashMapOf<String, ScriptDependencies>()
operator fun get(virtualFile: VirtualFile): ScriptDependencies? = cacheLock.read { cache[virtualFile.path] } operator fun get(virtualFile: VirtualFile): ScriptDependencies? = cacheLock.read { cache[virtualFile.path] }
val allScriptsClasspathCache = ClearableLazyValue(cacheLock) { val allScriptsClasspath by ClearableLazyValue(cacheLock) {
val files = cache.values.flatMap { it.classpath }.distinct() val files = cache.values.flatMap { it.classpath }.distinct()
ScriptDependenciesManager.toVfsRoots(files) ScriptDependenciesManager.toVfsRoots(files)
} }
val allScriptsClasspathScope = ClearableLazyValue(cacheLock) { val allScriptsClasspathScope by ClearableLazyValue(cacheLock) {
NonClasspathDirectoriesScope(allScriptsClasspathCache.get()) NonClasspathDirectoriesScope(allScriptsClasspath)
} }
val allLibrarySourcesCache = ClearableLazyValue(cacheLock) { val allLibrarySources by ClearableLazyValue(cacheLock) {
ScriptDependenciesManager.toVfsRoots(cache.values.flatMap { it.sources }.distinct()) ScriptDependenciesManager.toVfsRoots(cache.values.flatMap { it.sources }.distinct())
} }
val allLibrarySourcesScope = ClearableLazyValue(cacheLock) { val allLibrarySourcesScope by ClearableLazyValue(cacheLock) {
NonClasspathDirectoriesScope(allLibrarySourcesCache.get()) NonClasspathDirectoriesScope(allLibrarySources)
} }
private fun onChange(file: VirtualFile?) { private fun onChange(file: VirtualFile?) {
allScriptsClasspathCache.clear() this::allScriptsClasspath.clearValue()
allScriptsClasspathScope.clear() this::allScriptsClasspathScope.clearValue()
allLibrarySourcesCache.clear() this::allLibrarySources.clearValue()
allLibrarySourcesScope.clear() this::allLibrarySourcesScope.clearValue()
val kotlinScriptDependenciesClassFinder = val kotlinScriptDependenciesClassFinder =
Extensions.getArea(project).getExtensionPoint(PsiElementFinder.EP_NAME).extensions Extensions.getArea(project).getExtensionPoint(PsiElementFinder.EP_NAME).extensions
@@ -86,8 +90,8 @@ internal class ScriptDependenciesCache(private val project: Project) {
} }
fun hasNotCachedRoots(scriptDependencies: ScriptDependencies): Boolean { fun hasNotCachedRoots(scriptDependencies: ScriptDependencies): Boolean {
return !allScriptsClasspathCache.get().containsAll(ScriptDependenciesManager.toVfsRoots(scriptDependencies.classpath)) || return !allScriptsClasspath.containsAll(ScriptDependenciesManager.toVfsRoots(scriptDependencies.classpath)) ||
!allLibrarySourcesCache.get().containsAll(ScriptDependenciesManager.toVfsRoots(scriptDependencies.sources)) !allLibrarySources.containsAll(ScriptDependenciesManager.toVfsRoots(scriptDependencies.sources))
} }
fun clear() { fun clear() {
@@ -121,10 +125,13 @@ internal class ScriptDependenciesCache(private val project: Project) {
} }
} }
internal class ClearableLazyValue<out T : Any>(private val lock: ReentrantReadWriteLock, private val compute: () -> T) { private fun <R> KProperty0<R>.clearValue() {
private var value: T? = null isAccessible = true
(getDelegate() as ClearableLazyValue<*, *>).clear()
}
fun get(): T { private class ClearableLazyValue<in R, out T : Any>(private val lock: ReentrantReadWriteLock, private val compute: () -> T): ReadOnlyProperty<R, T> {
override fun getValue(thisRef: R, property: KProperty<*>): T {
lock.read { lock.read {
if (value == null) { if (value == null) {
lock.write { lock.write {
@@ -135,9 +142,13 @@ internal class ClearableLazyValue<out T : Any>(private val lock: ReentrantReadWr
} }
} }
private var value: T? = null
fun clear() { fun clear() {
lock.write { lock.write {
value = null value = null
} }
} }
} }
@@ -60,10 +60,10 @@ class ScriptDependenciesManager internal constructor(
scriptDefinitionProvider.setScriptDefinitions(def) scriptDefinitionProvider.setScriptDefinitions(def)
} }
fun getAllScriptsClasspathScope() = cache.allScriptsClasspathScope.get() fun getAllScriptsClasspathScope() = cache.allScriptsClasspathScope
fun getAllLibrarySourcesScope() = cache.allLibrarySourcesScope.get() fun getAllLibrarySourcesScope() = cache.allLibrarySourcesScope
fun getAllLibrarySources() = cache.allLibrarySourcesCache.get() fun getAllLibrarySources() = cache.allLibrarySources
fun getAllScriptsClasspath() = cache.allScriptsClasspathCache.get() fun getAllScriptsClasspath() = cache.allScriptsClasspath
companion object { companion object {
@JvmStatic @JvmStatic