Interop: remove old version
This commit is contained in:
@@ -1,46 +0,0 @@
|
||||
package kotlin_native.interop
|
||||
|
||||
import sun.misc.Unsafe
|
||||
|
||||
data class NativePtr private constructor(internal val value: Long) {
|
||||
|
||||
fun displacedBy(offset: Int) = NativePtr(value + offset)
|
||||
|
||||
companion object {
|
||||
fun byValue(value: Long): NativePtr? {
|
||||
return if (value == 0L) {
|
||||
null
|
||||
} else {
|
||||
NativePtr(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun NativePtr?.asLong() = if (this == null) 0L else value
|
||||
|
||||
internal object bridge {
|
||||
|
||||
fun malloc(size: Int): NativePtr = NativePtr.byValue(unsafe.allocateMemory(size.toLong()))!!
|
||||
fun free(ptr: NativePtr) = unsafe.freeMemory(ptr.asLong())
|
||||
|
||||
fun getInt64(ptr: NativePtr): Long = unsafe.getLong(ptr.asLong())
|
||||
fun putInt64(ptr: NativePtr, value: Long) = unsafe.putLong(ptr.asLong(), value)
|
||||
|
||||
fun getPtr(ptr: NativePtr): NativePtr? = NativePtr.byValue(unsafe.getLong(ptr.asLong()))
|
||||
fun putPtr(ptr: NativePtr, value: NativePtr?) = unsafe.putLong(ptr.asLong(), value.asLong())
|
||||
|
||||
fun getInt32(ptr: NativePtr): Int = unsafe.getInt(ptr.asLong())
|
||||
fun putInt32(ptr: NativePtr, value: Int) = unsafe.putInt(ptr.asLong(), value)
|
||||
|
||||
fun getInt16(ptr: NativePtr): Short = unsafe.getShort(ptr.asLong())
|
||||
fun putInt16(ptr: NativePtr, value: Short) = unsafe.putShort(ptr.asLong(), value)
|
||||
|
||||
fun getInt8(ptr: NativePtr): Byte = unsafe.getByte(ptr.asLong())
|
||||
fun putInt8(ptr: NativePtr, value: Byte) = unsafe.putByte(ptr.asLong(), value)
|
||||
|
||||
private val unsafe = with(Unsafe::class.java.getDeclaredField("theUnsafe")) {
|
||||
isAccessible = true
|
||||
return@with this.get(null) as Unsafe
|
||||
}
|
||||
}
|
||||
@@ -1,287 +0,0 @@
|
||||
package kotlin_native.interop
|
||||
|
||||
/**
|
||||
* This class provides a way to create a stable handle to any Kotlin object.
|
||||
* Its [value] can be safely passed to native code e.g. to be received in a Kotlin callback.
|
||||
*
|
||||
* Any [StableObjPtr] should be manually [disposed][dispose]
|
||||
*/
|
||||
data class StableObjPtr private constructor(val value: NativePtr) {
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* Creates a handle for given object.
|
||||
*/
|
||||
fun create(any: Any) = StableObjPtr(NativePtr.byValue(newGlobalRef(any))!!)
|
||||
|
||||
/**
|
||||
* Creates [StableObjPtr] from given raw value.
|
||||
*
|
||||
* @param value must be a [value] of some [StableObjPtr]
|
||||
*/
|
||||
fun fromValue(value: NativePtr) = StableObjPtr(value)
|
||||
|
||||
init {
|
||||
loadCallbacksLibrary()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the handle. It must not be [used][get] after that.
|
||||
*/
|
||||
fun dispose() {
|
||||
deleteGlobalRef(value.value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object this handle was [created][create] for.
|
||||
*/
|
||||
fun get(): Any = derefGlobalRef(value.value)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the type of native function.
|
||||
*
|
||||
* The instances of this class are supposed to be Kotlin objects (singletons),
|
||||
* because creating the instance implies allocating some amount of non-freeable memory for the instance itself
|
||||
* and for any unique Kotlin function "converted" to this type.
|
||||
*
|
||||
* Native function type definition consists in the following:
|
||||
* - Definitions of native function's parameter and return types to be passed into the constructor
|
||||
* - Implementation of [invoke] method which describes how to convert between these types and Kotlin types used in [F]
|
||||
*
|
||||
* @param F Kotlin function type corresponding to given native function type
|
||||
*/
|
||||
abstract class NativeFunctionType<F : Function<*>> protected constructor(returnType: CType, vararg paramTypes: CType) {
|
||||
|
||||
/**
|
||||
* Returns a native function of this type, which calls given Kotlin *static* function.
|
||||
*
|
||||
* Given function must be *static*, i.e. an (unbound) reference to a Kotlin function or
|
||||
* a closure which doesn't capture any variable
|
||||
*/
|
||||
fun fromStatic(function: F): NativePtr {
|
||||
// TODO: optimize synchronization
|
||||
synchronized(cache) {
|
||||
return cache.getOrPut(function, { createFromStatic(function) })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the C type of a function's parameter or return value.
|
||||
* It is supposed to be constructed using the primitive types (such as [SInt32]) and the [Struct] combinator.
|
||||
*
|
||||
* This description omits the details that are irrelevant for the ABI.
|
||||
*/
|
||||
protected open class CType internal constructor(val ffiType: ffi_type) {
|
||||
internal constructor(ffiTypePtr: Long) : this(NativePtr.byValue(ffiTypePtr).asRef(ffi_type)!!)
|
||||
}
|
||||
|
||||
protected object Void : CType(ffiTypeVoid())
|
||||
protected object UInt8 : CType(ffiTypeUInt8())
|
||||
protected object SInt8 : CType(ffiTypeSInt8())
|
||||
protected object UInt16 : CType(ffiTypeUInt16())
|
||||
protected object SInt16 : CType(ffiTypeSInt16())
|
||||
protected object UInt32 : CType(ffiTypeUInt32())
|
||||
protected object SInt32 : CType(ffiTypeSInt32())
|
||||
protected object UInt64 : CType(ffiTypeUInt64())
|
||||
protected object SInt64 : CType(ffiTypeSInt64())
|
||||
protected object Pointer : CType(ffiTypePointer())
|
||||
|
||||
protected class Struct(vararg elementTypes: CType) : CType(
|
||||
ffiTypeStruct(
|
||||
elementTypes.map { it.ffiType }
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
* This method should invoke given Kotlin function.
|
||||
*
|
||||
* @param args array of pointers to arguments to be passed to [function]
|
||||
* @param ret pointer to memory to be filled with return value of [function]
|
||||
*/
|
||||
protected abstract fun invoke(function: F, args: NativeArray<NativePtrBox>, ret: NativePtr)
|
||||
|
||||
companion object {
|
||||
init {
|
||||
loadCallbacksLibrary()
|
||||
}
|
||||
}
|
||||
|
||||
private val ffiCif = ffiCreateCif(returnType.ffiType, paramTypes.map { it.ffiType })
|
||||
|
||||
/**
|
||||
* Allocates a native function of this type for given Kotlin function.
|
||||
*/
|
||||
private fun createFromStatic(function: F): NativePtr {
|
||||
if (!isStatic(function)) {
|
||||
throw IllegalArgumentException()
|
||||
}
|
||||
|
||||
val impl = { ret: NativePtr, args: NativeArray<NativePtrBox> ->
|
||||
invoke(function, args, ret)
|
||||
}
|
||||
|
||||
return ffiCreateClosure(ffiCif, impl)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if given function is *static* as defined in [fromStatic].
|
||||
*/
|
||||
private fun isStatic(function: Function<*>): Boolean {
|
||||
// TODO: revise
|
||||
try {
|
||||
with(function.javaClass.getDeclaredField("INSTANCE")) {
|
||||
if (!java.lang.reflect.Modifier.isStatic(modifiers) || !java.lang.reflect.Modifier.isFinal(modifiers)) {
|
||||
return false
|
||||
}
|
||||
|
||||
isAccessible = true // TODO: undo
|
||||
|
||||
return get(null) == function
|
||||
}
|
||||
} catch (e: NoSuchFieldException) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private val cache = mutableMapOf<F, NativePtr>()
|
||||
}
|
||||
|
||||
/**
|
||||
* @see NativeFunctionType.fromStatic
|
||||
*/
|
||||
fun <F : Function<*>> F.staticAsNative(type: NativeFunctionType<F>) = type.fromStatic(this)
|
||||
|
||||
/**
|
||||
* Describes a "struct" with native function pointer field.
|
||||
*/
|
||||
class NativeFunctionBox<F : Function<*>>(ptr: NativePtr, private val type: NativeFunctionType<F>) : NativeRef(ptr) {
|
||||
|
||||
/**
|
||||
* Sets the function pointer field to null or native function calling given Kotlin function.
|
||||
*/
|
||||
fun setStatic(function: F?) {
|
||||
val nativeFunPtr = function?.staticAsNative(type)
|
||||
bridge.putPtr(ptr, nativeFunPtr)
|
||||
}
|
||||
}
|
||||
|
||||
val <F : Function<*>> NativeFunctionType<F>.ref: NativeRef.TypeWithSize<NativeFunctionBox<F>>
|
||||
get() = NativeRef.TypeWithSize(8, { NativeFunctionBox(it, this) }) // TODO: 64-bit specific
|
||||
|
||||
|
||||
private fun loadCallbacksLibrary() {
|
||||
System.loadLibrary("callbacks")
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reference to `ffi_type` struct instance.
|
||||
*/
|
||||
internal class ffi_type (ptr: NativePtr) : NativeRef(ptr) {
|
||||
companion object : Type<ffi_type>(::ffi_type)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reference to `ffi_cif` struct instance.
|
||||
*/
|
||||
internal class ffi_cif (ptr: NativePtr) : NativeRef(ptr) {
|
||||
companion object : Type<ffi_cif>(::ffi_cif)
|
||||
}
|
||||
|
||||
private external fun ffiTypeVoid(): Long
|
||||
private external fun ffiTypeUInt8(): Long
|
||||
private external fun ffiTypeSInt8(): Long
|
||||
private external fun ffiTypeUInt16(): Long
|
||||
private external fun ffiTypeSInt16(): Long
|
||||
private external fun ffiTypeUInt32(): Long
|
||||
private external fun ffiTypeSInt32(): Long
|
||||
private external fun ffiTypeUInt64(): Long
|
||||
private external fun ffiTypeSInt64(): Long
|
||||
private external fun ffiTypePointer(): Long
|
||||
|
||||
private external fun ffiTypeStruct0(elements: Long): Long
|
||||
|
||||
/**
|
||||
* Allocates and initializes `ffi_type` describing the struct.
|
||||
*
|
||||
* @param elements types of the struct elements
|
||||
*/
|
||||
private fun ffiTypeStruct(elementTypes: List<ffi_type>): ffi_type {
|
||||
val elements = mallocNativeArrayOf(ffi_type, *elementTypes.toTypedArray(), null).ptr
|
||||
val res = ffiTypeStruct0(elements.value)
|
||||
if (res == 0L) {
|
||||
throw OutOfMemoryError()
|
||||
}
|
||||
return NativePtr.byValue(res).asRef(ffi_type)!!
|
||||
}
|
||||
|
||||
private external fun ffiCreateCif0(nArgs: Int, rType: Long, argTypes: Long): Long
|
||||
|
||||
/**
|
||||
* Creates and prepares an `ffi_cif`.
|
||||
*
|
||||
* @param returnType native function return value type
|
||||
* @param paramTypes native function parameter types
|
||||
*
|
||||
* @return the initialized `ffi_cif`
|
||||
*/
|
||||
private fun ffiCreateCif(returnType: ffi_type, paramTypes: List<ffi_type>): ffi_cif {
|
||||
val nArgs = paramTypes.size
|
||||
val rType = returnType.ptr
|
||||
val argTypes = mallocNativeArrayOf(ffi_type, *paramTypes.toTypedArray(), null).ptr
|
||||
val res = ffiCreateCif0(nArgs, rType.value, argTypes.value)
|
||||
|
||||
when (res) {
|
||||
0L -> throw OutOfMemoryError()
|
||||
-1L -> throw Error("FFI_BAD_TYPEDEF")
|
||||
-2L -> throw Error("FFI_BAD_ABI")
|
||||
-3L -> throw Error("libffi error occurred")
|
||||
}
|
||||
|
||||
return NativePtr.byValue(res).asRef(ffi_cif)!!
|
||||
}
|
||||
|
||||
private fun ffiFunImpl0(ffiCif: Long, ret: Long, args: Long, userData: Any) {
|
||||
ffiFunImpl(NativePtr.byValue(ffiCif).asRef(ffi_cif)!!,
|
||||
NativePtr.byValue(ret)!!,
|
||||
NativePtr.byValue(args).asRef(array(NativePtrBox))!!,
|
||||
userData as (ret: NativePtr, args: NativeArray<NativePtrBox>) -> Unit)
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called from native code when a native function created with [ffiCreateClosure] is invoked.
|
||||
*
|
||||
* @param ret pointer to memory to be filled with return value of the invoked native function
|
||||
* @param args pointer to array of pointers to arguments passed to the invoked native function
|
||||
*/
|
||||
private fun ffiFunImpl(ffiCif: ffi_cif, ret: NativePtr, args: NativeArray<NativePtrBox>,
|
||||
userData: (NativePtr, NativeArray<NativePtrBox>) -> Unit) {
|
||||
|
||||
userData.invoke(ret, args)
|
||||
}
|
||||
|
||||
private external fun ffiCreateClosure0(ffiCif: Long, userData: Any): Long
|
||||
|
||||
/**
|
||||
* Uses libffi to allocate a native function which will call [ffiFunImpl] when invoked.
|
||||
*
|
||||
* @param ffiCif describes the type of the function to create
|
||||
*/
|
||||
private fun ffiCreateClosure(ffiCif: ffi_cif, userData: (NativePtr, NativeArray<NativePtrBox>) -> Unit): NativePtr {
|
||||
val res = ffiCreateClosure0(ffiCif.ptr.value, userData)
|
||||
|
||||
when (res) {
|
||||
0L -> throw OutOfMemoryError()
|
||||
-1L -> throw Error("libffi error occurred")
|
||||
}
|
||||
|
||||
return NativePtr.byValue(res)!!
|
||||
}
|
||||
|
||||
private external fun newGlobalRef(any: Any): Long
|
||||
private external fun derefGlobalRef(ref: Long): Any
|
||||
private external fun deleteGlobalRef(ref: Long)
|
||||
@@ -1,202 +0,0 @@
|
||||
package kotlin_native.interop
|
||||
|
||||
import java.io.Closeable
|
||||
|
||||
// TODO: what about equals/hashCode?
|
||||
|
||||
open class NativeRef(val ptr: NativePtr) {
|
||||
open class Type<T : NativeRef>(val byPtr: (NativePtr) -> T)
|
||||
open class TypeWithSize<T : NativeRef>(val size: Int, byPtr: (NativePtr) -> T) : NativeRef.Type<T>(byPtr)
|
||||
|
||||
final override fun equals(other: Any?): Boolean{
|
||||
if (this === other) return true
|
||||
if (other !is NativeRef) return false
|
||||
|
||||
return ptr == other.ptr
|
||||
}
|
||||
|
||||
final override fun hashCode(): Int{
|
||||
return ptr.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : NativeRef> NativePtr?.asRef(type: NativeRef.Type<T>) = this?.let { type.byPtr(this) }
|
||||
fun NativeRef?.getNativePtr() = this?.ptr
|
||||
|
||||
class Int8Box(ptr: NativePtr) : NativeRef(ptr) {
|
||||
companion object : NativeRef.TypeWithSize<Int8Box>(1, ::Int8Box)
|
||||
var value: Byte
|
||||
get() = bridge.getInt8(ptr)
|
||||
set(value) = bridge.putInt8(ptr, value)
|
||||
}
|
||||
|
||||
class Int16Box(ptr: NativePtr) : NativeRef(ptr) {
|
||||
companion object : NativeRef.TypeWithSize<Int16Box>(2, ::Int16Box)
|
||||
var value: Short
|
||||
get() = bridge.getInt16(ptr)
|
||||
set(value) = bridge.putInt16(ptr, value)
|
||||
}
|
||||
|
||||
class Int32Box(ptr: NativePtr) : NativeRef(ptr) {
|
||||
companion object : NativeRef.TypeWithSize<Int32Box>(4, ::Int32Box)
|
||||
var value: Int
|
||||
get() = bridge.getInt32(ptr)
|
||||
set(value) = bridge.putInt32(ptr, value)
|
||||
}
|
||||
|
||||
class NativePtrBox(ptr: NativePtr) : NativeRef(ptr) {
|
||||
companion object : NativeRef.TypeWithSize<NativePtrBox>(8, ::NativePtrBox) // TODO: 64-bit specific
|
||||
var value: NativePtr?
|
||||
get() = bridge.getPtr(ptr)
|
||||
set(value) = bridge.putPtr(ptr, value)
|
||||
}
|
||||
|
||||
class Int64Box(ptr: NativePtr) : NativeRef(ptr) {
|
||||
companion object : NativeRef.TypeWithSize<Int64Box>(8, ::Int64Box)
|
||||
var value: Long
|
||||
get() = bridge.getInt64(ptr)
|
||||
set(value) = bridge.putInt64(ptr, value)
|
||||
}
|
||||
|
||||
class RefBox<T : NativeRef>(ptr: NativePtr, val referentType: NativeRef.Type<T>) : NativeRef(ptr) {
|
||||
companion object {
|
||||
infix fun <T : NativeRef> of(type: NativeRef.Type<T>) = NativeRef.TypeWithSize<RefBox<T>>(8, { RefBox(it, type) }) // TODO: 64-bit specific
|
||||
}
|
||||
|
||||
var value: T?
|
||||
get() = bridge.getPtr(ptr).asRef(referentType)
|
||||
set(value) = bridge.putPtr(ptr, value.getNativePtr())
|
||||
}
|
||||
|
||||
val <T : NativeRef> NativeRef.Type<T>.ref: NativeRef.TypeWithSize<RefBox<T>>
|
||||
get() = Ref to this
|
||||
|
||||
object Ref {
|
||||
infix fun <T : NativeRef> to(type: NativeRef.Type<T>) = RefBox.Companion of type
|
||||
infix fun to(type: Byte.Companion) = Int8Box.Companion
|
||||
infix fun to(type: Short.Companion) = Int16Box.Companion
|
||||
infix fun to(type: Int.Companion) = Int32Box.Companion
|
||||
infix fun to(type: Long.Companion) = Int64Box.Companion
|
||||
}
|
||||
|
||||
open class NativeStruct(ptr: NativePtr) : NativeRef(ptr) {
|
||||
open class Type<T : NativeStruct>(size: Int, byPtr: (NativePtr) -> T) : NativeRef.TypeWithSize<T>(size, byPtr)
|
||||
|
||||
companion object {
|
||||
class FieldAt<T : NativeRef>(val type: NativeRef.Type<T>, val offset: Int) {
|
||||
operator fun getValue(thisRef: NativeStruct, property: kotlin.reflect.KProperty<*>): T {
|
||||
return type.byPtr(thisRef.ptr.displacedBy(offset))
|
||||
}
|
||||
}
|
||||
|
||||
infix fun <T : NativeRef> NativeRef.Type<T>.at(offset: Int) = NativeStruct.Companion.FieldAt(this, offset)
|
||||
}
|
||||
}
|
||||
|
||||
class NativeArray<T : NativeRef>(ptr: NativePtr, val elemType: NativeRef.TypeWithSize<T>) : NativeRef(ptr) {
|
||||
operator fun get(index: Int): T {
|
||||
return elemType.byPtr(ptr.displacedBy(index * elemType.size))
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
class Type<T : NativeRef> (val elemType: NativeRef.TypeWithSize<T>) :
|
||||
NativeRef.Type<NativeArray<T>>({ ptr -> NativeArray(ptr, elemType) }) {
|
||||
|
||||
infix fun length(length: Int) =
|
||||
NativeRef.TypeWithSize(elemType.size * length, { ptr -> NativeArray(ptr, elemType) })
|
||||
}
|
||||
|
||||
infix fun <T : NativeRef> of(elemType: NativeRef.TypeWithSize<T>) = NativeArray.Companion.Type(elemType)
|
||||
|
||||
fun <T : NativeRef> byRefToFirstElem(ref: T, refType: NativeRef.TypeWithSize<T>) = NativeArray(ref.ptr, refType)
|
||||
}
|
||||
}
|
||||
|
||||
operator fun <T : NativeRef> NativeRef.TypeWithSize<T>.get(length: Int) = NativeArray.Companion of this length length
|
||||
object array {
|
||||
|
||||
// array(type)
|
||||
operator fun <T : NativeRef> invoke(type: NativeRef.TypeWithSize<T>) = NativeArray.Companion of type
|
||||
|
||||
// array[length](type)
|
||||
operator fun get(length: Int) = array.ArrayWithLength(length)
|
||||
|
||||
class ArrayWithLength(val length: Int) {
|
||||
infix fun <T : NativeRef> of(type: NativeRef.TypeWithSize<T>) = NativeArray.Companion of type length length
|
||||
|
||||
operator fun <T : NativeRef> invoke(type: NativeRef.TypeWithSize<T>) = this of type
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class CString private constructor(internal val array: NativeArray<Int8Box>) : NativeRef(array.ptr) {
|
||||
companion object {
|
||||
fun fromArray(array: NativeArray<Int8Box>) = CString(array)
|
||||
}
|
||||
|
||||
fun length(): Int {
|
||||
var res = 0
|
||||
while (array[res].value != 0.toByte()) {
|
||||
++res
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val bytes = ByteArray(this.length())
|
||||
bytes.forEachIndexed { i, byte ->
|
||||
bytes[i] = this.array[i].value
|
||||
}
|
||||
return String(bytes) // TODO: encoding
|
||||
}
|
||||
|
||||
fun asCharPtr() = array[0]
|
||||
}
|
||||
|
||||
class __va_list_tag(ptr: NativePtr) : NativeRef(ptr) // FIXME
|
||||
|
||||
interface Placement {
|
||||
fun alloc(size: Int): NativePtr
|
||||
}
|
||||
|
||||
object heap : Placement {
|
||||
override fun alloc(size: Int) = bridge.malloc(size)
|
||||
|
||||
fun free(ptr: NativePtr) = bridge.free(ptr)
|
||||
|
||||
fun free(ref: NativeRef) = free(ref.ptr)
|
||||
}
|
||||
|
||||
// TODO: implement optimally
|
||||
class Arena : Placement, Closeable {
|
||||
|
||||
private val allocatedChunks = mutableListOf<NativePtr>()
|
||||
|
||||
override fun alloc(size: Int): NativePtr {
|
||||
val res = heap.alloc(size)
|
||||
try {
|
||||
allocatedChunks.add(res)
|
||||
return res
|
||||
} catch (e: Throwable) {
|
||||
heap.free(res)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
allocatedChunks.forEach {
|
||||
heap.free(it)
|
||||
}
|
||||
|
||||
allocatedChunks.clear()
|
||||
}
|
||||
|
||||
override fun close() = clear()
|
||||
|
||||
}
|
||||
|
||||
fun <T : NativeRef> Placement.alloc(type: NativeRef.TypeWithSize<T>): T {
|
||||
return type.byPtr(this.alloc(type.size))
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package kotlin_native.interop
|
||||
|
||||
fun <T : NativeRef> malloc(type: NativeRef.TypeWithSize<T>) = type.byPtr(bridge.malloc(type.size))
|
||||
|
||||
fun free(ptr: NativePtr?) {
|
||||
if (ptr != null) {
|
||||
bridge.free(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
fun free(ref: NativeRef?) = free(ref.getNativePtr())
|
||||
|
||||
fun <T : NativeRef> Placement.allocNativeArrayOf(elemType: NativeRef.Type<T>, elements: List<T?>): NativeArray<RefBox<T>> {
|
||||
val res = this.alloc(array[elements.size](elemType.ref))
|
||||
elements.forEachIndexed { i, element ->
|
||||
res[i].value = element
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
fun <T : NativeRef> Placement.allocNativeArrayOf(elemType: NativeRef.Type<T>, vararg elements: T?) =
|
||||
allocNativeArrayOf(elemType, elements.toList())
|
||||
|
||||
fun <T : NativeRef> mallocNativeArrayOf(elemType: NativeRef.Type<T>, vararg elements: T?) = heap.allocNativeArrayOf(elemType, *elements)
|
||||
|
||||
fun Placement.allocNativeArrayOf(elements: ByteArray): NativeArray<Int8Box> {
|
||||
val res = this.alloc(array[elements.size](Int8Box))
|
||||
elements.forEachIndexed { i, element ->
|
||||
res[i].value = element
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
fun CString.Companion.fromString(str: String?): CString? {
|
||||
return str?.toCString(heap)
|
||||
}
|
||||
|
||||
fun Int8Box.asCString() = CString.fromArray(NativeArray.byRefToFirstElem(this, Int8Box))
|
||||
|
||||
fun String.toCString(retValPlacement: Placement): CString {
|
||||
val bytes = this.toByteArray() // TODO: encoding
|
||||
val len = bytes.size
|
||||
val nativeBytes = retValPlacement.alloc(array[len + 1](Int8Box))
|
||||
|
||||
bytes.forEachIndexed { i, byte ->
|
||||
nativeBytes[i].value = byte
|
||||
}
|
||||
nativeBytes[len].value = 0
|
||||
|
||||
return CString.fromArray(nativeBytes)
|
||||
}
|
||||
|
||||
class MemScope private constructor(private val arena: Arena) : Placement by arena {
|
||||
val memScope: Placement
|
||||
get() = this
|
||||
|
||||
companion object {
|
||||
internal inline fun <R> use(block: MemScope.()->R): R {
|
||||
val memScope = MemScope(Arena())
|
||||
try {
|
||||
return memScope.block()
|
||||
} finally {
|
||||
memScope.arena.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs given [block] providing allocation of memory
|
||||
* which will be automatically disposed at the end of this scope.
|
||||
*/
|
||||
inline fun <R> memScoped(block: MemScope.()->R): R {
|
||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") // TODO: it is a hack
|
||||
return MemScope.use(block)
|
||||
}
|
||||
Reference in New Issue
Block a user