Minorly rework CValuesRef to make it more universal when subclassing

Allow `getPointer` to register custom disposers with `defer`
This commit is contained in:
Svyatoslav Scherbina
2017-09-19 12:37:13 +03:00
committed by SvyatoslavScherbina
parent a3721f857c
commit 17ccd3ee02
8 changed files with 46 additions and 55 deletions
@@ -184,9 +184,9 @@ internal fun CValue<CXCursor>.isLeaf(): Boolean {
return !hasChildren
}
internal fun List<String>.toNativeStringArray(placement: NativePlacement): CArrayPointer<CPointerVar<ByteVar>> {
return placement.allocArray(this.size) { index ->
this.value = this@toNativeStringArray[index].cstr.getPointer(placement)
internal fun List<String>.toNativeStringArray(scope: AutofreeScope): CArrayPointer<CPointerVar<ByteVar>> {
return scope.allocArray(this.size) { index ->
this.value = this@toNativeStringArray[index].cstr.getPointer(scope)
}
}
@@ -70,26 +70,7 @@ abstract class CValuesRef<T : CPointed> {
* If this reference is [CPointer], returns this pointer.
* Otherwise copies the referenced values to [placement] and returns the pointer to the copy.
*/
abstract fun getPointer(placement: NativePlacement): CPointer<T>
}
inline fun <T : CPointed, R> CValuesRef<T>?.usePointer(block: (CPointer<T>?) -> R): R {
val allocated: Boolean
val pointer: CPointer<T>? = if (this is CPointer<T>?) {
allocated = false
this
} else {
allocated = true
this!!.getPointer(nativeHeap)
}
return try {
block(pointer)
} finally {
if (allocated) {
nativeHeap.free(pointer.rawValue)
}
}
abstract fun getPointer(scope: AutofreeScope): CPointer<T>
}
/**
@@ -100,7 +81,7 @@ abstract class CValues<T : CVariable> : CValuesRef<T>() {
/**
* Copies the values to [placement] and returns the pointer to the copy.
*/
override abstract fun getPointer(placement: NativePlacement): CPointer<T>
override abstract fun getPointer(scope: AutofreeScope): CPointer<T>
// TODO: optimize
override fun equals(other: Any?): Boolean {
@@ -134,7 +115,7 @@ abstract class CValues<T : CVariable> : CValuesRef<T>() {
abstract val size: Int
}
fun <T : CVariable> CValues<T>.placeTo(placement: NativePlacement) = this.getPointer(placement)
fun <T : CVariable> CValues<T>.placeTo(scope: AutofreeScope) = this.getPointer(scope)
/**
* The single immutable C value.
@@ -163,7 +144,7 @@ class CPointer<T : CPointed> internal constructor(val rawValue: NativePtr) : CVa
override fun toString() = this.cPointerToString()
override fun getPointer(placement: NativePlacement) = this
override fun getPointer(scope: AutofreeScope) = this
}
/**
@@ -65,7 +65,11 @@ open class DeferScope {
}
}
open class ArenaBase(private val parent: NativeFreeablePlacement = nativeHeap) : NativePlacement, DeferScope() {
abstract class AutofreeScope : DeferScope(), NativePlacement {
override abstract fun alloc(size: Long, align: Int): NativePointed
}
open class ArenaBase(private val parent: NativeFreeablePlacement = nativeHeap) : AutofreeScope() {
private var lastChunk: NativePointed? = null
@@ -209,8 +213,8 @@ fun NativePlacement.allocArrayOf(vararg elements: Float): CArrayPointer<FloatVar
fun <T : CPointed> NativePlacement.allocPointerTo() = alloc<CPointerVar<T>>()
fun <T : CVariable> zeroValue(size: Int, align: Int): CValue<T> = object : CValue<T>() {
override fun getPointer(placement: NativePlacement): CPointer<T> {
val result = placement.alloc(size, align)
override fun getPointer(scope: AutofreeScope): CPointer<T> {
val result = scope.alloc(size, align)
nativeMemUtils.zeroMemory(result, size)
return interpretCPointer(result.rawPtr)!!
}
@@ -232,7 +236,7 @@ fun <T : CVariable> CPointed.readValues(size: Int, align: Int): CValues<T> {
nativeMemUtils.getByteArray(this, bytes, size)
return object : CValues<T>() {
override fun getPointer(placement: NativePlacement): CPointer<T> = placement.placeBytes(bytes, align)
override fun getPointer(scope: AutofreeScope): CPointer<T> = scope.placeBytes(bytes, align)
override val size get() = bytes.size
}
}
@@ -244,7 +248,7 @@ fun <T : CVariable> CPointed.readValue(size: Long, align: Int): CValue<T> {
val bytes = ByteArray(size.toInt())
nativeMemUtils.getByteArray(this, bytes, size.toInt())
return object : CValue<T>() {
override fun getPointer(placement: NativePlacement): CPointer<T> = placement.placeBytes(bytes, align)
override fun getPointer(scope: AutofreeScope): CPointer<T> = scope.placeBytes(bytes, align)
override val size get() = bytes.size
}
}
@@ -255,7 +259,7 @@ inline fun <reified T : CStructVar> T.readValue(): CValue<T> = this.readValue(si
fun CValue<*>.write(location: NativePtr) {
// TODO: probably CValue must be redesigned.
val fakePlacement = object : NativePlacement {
val fakeScope = object : AutofreeScope() {
var used = false
override fun alloc(size: Long, align: Int): NativePointed {
assert(!used)
@@ -264,8 +268,8 @@ fun CValue<*>.write(location: NativePtr) {
}
}
this.getPointer(fakePlacement)
assert(fakePlacement.used)
this.getPointer(fakeScope)
assert(fakeScope.used)
}
// TODO: optimize
@@ -302,7 +306,7 @@ inline fun <reified T : CVariable> createValues(count: Int, initializer: T.(inde
}
fun cValuesOf(vararg elements: Byte): CValues<ByteVar> = object : CValues<ByteVar>() {
override fun getPointer(placement: NativePlacement) = placement.allocArrayOf(elements)
override fun getPointer(scope: AutofreeScope) = scope.allocArrayOf(elements)
override val size get() = 1 * elements.size
}
@@ -318,7 +322,7 @@ fun cValuesOf(vararg elements: Long): CValues<LongVar> =
createValues(elements.size) { index -> this.value = elements[index] }
fun cValuesOf(vararg elements: Float): CValues<FloatVar> = object : CValues<FloatVar>() {
override fun getPointer(placement: NativePlacement) = placement.allocArrayOf(*elements)
override fun getPointer(scope: AutofreeScope) = scope.allocArrayOf(*elements)
override val size get() = 4 * elements.size
}
@@ -348,8 +352,8 @@ val String.cstr: CValues<ByteVar>
return object : CValues<ByteVar>() {
override val size get() = bytes.size + 1
override fun getPointer(placement: NativePlacement): CPointer<ByteVar> {
val result = placement.allocArray<ByteVar>(bytes.size + 1)
override fun getPointer(scope: AutofreeScope): CPointer<ByteVar> {
val result = scope.allocArray<ByteVar>(bytes.size + 1)
nativeMemUtils.putByteArray(bytes, result.pointed, bytes.size)
result[bytes.size] = 0.toByte()
return result
@@ -363,8 +367,8 @@ val String.wcstr: CValues<ShortVar>
return object : CValues<ShortVar>() {
override val size get() = 2 * (chars.size + 1)
override fun getPointer(placement: NativePlacement): CPointer<ShortVar> {
val result = placement.allocArray<ShortVar>(chars.size + 1)
override fun getPointer(scope: AutofreeScope): CPointer<ShortVar> {
val result = scope.allocArray<ShortVar>(chars.size + 1)
nativeMemUtils.putCharArray(chars, result.pointed, chars.size)
result[chars.size] = 0.toShort()
return result
@@ -16,7 +16,7 @@ const val FFI_TYPE_KIND_POINTER: FfiTypeKind = 7
private tailrec fun convertArgument(
argument: Any?, isVariadic: Boolean, location: COpaquePointer,
additionalPlacement: NativePlacement
additionalPlacement: AutofreeScope
): FfiTypeKind = when (argument) {
is CValuesRef<*>? -> {
location.reinterpret<CPointerVar<*>>()[0] = argument?.getPointer(additionalPlacement)
@@ -96,7 +96,7 @@ inline fun <reified T : CVariable> NativePlacement.allocFfiReturnValueBuffer(ty
fun callWithVarargs(codePtr: NativePtr, returnValuePtr: NativePtr, returnTypeKind: FfiTypeKind,
fixedArguments: Array<out Any?>, variadicArguments: Array<out Any?>,
argumentsPlacement: NativePlacement) {
argumentsPlacement: AutofreeScope) {
val totalArgumentsNumber = fixedArguments.size + variadicArguments.size
@@ -40,6 +40,14 @@ class KotlinCodeBuilder {
lines.add(" ".repeat(nesting) + line)
}
private var memScoped = false
fun pushMemScoped() {
if (!memScoped) {
memScoped = true
pushBlock("memScoped {")
}
}
fun pushBlock(line: String, free: String = "") {
out(line)
freeStack.add(free)
@@ -41,9 +41,9 @@ class MappingBridgeGeneratorImpl(
kotlinValues.forEachIndexed { index, (type, value) ->
if (type.unwrapTypedefs() is RecordType) {
val tmpVarName = "kni$index"
builder.pushBlock("$value.usePointer { $tmpVarName ->")
bridgeArguments.add(BridgeTypedKotlinValue(BridgedType.NATIVE_PTR, "$tmpVarName.rawValue"))
builder.pushMemScoped()
val bridgeArgument = "$value.getPointer(memScope).rawValue"
bridgeArguments.add(BridgeTypedKotlinValue(BridgedType.NATIVE_PTR, bridgeArgument))
} else {
val info = mirror(declarationMapper, type).info
bridgeArguments.add(BridgeTypedKotlinValue(info.bridgedType, info.argToBridged(value)))
@@ -599,24 +599,22 @@ class StubGenerator(
}
}
val tmpVarName = "kniTmp$index"
val representAsValuesRef = representCFunctionParameterAsValuesRef(parameter.type)
val bridgeArgument = if (representCFunctionParameterAsString(parameter.type)) {
kotlinParameters.add(parameterName to KotlinTypes.string.makeNullable())
bodyGenerator.pushBlock("$parameterName?.cstr.usePointer { $tmpVarName ->")
tmpVarName
bodyGenerator.pushMemScoped()
"$parameterName?.cstr?.getPointer(memScope)"
} else if (representCFunctionParameterAsWString(parameter.type)) {
kotlinParameters.add(parameterName to KotlinTypes.string.makeNullable())
bodyGenerator.pushBlock("$parameterName?.wcstr.usePointer { $tmpVarName ->")
tmpVarName
bodyGenerator.pushMemScoped()
"$parameterName?.wcstr?.getPointer(memScope)"
} else if (representAsValuesRef != null) {
val pointedType = mirror(representAsValuesRef).pointedType
val parameterType = KotlinTypes.cValuesRef.typeWith(pointedType).makeNullable()
kotlinParameters.add(parameterName to parameterType)
bodyGenerator.pushBlock("$parameterName.usePointer { $tmpVarName ->")
tmpVarName
bodyGenerator.pushMemScoped()
"$parameterName?.getPointer(memScope)"
} else {
val mirror = mirror(parameter.type)
kotlinParameters.add(parameterName to mirror.argType)
@@ -640,7 +638,7 @@ class StubGenerator(
val returnTypeKind = getFfiTypeKind(func.returnType)
kotlinParameters.add("vararg variadicArguments" to KotlinTypes.any.makeNullable())
bodyGenerator.pushBlock("memScoped {")
bodyGenerator.pushMemScoped()
val resultVar = "kniResult"
@@ -67,7 +67,7 @@ class CPointerBox(val value: CPointer<CPointed>) : CValuesRef<CPointed>() {
override fun toString() = value.toString()
override fun getPointer(placement: NativePlacement) = value.getPointer(placement)
override fun getPointer(scope: AutofreeScope) = value.getPointer(scope)
}
fun boxCPointer(value: CPointer<CPointed>?) = if (value != null) CPointerBox(value) else null