disbrowser/src/main/java/com/smallhacker/disbrowser/asm/MemorySpace.kt

86 lines
3.3 KiB
Kotlin

package com.smallhacker.disbrowser.asm
import com.smallhacker.disbrowser.util.UInt24
import com.smallhacker.disbrowser.util.joinBytes
import com.smallhacker.disbrowser.util.joinNullableBytes
import com.smallhacker.disbrowser.util.toUInt24
interface MemorySpace {
val size: UInt
operator fun get(address: UInt): UByte?
}
interface ValidMemorySpace : MemorySpace {
override operator fun get(address: UInt): UByte
}
object EmptyMemorySpace : ValidMemorySpace {
override val size get() = 0u
override fun get(address: UInt) = throw IllegalStateException()
}
fun MemorySpace.asSequence(): Sequence<UByte?> = (0u until size).asSequence().map { this[it] }
fun MemorySpace.getWord(address: UInt): UShort? = joinNullableBytes(this[address], this[address + 1u])?.toUShort()
fun MemorySpace.getLong(address: UInt): UInt24? = joinNullableBytes(this[address], this[address + 1u], this[address + 2u])?.toUInt24()
fun MemorySpace.range(start: UInt, length: UInt): MemorySpace = MemoryRange(this, start, length)
fun MemorySpace.range(start: SnesAddress, length: UInt): MemorySpace = range(start.value.toUInt(), length)
fun MemorySpace.validate(): ValidMemorySpace? {
if (asSequence().any { it == null }) {
return null
}
return ValidatedMemorySpace(this)
}
fun ValidMemorySpace.asSequence(): Sequence<UByte> = (0u until size).asSequence().map { this[it] }
fun ValidMemorySpace.getWord(address: UInt): UShort = joinBytes(this[address], this[address + 1u]).toUShort()
fun ValidMemorySpace.getLong(address: UInt): UInt24 = joinBytes(this[address], this[address + 1u], this[address + 2u]).toUInt24()
fun ValidMemorySpace.range(start: UInt, length: UInt): ValidMemorySpace = MemoryRange(this, start, length).validate()!!
fun ValidMemorySpace.range(start: SnesAddress, length: UInt): ValidMemorySpace = range(start.value.toUInt(), length).validate()!!
class ArrayMemorySpace(private val bytes: UByteArray) : MemorySpace {
override val size = bytes.size.toUInt()
override fun get(address: UInt): UByte? {
if (address >= size) {
return null
}
return bytes[address.toInt()]
}
}
class UnreadableMemory(override val size: UInt) : MemorySpace {
override fun get(address: UInt): UByte? = null
}
private class MemoryRange(private val parent: MemorySpace, private val start: UInt, override val size: UInt) : MemorySpace {
override fun get(address: UInt) = if (address < size) parent[start + address] else null
}
private class ValidatedMemorySpace(private val parent: MemorySpace) : ValidMemorySpace {
override val size get() = parent.size
override fun get(address: UInt) = parent[address]!!
}
private class ReindexedMemorySpace(
private val parent: MemorySpace,
override val size: UInt,
private val mapper: (UInt) -> UInt
) : MemorySpace {
override fun get(address: UInt): UByte? {
if (address >= size) {
return null
}
val mapped = mapper(address)
return parent[mapped]
}
}
fun MemorySpace.deinterleave(entries: UInt, vararg startOffsets: UInt): MemorySpace {
val fieldCount = startOffsets.size.toUInt()
return ReindexedMemorySpace(this, entries * fieldCount) {
val entry = it / fieldCount
val field = it.rem(fieldCount)
startOffsets[field.toInt()] + entry
}
}