experiments/MemLayout: add one more prototype
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
package _2
|
||||
|
||||
import bridge
|
||||
import kotlin.reflect.KProperty
|
||||
import java.io.Closeable
|
||||
import NativeFunction
|
||||
|
||||
|
||||
operator fun NativeFunction.invoke(vararg args: Any?): Long {
|
||||
val convertedArgs = LongArray(args.size)
|
||||
|
||||
val allocatedArgs = mutableListOf<Ptr<*>>()
|
||||
args.forEachIndexed { i, arg ->
|
||||
val convertedArg = when (arg) {
|
||||
null -> 0L
|
||||
is Long -> arg
|
||||
is Ptr<*> -> arg.ptr
|
||||
is String -> {
|
||||
val cString = CString.fromString(arg)
|
||||
allocatedArgs.add(cString)
|
||||
cString.ptr
|
||||
}
|
||||
is Byte -> arg.toLong()
|
||||
is Char -> arg.toLong()
|
||||
is Short -> arg.toLong()
|
||||
is Int -> arg.toLong()
|
||||
else -> throw NotImplementedError()
|
||||
}
|
||||
convertedArgs[i] = convertedArg
|
||||
}
|
||||
try {
|
||||
return bridge.call(this.ptr, *convertedArgs)
|
||||
} finally {
|
||||
allocatedArgs.forEach { bridge.free(it.ptr) }
|
||||
}
|
||||
}
|
||||
|
||||
open class StructLayout(val size: Int)
|
||||
|
||||
open class Ptr<T : StructLayout>(val ptr: Long)
|
||||
|
||||
|
||||
fun <T : StructLayout> alloc(layout: T): HeapPtr<T> {
|
||||
return HeapPtr<T>(bridge.malloc(layout.size))
|
||||
}
|
||||
|
||||
class HeapPtr<T : StructLayout>(ptr: Long) : Ptr<T>(ptr), Closeable {
|
||||
override fun close() {
|
||||
free()
|
||||
}
|
||||
|
||||
fun free() {
|
||||
bridge.free(ptr)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ByteField(val offset: Int) {
|
||||
operator fun getValue(thisRef: Ptr<*>, property: KProperty<*>): Byte {
|
||||
return bridge.getByte(thisRef.ptr + offset)
|
||||
}
|
||||
|
||||
operator fun setValue(thisRef: Ptr<*>, property: KProperty<*>, value: Byte) {
|
||||
bridge.putByte(thisRef.ptr + offset, value)
|
||||
}
|
||||
}
|
||||
|
||||
class ShortField(val offset: Int) {
|
||||
operator fun getValue(thisRef: Ptr<*>, property: KProperty<*>): Short {
|
||||
return bridge.getShort(thisRef.ptr + offset)
|
||||
}
|
||||
|
||||
operator fun setValue(thisRef: Ptr<*>, property: KProperty<*>, value: Short) {
|
||||
bridge.putShort(thisRef.ptr + offset, value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IntField(val offset: Int) {
|
||||
operator fun getValue(thisRef: Ptr<*>, property: KProperty<*>): Int {
|
||||
return bridge.getInt(thisRef.ptr + offset)
|
||||
}
|
||||
|
||||
operator fun setValue(thisRef: Ptr<*>, property: KProperty<*>, value: Int) {
|
||||
bridge.putInt(thisRef.ptr + offset, value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class LongField(val offset: Int) {
|
||||
operator fun getValue(thisRef: Ptr<*>, property: KProperty<*>): Long {
|
||||
return bridge.getLong(thisRef.ptr + offset)
|
||||
}
|
||||
|
||||
operator fun setValue(thisRef: Ptr<*>, property: KProperty<*>, value: Long) {
|
||||
bridge.putLong(thisRef.ptr + offset, value)
|
||||
}
|
||||
}
|
||||
|
||||
class PtrField<T : StructLayout>(val offset: Int) {
|
||||
operator fun getValue(thisRef: Ptr<*>, property: KProperty<*>): Ptr<T> {
|
||||
return Ptr<T>(bridge.getLong(thisRef.ptr + offset))
|
||||
}
|
||||
|
||||
operator fun setValue(thisRef: Ptr<*>, property: KProperty<*>, value: Ptr<T>) {
|
||||
bridge.putLong(thisRef.ptr + offset, value.ptr)
|
||||
}
|
||||
}
|
||||
|
||||
class StructField<T : StructLayout>(val offset: Int) {
|
||||
operator fun getValue(thisRef: Ptr<*>, property: KProperty<*>) = Ptr<T>(thisRef.ptr + offset)
|
||||
}
|
||||
|
||||
fun byteAt(offset: Int) = ByteField(offset)
|
||||
fun shortAt(offset: Int) = ShortField(offset)
|
||||
fun intAt(offset: Int) = IntField(offset)
|
||||
fun longAt(offset: Int) = LongField(offset)
|
||||
fun <T : StructLayout> ptrAt(offset: Int) = PtrField<T>(offset)
|
||||
fun <T: StructLayout> structAt(offset: Int) = StructField<T>(offset)
|
||||
|
||||
class StructArray<T : StructLayout>(val elemLayout: T, length: Int) : StructLayout(elemLayout.size * length)
|
||||
|
||||
class PtrToStructArray<T : StructLayout>(ptr: Long, val elemLayout: StructLayout) : Ptr<StructArray<T>>(ptr) {
|
||||
operator fun get(index: Int) = Ptr<T>(ptr + elemLayout.size * index)
|
||||
}
|
||||
|
||||
fun <T : StructLayout> allocArray(layout: StructArray<T>) = PtrToStructArray<T>(alloc(layout).ptr, layout.elemLayout)
|
||||
fun <T : StructLayout> allocArray(elemLayout: T, length: Int) = allocArray(StructArray(elemLayout, length))
|
||||
|
||||
object IntBox : StructLayout(4)
|
||||
var Ptr<IntBox>.value by intAt(0)
|
||||
|
||||
class PtrBox<T : StructLayout> : StructLayout(8)
|
||||
var <T : StructLayout> Ptr<PtrBox<T>>.value by ptrAt<T>(0)
|
||||
|
||||
class CString(length: Int) : StructLayout(length + 1) {
|
||||
|
||||
companion object {
|
||||
|
||||
fun fromString(str: String): Ptr<CString> {
|
||||
val bytes = str.toByteArray(); // FIXME: encoding
|
||||
val result = alloc(CString(bytes.size))
|
||||
|
||||
bytes.forEachIndexed { i, byte ->
|
||||
result[i] = byte
|
||||
}
|
||||
result[bytes.size] = 0.toByte()
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
operator fun Ptr<CString>.get(index: Int) = bridge.getByte(ptr + index)
|
||||
operator fun Ptr<CString>.set(index: Int, value: Byte) = bridge.putByte(ptr + index, value)
|
||||
|
||||
fun Ptr<CString>.toKotlinString(): String {
|
||||
|
||||
var length = 0
|
||||
while (this[length] != 0.toByte()) {
|
||||
++length
|
||||
}
|
||||
|
||||
val bytes = ByteArray(length)
|
||||
for (i in 0 .. length-1) {
|
||||
bytes.set(i, this[i])
|
||||
}
|
||||
|
||||
return String(bytes) // FIXME: encoding
|
||||
}
|
||||
|
||||
object timespec : StructLayout(16);
|
||||
|
||||
val Ptr<timespec>.tv_sec by longAt(0)
|
||||
val Ptr<timespec>.tv_usec by longAt(8)
|
||||
|
||||
object stat64 : StructLayout(144);
|
||||
|
||||
val Ptr<stat64>.st_dev by intAt(0)
|
||||
val Ptr<stat64>.st_mode by shortAt(4)
|
||||
val Ptr<stat64>.st_nlink by shortAt(6)
|
||||
val Ptr<stat64>.st_ino by longAt(8)
|
||||
val Ptr<stat64>.st_atimespec by structAt<timespec>(32)
|
||||
val Ptr<stat64>.st_mtimespec by structAt<timespec>(48)
|
||||
val Ptr<stat64>.st_ctimespec by structAt<timespec>(64)
|
||||
val Ptr<stat64>.st_birthtimespec by structAt<timespec>(80)
|
||||
val Ptr<stat64>.st_size by longAt(96)
|
||||
|
||||
val stat64Fun = NativeFunction.lookup("stat\$INODE64")!!
|
||||
|
||||
object dirent64 : StructLayout(1048);
|
||||
val Ptr<dirent64>.d_ino by longAt(0)
|
||||
val Ptr<dirent64>.d_seekoff by longAt(8)
|
||||
val Ptr<dirent64>.d_reclen by shortAt(16)
|
||||
val Ptr<dirent64>.d_namelen by shortAt(18)
|
||||
val Ptr<dirent64>.d_type by byteAt(20)
|
||||
val Ptr<dirent64>.d_name by structAt<CString>(21)
|
||||
|
||||
val opendir = NativeFunction.lookup("opendir")!!
|
||||
val readdir_r64 = NativeFunction.lookup("readdir_r\$INODE64")!!
|
||||
val closedir = NativeFunction.lookup("closedir")!!
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
|
||||
val array = allocArray(IntBox, 5)
|
||||
array[0].value = 5
|
||||
array[1].value = 6
|
||||
|
||||
println(array[0].value)
|
||||
println(array[1].value)
|
||||
|
||||
alloc(stat64).use { s ->
|
||||
val res = stat64Fun("/etc/passwd", s)
|
||||
println(res)
|
||||
with(s) {
|
||||
println("st_dev=$st_dev")
|
||||
println("st_mode=$st_mode")
|
||||
println("st_nlink=$st_nlink")
|
||||
println("st_ino=$st_ino")
|
||||
println("st_mtimespec.tv_sec=${st_mtimespec.tv_sec}")
|
||||
println("st_size=$st_size")
|
||||
}
|
||||
}
|
||||
|
||||
val dirp = opendir("/tmp")
|
||||
try {
|
||||
alloc(dirent64).use { entry ->
|
||||
alloc(PtrBox<dirent64>()).use { result ->
|
||||
|
||||
while (true) {
|
||||
val errno = readdir_r64(dirp, entry, result)
|
||||
if (result.value.ptr == 0L) {
|
||||
break
|
||||
}
|
||||
println(entry.d_name.toKotlinString())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
closedir(dirp)
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user