org.jetbrains.kotlin.cli.common.repl.BasicReplState.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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 org.jetbrains.kotlin.cli.common.repl
import java.io.Serializable
import java.util.*
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.write
data class LineId(override val no: Int, override val generation: Int, private val codeHash: Int) : ILineId, Serializable {
override fun compareTo(other: ILineId): Int = (other as? LineId)?.let { lineId ->
no.compareTo(lineId.no).takeIf { no -> no != 0 }
?: codeHash.compareTo(lineId.codeHash)
} ?: -1 // TODO: check if it doesn't break something
companion object {
private const val serialVersionUID: Long = 8328354000L
}
}
open class BasicReplStageHistory(override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()) : IReplStageHistory, ArrayList>() {
val currentLineNumber = AtomicInteger(REPL_CODE_LINE_FIRST_NO)
val currentGeneration = AtomicInteger(REPL_CODE_LINE_FIRST_GEN)
override fun push(id: ILineId, item: T) {
lock.write {
add(ReplHistoryRecord(id, item))
}
}
override fun pop(): ReplHistoryRecord? = lock.write { if (isEmpty()) null else removeAt(lastIndex) }
override fun reset(): Iterable {
lock.write {
val removed = map { it.id }
clear()
currentGeneration.incrementAndGet()
currentLineNumber.set(REPL_CODE_LINE_FIRST_NO)
return removed
}
}
override fun resetTo(id: ILineId): Iterable {
lock.write {
return tryResetTo(id) ?: throw NoSuchElementException("Cannot reset to non-existent line ${id.no}")
}
}
protected fun tryResetTo(id: ILineId): List? {
val idx = indexOfFirst { it.id == id }
if (idx < 0) return null
return if (idx < lastIndex) {
val removed = asSequence().drop(idx + 1).map { it.id }.toList()
removeRange(idx + 1, size)
currentGeneration.incrementAndGet()
removed.lastOrNull()?.no?.let {
currentLineNumber.set(it)
}
removed
} else {
currentGeneration.incrementAndGet()
currentLineNumber.set(id.no + 1)
emptyList()
}
}
}
open class BasicReplStageState(override final val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()): IReplStageState {
override val currentGeneration: Int get() = history.currentGeneration.get()
override fun getNextLineNo(): Int = history.currentLineNumber.getAndIncrement()
override val history: BasicReplStageHistory = BasicReplStageHistory(lock)
}