package ru.dbotthepony.kstarbound.util import com.github.benmanes.caffeine.cache.Interner import kotlin.concurrent.getOrSet class PathStack(private val interner: Interner = Interner { it }) { private val _stack = object : ThreadLocal>() { override fun initialValue(): ArrayDeque { return ArrayDeque() } } private val stack: ArrayDeque get() = _stack.get() fun push(value: String) { stack.addLast(value) } fun pushFilename(value: String) { push(value.substringBefore(':').substringBeforeLast('/')) } fun last() = stack.lastOrNull() fun pop() = stack.removeLast() inline fun block(path: String, block: (String) -> T): T { try { push(path) return block.invoke(path) } finally { pop() } } inline operator fun invoke(path: String, block: (String) -> T) = block(path, block) private fun remap(a: String, b: String): String { if (b.isEmpty()) return a if (b[0] == '/') return b return interner.intern("$a/$b") } fun remap(path: String): String { return remap(checkNotNull(last()) { "Not reading an asset on current thread" }, path) } fun remapSafe(path: String): String? { return remap(last() ?: return null, path) } }