Implement scope-local C pointer. (#1471)
This commit is contained in:
+16
@@ -337,6 +337,22 @@ manually:
|
|||||||
|
|
||||||
In all cases the C string is supposed to be encoded as UTF-8.
|
In all cases the C string is supposed to be encoded as UTF-8.
|
||||||
|
|
||||||
|
### Scope-local pointers ###
|
||||||
|
|
||||||
|
It is possible to create scope-stable pointer of C representation of `CValues<T>`
|
||||||
|
instance using `CValues<T>.ptr` extension property available under memScoped { ... }.
|
||||||
|
It allows to use APIs which requires C pointers with lifetime bound to certain `MemScope`. For example:
|
||||||
|
```
|
||||||
|
memScoped {
|
||||||
|
items = arrayOfNulls<CPointer<ITEM>?>(6)
|
||||||
|
arrayOf("one", "two").forEachIndexed { index, value -> items[index] = value.cstr.ptr }
|
||||||
|
menu = new_menu("Menu".cstr.ptr, items.toCValues().ptr)
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
In this example all values passed to the C API `new_menu()` have lifetime of innermost `memScope`
|
||||||
|
it belongs to. Once control flow will leave `memScoped` scope C pointers become invalid.
|
||||||
|
|
||||||
### Passing and receiving structs by value ###
|
### Passing and receiving structs by value ###
|
||||||
|
|
||||||
When C function takes or returns a struct `T` by value, the corresponding
|
When C function takes or returns a struct `T` by value, the corresponding
|
||||||
|
|||||||
@@ -412,6 +412,9 @@ class MemScope : ArenaBase() {
|
|||||||
|
|
||||||
val memScope: MemScope
|
val memScope: MemScope
|
||||||
get() = this
|
get() = this
|
||||||
|
|
||||||
|
val <T: CVariable> CValues<T>.ptr: CPointer<T>
|
||||||
|
get() = this@ptr.getPointer(this@MemScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: consider renaming `memScoped` because it now supports `defer`.
|
// TODO: consider renaming `memScoped` because it now supports `defer`.
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ buildscript {
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
|
google()
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'konan'
|
apply plugin: 'konan'
|
||||||
@@ -81,4 +82,4 @@ task buildApk(type: Copy) {
|
|||||||
dependsOn "assembleDebug"
|
dependsOn "assembleDebug"
|
||||||
destinationDir outDir
|
destinationDir outDir
|
||||||
from 'build/outputs/apk'
|
from 'build/outputs/apk'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -306,10 +306,10 @@ class Renderer(val parentArena: NativePlacement, val nativeActivity: ANativeActi
|
|||||||
}
|
}
|
||||||
|
|
||||||
glFrontFace(GL_CW)
|
glFrontFace(GL_CW)
|
||||||
glVertexPointer(4, GL_FLOAT, 0, vertices.toFloatArray().toCValues().getPointer(this))
|
glVertexPointer(4, GL_FLOAT, 0, vertices.toFloatArray().toCValues().ptr)
|
||||||
glTexCoordPointer(2, GL_FLOAT, 0, texCoords.toFloatArray().toCValues().getPointer(this))
|
glTexCoordPointer(2, GL_FLOAT, 0, texCoords.toFloatArray().toCValues().ptr)
|
||||||
glNormalPointer(GL_FLOAT, 0, normals.toFloatArray().toCValues().getPointer(this))
|
glNormalPointer(GL_FLOAT, 0, normals.toFloatArray().toCValues().ptr)
|
||||||
glDrawElements(GL_TRIANGLES, triangles.size, GL_UNSIGNED_BYTE, triangles.toByteArray().toCValues().getPointer(this))
|
glDrawElements(GL_TRIANGLES, triangles.size, GL_UNSIGNED_BYTE, triangles.toByteArray().toCValues().ptr)
|
||||||
|
|
||||||
glPopMatrix()
|
glPopMatrix()
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ fun gtkMain(args: Array<String>): Int {
|
|||||||
g_signal_connect(app, "activate", staticCFunction(::activate))
|
g_signal_connect(app, "activate", staticCFunction(::activate))
|
||||||
val status = memScoped {
|
val status = memScoped {
|
||||||
g_application_run(app.reinterpret(),
|
g_application_run(app.reinterpret(),
|
||||||
args.size, args.map { it.cstr.getPointer(memScope) }.toCValues())
|
args.size, args.map { it.cstr.ptr }.toCValues())
|
||||||
}
|
}
|
||||||
g_object_unref(app)
|
g_object_unref(app)
|
||||||
return status
|
return status
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ fun main(args: Array<String>) {
|
|||||||
val bufferLength = 100L
|
val bufferLength = 100L
|
||||||
val buffer = allocArray<ByteVar>(bufferLength)
|
val buffer = allocArray<ByteVar>(bufferLength)
|
||||||
val connectionIdString = "#${++connectionId}: ".cstr
|
val connectionIdString = "#${++connectionId}: ".cstr
|
||||||
val connectionIdBytes = connectionIdString.getPointer(this)
|
val connectionIdBytes = connectionIdString.ptr
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -212,4 +212,4 @@ inline fun Long.ensureUnixCallResult(predicate: (Long) -> Boolean): Long {
|
|||||||
throw Error(getUnixError())
|
throw Error(getUnixError())
|
||||||
}
|
}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import platform.UIKit.*
|
|||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
memScoped {
|
memScoped {
|
||||||
val argc = args.size + 1
|
val argc = args.size + 1
|
||||||
val argv = (arrayOf("konan") + args).map { it.cstr.getPointer(memScope) }.toCValues()
|
val argv = (arrayOf("konan") + args).map { it.cstr.ptr }.toCValues()
|
||||||
|
|
||||||
autoreleasepool {
|
autoreleasepool {
|
||||||
UIApplicationMain(argc, argv, null, NSStringFromClass(AppDelegate))
|
UIApplicationMain(argc, argv, null, NSStringFromClass(AppDelegate))
|
||||||
|
|||||||
Reference in New Issue
Block a user