152 lines
3.7 KiB
Kotlin
152 lines
3.7 KiB
Kotlin
package ru.dbotthepony.kstarbound.lua
|
|
|
|
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
|
|
import ru.dbotthepony.kstarbound.lua.userdata.LuaFuture
|
|
import ru.dbotthepony.kstarbound.lua.userdata.LuaPathFinder
|
|
import ru.dbotthepony.kstarbound.util.random.random
|
|
import java.io.Closeable
|
|
import java.lang.ref.Cleaner.Cleanable
|
|
import java.util.concurrent.ConcurrentLinkedQueue
|
|
import java.util.random.RandomGenerator
|
|
import kotlin.properties.Delegates
|
|
|
|
class LuaSharedState(val handlesThread: LuaThread, private val cleanable: Cleanable) : Closeable {
|
|
private val pendingFree = ConcurrentLinkedQueue<Int>()
|
|
private val freeHandles = IntAVLTreeSet()
|
|
private var nextHandle = 0
|
|
// faster code path
|
|
private var handlesInUse = 0
|
|
|
|
private val namedHandles = HashMap<Any, LuaHandle>()
|
|
var random: RandomGenerator = random()
|
|
|
|
var commonHandles by Delegates.notNull<CommonHandleRegistry>()
|
|
private set
|
|
|
|
var isValid = true
|
|
private set
|
|
|
|
fun ensureValid() {
|
|
check(isValid) { "Tried to use NULL LuaState!" }
|
|
}
|
|
|
|
var errorToStringFunction by Delegates.notNull<LuaHandle>()
|
|
private set
|
|
|
|
var errorTrapFunction by Delegates.notNull<LuaHandle>()
|
|
private set
|
|
|
|
override fun toString(): String {
|
|
return "LuaSharedState[$handlesThread]"
|
|
}
|
|
|
|
override fun close() {
|
|
if (!isValid) return
|
|
isValid = false
|
|
namedHandles.clear()
|
|
cleanable.clean()
|
|
errorToStringFunction = LuaHandle.Nil
|
|
errorTrapFunction = LuaHandle.Nil
|
|
commonHandles = CommonHandleRegistry.EMPTY
|
|
}
|
|
|
|
fun initializeHandles(mainThread: LuaThread) {
|
|
val future = LuaFuture.initializeHandle(mainThread)
|
|
val pathFinder = LuaPathFinder.initializeHandle(mainThread)
|
|
|
|
commonHandles = CommonHandleRegistry(
|
|
future = future,
|
|
pathFinder = pathFinder,
|
|
)
|
|
|
|
handlesThread.push {
|
|
//it.lua.push(it.nextObject<Throwable?>(-1)?.stackTraceToString() ?: it.nextObject<Any?>(-1).toString())
|
|
it.lua.push(it.nextObject<Any?>().toString())
|
|
1
|
|
}
|
|
|
|
errorToStringFunction = allocateHandle(null)
|
|
|
|
handlesThread.push {
|
|
val peek = it.peek()
|
|
|
|
if (peek == LuaType.STRING) {
|
|
val err = LuaRuntimeException(it.lua.traceback(it.lua.getString(), 1))
|
|
it.lua.push(err)
|
|
} else if (peek == LuaType.USERDATA) {
|
|
val obj = it.nextObject<Any>()
|
|
|
|
if (obj is Throwable && obj !is LuaRuntimeException) {
|
|
val err = LuaRuntimeException(it.lua.traceback(obj.toString(), 1), cause = obj, writeStackTrace = false)
|
|
it.lua.push(err)
|
|
}
|
|
}
|
|
|
|
1
|
|
}
|
|
|
|
errorTrapFunction = allocateHandle(null)
|
|
}
|
|
|
|
fun freeHandle(handle: Int, key: Any?) {
|
|
if (!isValid) return
|
|
pendingFree.add(handle)
|
|
|
|
if (key != null) {
|
|
namedHandles.remove(key)
|
|
}
|
|
}
|
|
|
|
fun cleanup() {
|
|
ensureValid()
|
|
if (handlesInUse == 0) return
|
|
var handle = pendingFree.poll()
|
|
|
|
while (handle != null) {
|
|
handlesInUse--
|
|
freeHandles.add(handle)
|
|
handlesThread.push()
|
|
handlesThread.copy(-1, handle)
|
|
handlesThread.pop()
|
|
|
|
handle = pendingFree.poll()
|
|
}
|
|
}
|
|
|
|
fun allocateHandle(name: Any?): LuaHandle {
|
|
ensureValid()
|
|
require(name == null || name !in namedHandles) { "Named handle '$name' already exists" }
|
|
handlesInUse++
|
|
|
|
if (freeHandles.isEmpty()) {
|
|
if (nextHandle % 10 == 0) {
|
|
handlesThread.ensureExtraCapacity(20)
|
|
}
|
|
|
|
return LuaHandle.Regular(this, ++nextHandle, name).also {
|
|
if (name != null) namedHandles[name] = it
|
|
}
|
|
} else {
|
|
val handle = freeHandles.firstInt()
|
|
freeHandles.remove(handle)
|
|
|
|
handlesThread.copy(-1, handle)
|
|
handlesThread.pop()
|
|
|
|
return LuaHandle.Regular(this, handle, name).also {
|
|
if (name != null) namedHandles[name] = it
|
|
}
|
|
}
|
|
}
|
|
|
|
fun getNamedHandle(key: Any): LuaHandle {
|
|
ensureValid()
|
|
return namedHandles[key] ?: throw NoSuchElementException("No such handle: $key")
|
|
}
|
|
|
|
fun findNamedHandle(key: Any): LuaHandle? {
|
|
ensureValid()
|
|
return namedHandles[key]
|
|
}
|
|
}
|