Use unsigned types in interop (#1913)

This commit is contained in:
SvyatoslavScherbina
2018-08-24 18:30:56 +03:00
committed by GitHub
parent 29cddb46bf
commit 8f1b94f38b
46 changed files with 665 additions and 192 deletions
+11 -15
View File
@@ -468,28 +468,24 @@ Sometimes the C libraries have function parameters or struct fields of
platform-dependent type, e.g. `long` or `size_t`. Kotlin itself doesn't provide
neither implicit integer casts nor C-style integer casts (e.g.
`(size_t) intValue`), so to make writing portable code in such cases easier,
the following methods are provided:
`convert` method is provided:
* `fun ${type1}.signExtend<${type2}>(): ${type2}`
* `fun ${type1}.narrow<${type2}>(): ${type2}`
```
fun ${type1}.convert<${type2}>(): ${type2}
```
where each of `type1` and `type2` must be an integral type.
where each of `type1` and `type2` must be an integral type, either signed or unsigned.
The `signExtend` converts the integer value to more wide, i.e. the result must
have the same or greater size.
The `narrow` converts the integer value to smaller one (possibly changing the
value due to loosing significant bits), so the result must have the same or
less size.
`.convert<${type}>` has the same semantics as one of the
`.toByte`, `.toShort`, `.toInt`, `.toLong`,
`.toUByte`, `.toUShort`, `.toUInt` or `.toULong`
methods, depending on `type`.
Any allowed `.signExtend<${type}>` or `.narrow<${type}>` have the same
semantics as one of the `.toByte`, `.toShort`, `.toInt` or `.toLong` methods,
depending on `type`.
The example of using `signExtend`:
The example of using `convert`:
```
fun zeroMemory(buffer: COpaquePointer, size: Int) {
memset(buffer, 0, size.signExtend<size_t>())
memset(buffer, 0, size.convert<size_t>())
}
```
+6
View File
@@ -72,6 +72,12 @@ dependencies {
sourceSets.main.kotlin.srcDirs += "src/jvm/kotlin"
compileKotlin {
kotlinOptions {
freeCompilerArgs = ['-Xuse-experimental=kotlin.ExperimentalUnsignedTypes']
}
}
task nativelibs(type: Copy) {
dependsOn 'callbacksSharedLibrary'
@@ -121,7 +121,7 @@ private fun getEnumCType(classifier: KClass<*>): CEnumType? {
}
@Suppress("UNCHECKED_CAST")
return CEnumType(rawValueCType as CType<Number>)
return CEnumType(rawValueCType as CType<Any>)
}
private fun getArgOrRetValCType(type: KType): CType<*> {
@@ -346,7 +346,7 @@ private class Struct(val size: Long, val align: Int, elementTypes: List<CType<*>
override fun write(location: NativePtr, value: CValue<*>) = value.write(location)
}
private class CEnumType(private val rawValueCType: CType<Number>) : CType<CEnum>(rawValueCType.ffiType) {
private class CEnumType(private val rawValueCType: CType<Any>) : CType<CEnum>(rawValueCType.ffiType) {
override fun read(location: NativePtr): CEnum {
TODO("enum-typed callback parameters")
@@ -26,16 +26,20 @@ inline operator fun <T : ByteVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<
inline operator fun <T : ByteVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
this + index.toLong()
@JvmName("get\$Byte")
inline operator fun <T : Byte> CPointer<ByteVarOf<T>>.get(index: Int): T =
(this + index)!!.pointed.value
@JvmName("set\$Byte")
inline operator fun <T : Byte> CPointer<ByteVarOf<T>>.set(index: Int, value: T) {
(this + index)!!.pointed.value = value
}
@JvmName("get\$Byte")
inline operator fun <T : Byte> CPointer<ByteVarOf<T>>.get(index: Long): T =
(this + index)!!.pointed.value
@JvmName("set\$Byte")
inline operator fun <T : Byte> CPointer<ByteVarOf<T>>.set(index: Long, value: T) {
(this + index)!!.pointed.value = value
}
@@ -48,16 +52,20 @@ inline operator fun <T : ShortVarOf<*>> CPointer<T>?.plus(index: Long): CPointer
inline operator fun <T : ShortVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
this + index.toLong()
@JvmName("get\$Short")
inline operator fun <T : Short> CPointer<ShortVarOf<T>>.get(index: Int): T =
(this + index)!!.pointed.value
@JvmName("set\$Short")
inline operator fun <T : Short> CPointer<ShortVarOf<T>>.set(index: Int, value: T) {
(this + index)!!.pointed.value = value
}
@JvmName("get\$Short")
inline operator fun <T : Short> CPointer<ShortVarOf<T>>.get(index: Long): T =
(this + index)!!.pointed.value
@JvmName("set\$Short")
inline operator fun <T : Short> CPointer<ShortVarOf<T>>.set(index: Long, value: T) {
(this + index)!!.pointed.value = value
}
@@ -70,16 +78,20 @@ inline operator fun <T : IntVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T
inline operator fun <T : IntVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
this + index.toLong()
@JvmName("get\$Int")
inline operator fun <T : Int> CPointer<IntVarOf<T>>.get(index: Int): T =
(this + index)!!.pointed.value
@JvmName("set\$Int")
inline operator fun <T : Int> CPointer<IntVarOf<T>>.set(index: Int, value: T) {
(this + index)!!.pointed.value = value
}
@JvmName("get\$Int")
inline operator fun <T : Int> CPointer<IntVarOf<T>>.get(index: Long): T =
(this + index)!!.pointed.value
@JvmName("set\$Int")
inline operator fun <T : Int> CPointer<IntVarOf<T>>.set(index: Long, value: T) {
(this + index)!!.pointed.value = value
}
@@ -92,20 +104,128 @@ inline operator fun <T : LongVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<
inline operator fun <T : LongVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
this + index.toLong()
@JvmName("get\$Long")
inline operator fun <T : Long> CPointer<LongVarOf<T>>.get(index: Int): T =
(this + index)!!.pointed.value
@JvmName("set\$Long")
inline operator fun <T : Long> CPointer<LongVarOf<T>>.set(index: Int, value: T) {
(this + index)!!.pointed.value = value
}
@JvmName("get\$Long")
inline operator fun <T : Long> CPointer<LongVarOf<T>>.get(index: Long): T =
(this + index)!!.pointed.value
@JvmName("set\$Long")
inline operator fun <T : Long> CPointer<LongVarOf<T>>.set(index: Long, value: T) {
(this + index)!!.pointed.value = value
}
@JvmName("plus\$UByte")
inline operator fun <T : UByteVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? =
interpretCPointer(this.rawValue + index * 1)
@JvmName("plus\$UByte")
inline operator fun <T : UByteVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
this + index.toLong()
@JvmName("get\$UByte")
inline operator fun <T : UByte> CPointer<UByteVarOf<T>>.get(index: Int): T =
(this + index)!!.pointed.value
@JvmName("set\$UByte")
inline operator fun <T : UByte> CPointer<UByteVarOf<T>>.set(index: Int, value: T) {
(this + index)!!.pointed.value = value
}
@JvmName("get\$UByte")
inline operator fun <T : UByte> CPointer<UByteVarOf<T>>.get(index: Long): T =
(this + index)!!.pointed.value
@JvmName("set\$UByte")
inline operator fun <T : UByte> CPointer<UByteVarOf<T>>.set(index: Long, value: T) {
(this + index)!!.pointed.value = value
}
@JvmName("plus\$UShort")
inline operator fun <T : UShortVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? =
interpretCPointer(this.rawValue + index * 2)
@JvmName("plus\$UShort")
inline operator fun <T : UShortVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
this + index.toLong()
@JvmName("get\$UShort")
inline operator fun <T : UShort> CPointer<UShortVarOf<T>>.get(index: Int): T =
(this + index)!!.pointed.value
@JvmName("set\$UShort")
inline operator fun <T : UShort> CPointer<UShortVarOf<T>>.set(index: Int, value: T) {
(this + index)!!.pointed.value = value
}
@JvmName("get\$UShort")
inline operator fun <T : UShort> CPointer<UShortVarOf<T>>.get(index: Long): T =
(this + index)!!.pointed.value
@JvmName("set\$UShort")
inline operator fun <T : UShort> CPointer<UShortVarOf<T>>.set(index: Long, value: T) {
(this + index)!!.pointed.value = value
}
@JvmName("plus\$UInt")
inline operator fun <T : UIntVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? =
interpretCPointer(this.rawValue + index * 4)
@JvmName("plus\$UInt")
inline operator fun <T : UIntVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
this + index.toLong()
@JvmName("get\$UInt")
inline operator fun <T : UInt> CPointer<UIntVarOf<T>>.get(index: Int): T =
(this + index)!!.pointed.value
@JvmName("set\$UInt")
inline operator fun <T : UInt> CPointer<UIntVarOf<T>>.set(index: Int, value: T) {
(this + index)!!.pointed.value = value
}
@JvmName("get\$UInt")
inline operator fun <T : UInt> CPointer<UIntVarOf<T>>.get(index: Long): T =
(this + index)!!.pointed.value
@JvmName("set\$UInt")
inline operator fun <T : UInt> CPointer<UIntVarOf<T>>.set(index: Long, value: T) {
(this + index)!!.pointed.value = value
}
@JvmName("plus\$ULong")
inline operator fun <T : ULongVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? =
interpretCPointer(this.rawValue + index * 8)
@JvmName("plus\$ULong")
inline operator fun <T : ULongVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
this + index.toLong()
@JvmName("get\$ULong")
inline operator fun <T : ULong> CPointer<ULongVarOf<T>>.get(index: Int): T =
(this + index)!!.pointed.value
@JvmName("set\$ULong")
inline operator fun <T : ULong> CPointer<ULongVarOf<T>>.set(index: Int, value: T) {
(this + index)!!.pointed.value = value
}
@JvmName("get\$ULong")
inline operator fun <T : ULong> CPointer<ULongVarOf<T>>.get(index: Long): T =
(this + index)!!.pointed.value
@JvmName("set\$ULong")
inline operator fun <T : ULong> CPointer<ULongVarOf<T>>.set(index: Long, value: T) {
(this + index)!!.pointed.value = value
}
@JvmName("plus\$Float")
inline operator fun <T : FloatVarOf<*>> CPointer<T>?.plus(index: Long): CPointer<T>? =
interpretCPointer(this.rawValue + index * 4)
@@ -114,16 +234,20 @@ inline operator fun <T : FloatVarOf<*>> CPointer<T>?.plus(index: Long): CPointer
inline operator fun <T : FloatVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
this + index.toLong()
@JvmName("get\$Float")
inline operator fun <T : Float> CPointer<FloatVarOf<T>>.get(index: Int): T =
(this + index)!!.pointed.value
@JvmName("set\$Float")
inline operator fun <T : Float> CPointer<FloatVarOf<T>>.set(index: Int, value: T) {
(this + index)!!.pointed.value = value
}
@JvmName("get\$Float")
inline operator fun <T : Float> CPointer<FloatVarOf<T>>.get(index: Long): T =
(this + index)!!.pointed.value
@JvmName("set\$Float")
inline operator fun <T : Float> CPointer<FloatVarOf<T>>.set(index: Long, value: T) {
(this + index)!!.pointed.value = value
}
@@ -136,16 +260,20 @@ inline operator fun <T : DoubleVarOf<*>> CPointer<T>?.plus(index: Long): CPointe
inline operator fun <T : DoubleVarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? =
this + index.toLong()
@JvmName("get\$Double")
inline operator fun <T : Double> CPointer<DoubleVarOf<T>>.get(index: Int): T =
(this + index)!!.pointed.value
@JvmName("set\$Double")
inline operator fun <T : Double> CPointer<DoubleVarOf<T>>.set(index: Int, value: T) {
(this + index)!!.pointed.value = value
}
@JvmName("get\$Double")
inline operator fun <T : Double> CPointer<DoubleVarOf<T>>.get(index: Long): T =
(this + index)!!.pointed.value
@JvmName("set\$Double")
inline operator fun <T : Double> CPointer<DoubleVarOf<T>>.set(index: Long, value: T) {
(this + index)!!.pointed.value = value
}
@@ -163,16 +291,20 @@ echo "@JvmName(\"plus\\\$$1\")"
echo "inline operator fun <T : ${1}VarOf<*>> CPointer<T>?.plus(index: Int): CPointer<T>? ="
echo " this + index.toLong()"
echo
echo "@JvmName(\"get\\\$$1\")"
echo "inline operator fun <T : $1> CPointer<${1}VarOf<T>>.get(index: Int): T ="
echo " (this + index)!!.pointed.value"
echo
echo "@JvmName(\"set\\\$$1\")"
echo "inline operator fun <T : $1> CPointer<${1}VarOf<T>>.set(index: Int, value: T) {"
echo " (this + index)!!.pointed.value = value"
echo '}'
echo
echo "@JvmName(\"get\\\$$1\")"
echo "inline operator fun <T : $1> CPointer<${1}VarOf<T>>.get(index: Long): T ="
echo " (this + index)!!.pointed.value"
echo
echo "@JvmName(\"set\\\$$1\")"
echo "inline operator fun <T : $1> CPointer<${1}VarOf<T>>.set(index: Long, value: T) {"
echo " (this + index)!!.pointed.value = value"
echo '}'
@@ -183,6 +315,10 @@ gen Byte 1
gen Short 2
gen Int 4
gen Long 8
gen UByte 1
gen UShort 2
gen UInt 4
gen ULong 8
gen Float 4
gen Double 8
@@ -246,7 +246,7 @@ sealed class CPrimitiveVar(rawPtr: NativePtr) : CVariable(rawPtr) {
}
interface CEnum {
val value: Number
val value: Any
}
abstract class CEnumVar(rawPtr: NativePtr) : CPrimitiveVar(rawPtr)
@@ -278,6 +278,26 @@ class LongVarOf<T : Long>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
companion object : Type(8)
}
@Suppress("FINAL_UPPER_BOUND")
class UByteVarOf<T : UByte>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
companion object : Type(1)
}
@Suppress("FINAL_UPPER_BOUND")
class UShortVarOf<T : UShort>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
companion object : Type(2)
}
@Suppress("FINAL_UPPER_BOUND")
class UIntVarOf<T : UInt>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
companion object : Type(4)
}
@Suppress("FINAL_UPPER_BOUND")
class ULongVarOf<T : ULong>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
companion object : Type(8)
}
@Suppress("FINAL_UPPER_BOUND")
class FloatVarOf<T : Float>(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) {
companion object : Type(4)
@@ -293,6 +313,10 @@ typealias ByteVar = ByteVarOf<Byte>
typealias ShortVar = ShortVarOf<Short>
typealias IntVar = IntVarOf<Int>
typealias LongVar = LongVarOf<Long>
typealias UByteVar = UByteVarOf<UByte>
typealias UShortVar = UShortVarOf<UShort>
typealias UIntVar = UIntVarOf<UInt>
typealias ULongVar = ULongVarOf<ULong>
typealias FloatVar = FloatVarOf<Float>
typealias DoubleVar = DoubleVarOf<Double>
@@ -330,6 +354,26 @@ var <T : Long> LongVarOf<T>.value: T
get() = nativeMemUtils.getLong(this) as T
set(value) = nativeMemUtils.putLong(this, value)
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
var <T : UByte> UByteVarOf<T>.value: T
get() = nativeMemUtils.getByte(this).toUByte() as T
set(value) = nativeMemUtils.putByte(this, value.toByte())
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
var <T : UShort> UShortVarOf<T>.value: T
get() = nativeMemUtils.getShort(this).toUShort() as T
set(value) = nativeMemUtils.putShort(this, value.toShort())
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
var <T : UInt> UIntVarOf<T>.value: T
get() = nativeMemUtils.getInt(this).toUInt() as T
set(value) = nativeMemUtils.putInt(this, value.toInt())
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
var <T : ULong> ULongVarOf<T>.value: T
get() = nativeMemUtils.getLong(this).toULong() as T
set(value) = nativeMemUtils.putLong(this, value.toLong())
// TODO: ensure native floats have the appropriate binary representation
@Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST")
@@ -321,6 +321,22 @@ fun cValuesOf(vararg elements: Int): CValues<IntVar> =
fun cValuesOf(vararg elements: Long): CValues<LongVar> =
createValues(elements.size) { index -> this.value = elements[index] }
@JvmName("cValuesOfUnsigned")
fun cValuesOf(vararg elements: UByte): CValues<UByteVar> =
createValues(elements.size) { index -> this.value = elements[index] }
@JvmName("cValuesOfUnsigned")
fun cValuesOf(vararg elements: UShort): CValues<UShortVar> =
createValues(elements.size) { index -> this.value = elements[index] }
@JvmName("cValuesOfUnsigned")
fun cValuesOf(vararg elements: UInt): CValues<UIntVar> =
createValues(elements.size) { index -> this.value = elements[index] }
@JvmName("cValuesOfUnsigned")
fun cValuesOf(vararg elements: ULong): CValues<ULongVar> =
createValues(elements.size) { index -> this.value = elements[index] }
fun cValuesOf(vararg elements: Float): CValues<FloatVar> = object : CValues<FloatVar>() {
override fun getPointer(scope: AutofreeScope) = scope.allocArrayOf(*elements)
override val size get() = 4 * elements.size
@@ -102,6 +102,34 @@ private fun invokeImplLongRet(ptr: COpaquePointer, vararg args: Any?): Long = me
resultBuffer.value
}
@ExportForCompiler
private fun invokeImplUByteRet(ptr: COpaquePointer, vararg args: Any?): UByte = memScoped {
val resultBuffer = allocFfiReturnValueBuffer<UByteVar>(UByteVar)
callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_UINT8, args, null, memScope)
resultBuffer.value
}
@ExportForCompiler
private fun invokeImplUShortRet(ptr: COpaquePointer, vararg args: Any?): UShort = memScoped {
val resultBuffer = allocFfiReturnValueBuffer<UShortVar>(UShortVar)
callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_UINT16, args, null, memScope)
resultBuffer.value
}
@ExportForCompiler
private fun invokeImplUIntRet(ptr: COpaquePointer, vararg args: Any?): UInt = memScoped {
val resultBuffer = allocFfiReturnValueBuffer<UIntVar>(UIntVar)
callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_UINT32, args, null, memScope)
resultBuffer.value
}
@ExportForCompiler
private fun invokeImplULongRet(ptr: COpaquePointer, vararg args: Any?): ULong = memScoped {
val resultBuffer = allocFfiReturnValueBuffer<ULongVar>(ULongVar)
callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_UINT64, args, null, memScope)
resultBuffer.value
}
@ExportForCompiler
private fun invokeImplFloatRet(ptr: COpaquePointer, vararg args: Any?): Float = memScoped {
val resultBuffer = allocFfiReturnValueBuffer<FloatVar>(FloatVar)
@@ -28,12 +28,23 @@ external fun bitsToFloat(bits: Int): Float
@Intrinsic
external fun bitsToDouble(bits: Long): Double
// TODO: deprecate.
@Intrinsic
external fun <R : Number> Number.signExtend(): R
// TODO: deprecate.
@Intrinsic
external fun <R : Number> Number.narrow(): R
@Intrinsic external fun <R : Any> Byte.convert(): R
@Intrinsic external fun <R : Any> Short.convert(): R
@Intrinsic external fun <R : Any> Int.convert(): R
@Intrinsic external fun <R : Any> Long.convert(): R
@Intrinsic external fun <R : Any> UByte.convert(): R
@Intrinsic external fun <R : Any> UShort.convert(): R
@Intrinsic external fun <R : Any> UInt.convert(): R
@Intrinsic external fun <R : Any> ULong.convert(): R
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.FILE)
@Retention(AnnotationRetention.SOURCE)
internal annotation class JvmName(val name: String)
@@ -56,6 +56,19 @@ fun IntArray.refTo(index: Int): CValuesRef<IntVar> = this.usingPinned { addressO
fun Pinned<LongArray>.addressOf(index: Int): CPointer<LongVar> = this.addressOfElement(index)
fun LongArray.refTo(index: Int): CValuesRef<LongVar> = this.usingPinned { addressOf(index) }
// TODO: pinning of unsigned arrays involves boxing as they are inline classes wrapping signed arrays.
fun Pinned<UByteArray>.addressOf(index: Int): CPointer<UByteVar> = this.get().addressOfElement(index)
fun UByteArray.refTo(index: Int): CValuesRef<UByteVar> = this.usingPinned { addressOf(index) }
fun Pinned<UShortArray>.addressOf(index: Int): CPointer<UShortVar> = this.get().addressOfElement(index)
fun UShortArray.refTo(index: Int): CValuesRef<UShortVar> = this.usingPinned { addressOf(index) }
fun Pinned<UIntArray>.addressOf(index: Int): CPointer<UIntVar> = this.get().addressOfElement(index)
fun UIntArray.refTo(index: Int): CValuesRef<UIntVar> = this.usingPinned { addressOf(index) }
fun Pinned<ULongArray>.addressOf(index: Int): CPointer<ULongVar> = this.get().addressOfElement(index)
fun ULongArray.refTo(index: Int): CValuesRef<ULongVar> = this.usingPinned { addressOf(index) }
fun Pinned<FloatArray>.addressOf(index: Int): CPointer<FloatVar> = this.addressOfElement(index)
fun FloatArray.refTo(index: Int): CValuesRef<FloatVar> = this.usingPinned { addressOf(index) }
@@ -79,3 +92,15 @@ private external fun getAddressOfElement(array: Any, index: Int): COpaquePointer
@Suppress("NOTHING_TO_INLINE")
private inline fun <P : CVariable> Pinned<*>.addressOfElement(index: Int): CPointer<P> =
getAddressOfElement(this.get(), index).reinterpret()
@SymbolName("Kotlin_Arrays_getAddressOfElement")
private external fun UByteArray.addressOfElement(index: Int): CPointer<UByteVar>
@SymbolName("Kotlin_Arrays_getAddressOfElement")
private external fun UShortArray.addressOfElement(index: Int): CPointer<UShortVar>
@SymbolName("Kotlin_Arrays_getAddressOfElement")
private external fun UIntArray.addressOfElement(index: Int): CPointer<UIntVar>
@SymbolName("Kotlin_Arrays_getAddressOfElement")
private external fun ULongArray.addressOfElement(index: Int): CPointer<ULongVar>
@@ -30,11 +30,15 @@ const val FFI_TYPE_KIND_SINT64: FfiTypeKind = 4
const val FFI_TYPE_KIND_FLOAT: FfiTypeKind = 5
const val FFI_TYPE_KIND_DOUBLE: FfiTypeKind = 6
const val FFI_TYPE_KIND_POINTER: FfiTypeKind = 7
const val FFI_TYPE_KIND_UINT8: FfiTypeKind = 8
const val FFI_TYPE_KIND_UINT16: FfiTypeKind = 9
const val FFI_TYPE_KIND_UINT32: FfiTypeKind = 10
const val FFI_TYPE_KIND_UINT64: FfiTypeKind = 11
private tailrec fun convertArgument(
argument: Any?, isVariadic: Boolean, location: COpaquePointer,
additionalPlacement: AutofreeScope
): FfiTypeKind = when (argument) {
): FfiTypeKind = when (argument) { // FIXME: optimize
is CValuesRef<*>? -> {
location.reinterpret<CPointerVar<*>>()[0] = argument?.getPointer(additionalPlacement)
FFI_TYPE_KIND_POINTER
@@ -79,6 +83,30 @@ private tailrec fun convertArgument(
FFI_TYPE_KIND_SINT16
}
is UInt -> {
location.reinterpret<UIntVar>()[0] = argument
FFI_TYPE_KIND_UINT32
}
is ULong -> {
location.reinterpret<ULongVar>()[0] = argument
FFI_TYPE_KIND_UINT64
}
is UByte -> if (isVariadic) {
convertArgument(argument.toUInt(), isVariadic, location, additionalPlacement)
} else {
location.reinterpret<UByteVar>()[0] = argument
FFI_TYPE_KIND_UINT8
}
is UShort -> if (isVariadic) {
convertArgument(argument.toUInt(), isVariadic, location, additionalPlacement)
} else {
location.reinterpret<UShortVar>()[0] = argument
FFI_TYPE_KIND_UINT16
}
is Double -> {
location.reinterpret<DoubleVar>()[0] = argument
FFI_TYPE_KIND_DOUBLE
@@ -162,6 +162,10 @@ object KotlinTypes {
val short by BuiltInType
val int by BuiltInType
val long by BuiltInType
val uByte by BuiltInType
val uShort by BuiltInType
val uInt by BuiltInType
val uLong by BuiltInType
val float by BuiltInType
val double by BuiltInType
val unit by BuiltInType
@@ -23,8 +23,12 @@ interface DeclarationMapper {
fun isMappedToStrict(enumDef: EnumDef): Boolean
fun getKotlinNameForValue(enumDef: EnumDef): String
fun getPackageFor(declaration: TypeDeclaration): String
val useUnsignedTypes: Boolean
}
fun DeclarationMapper.isMappedToSigned(integerType: IntegerType): Boolean = integerType.isSigned || !useUnsignedTypes
fun DeclarationMapper.getKotlinClassFor(
objCClassOrProtocol: ObjCClassOrProtocol,
isMeta: Boolean = false
@@ -41,38 +45,46 @@ fun DeclarationMapper.getKotlinClassFor(
return Classifier.topLevel(pkg, className)
}
val PrimitiveType.kotlinType: KotlinClassifierType
get() = when (this) {
is CharType -> KotlinTypes.byte
fun PrimitiveType.getKotlinType(declarationMapper: DeclarationMapper): KotlinClassifierType = when (this) {
is CharType -> KotlinTypes.byte
is BoolType -> KotlinTypes.boolean
is BoolType -> KotlinTypes.boolean
// TODO: C primitive types should probably be generated as type aliases for Kotlin types.
is IntegerType -> when (this.size) {
// TODO: C primitive types should probably be generated as type aliases for Kotlin types.
is IntegerType -> if (declarationMapper.isMappedToSigned(this)) {
when (this.size) {
1 -> KotlinTypes.byte
2 -> KotlinTypes.short
4 -> KotlinTypes.int
8 -> KotlinTypes.long
else -> TODO(this.toString())
}
is FloatingType -> when (this.size) {
4 -> KotlinTypes.float
8 -> KotlinTypes.double
} else {
when (this.size) {
1 -> KotlinTypes.uByte
2 -> KotlinTypes.uShort
4 -> KotlinTypes.uInt
8 -> KotlinTypes.uLong
else -> TODO(this.toString())
}
else -> throw NotImplementedError()
}
private val PrimitiveType.bridgedType: BridgedType
get() {
val kotlinType = this.kotlinType
return BridgedType.values().single {
it.kotlinType == kotlinType
}
is FloatingType -> when (this.size) {
4 -> KotlinTypes.float
8 -> KotlinTypes.double
else -> TODO(this.toString())
}
else -> throw NotImplementedError()
}
private fun PrimitiveType.getBridgedType(declarationMapper: DeclarationMapper): BridgedType {
val kotlinType = this.getKotlinType(declarationMapper)
return BridgedType.values().single {
it.kotlinType == kotlinType
}
}
internal val ObjCPointer.isNullable: Boolean
get() = this.nullability != ObjCPointer.Nullability.NonNull
@@ -334,16 +346,26 @@ sealed class TypeInfo {
}
}
fun mirrorPrimitiveType(type: PrimitiveType): TypeMirror.ByValue {
fun mirrorPrimitiveType(type: PrimitiveType, declarationMapper: DeclarationMapper): TypeMirror.ByValue {
val varClassName = when (type) {
is CharType -> "ByteVar"
is BoolType -> "BooleanVar"
is IntegerType -> when (type.size) {
1 -> "ByteVar"
2 -> "ShortVar"
4 -> "IntVar"
8 -> "LongVar"
else -> TODO(type.toString())
is IntegerType -> if (declarationMapper.isMappedToSigned(type)) {
when (type.size) {
1 -> "ByteVar"
2 -> "ShortVar"
4 -> "IntVar"
8 -> "LongVar"
else -> TODO(type.toString())
}
} else {
when (type.size) {
1 -> "UByteVar"
2 -> "UShortVar"
4 -> "UIntVar"
8 -> "ULongVar"
else -> TODO(type.toString())
}
}
is FloatingType -> when (type.size) {
4 -> "FloatVar"
@@ -359,9 +381,9 @@ fun mirrorPrimitiveType(type: PrimitiveType): TypeMirror.ByValue {
val info = if (type == BoolType) {
TypeInfo.Boolean()
} else {
TypeInfo.Primitive(type.bridgedType, varClassOf)
TypeInfo.Primitive(type.getBridgedType(declarationMapper), varClassOf)
}
return TypeMirror.ByValue(varClass.type, info, type.kotlinType)
return TypeMirror.ByValue(varClass.type, info, type.getKotlinType(declarationMapper))
}
private fun byRefTypeMirror(pointedType: KotlinClassifierType) : TypeMirror.ByRef {
@@ -370,7 +392,7 @@ private fun byRefTypeMirror(pointedType: KotlinClassifierType) : TypeMirror.ByRe
}
fun mirror(declarationMapper: DeclarationMapper, type: Type): TypeMirror = when (type) {
is PrimitiveType -> mirrorPrimitiveType(type)
is PrimitiveType -> mirrorPrimitiveType(type, declarationMapper)
is RecordType -> byRefTypeMirror(declarationMapper.getKotlinClassForPointed(type.decl).type)
@@ -380,7 +402,7 @@ fun mirror(declarationMapper: DeclarationMapper, type: Type): TypeMirror = when
when {
declarationMapper.isMappedToStrict(type.def) -> {
val bridgedType = (type.def.baseType.unwrapTypedefs() as PrimitiveType).bridgedType
val bridgedType = (type.def.baseType.unwrapTypedefs() as PrimitiveType).getBridgedType(declarationMapper)
val clazz = Classifier.topLevel(pkg, kotlinName)
val info = TypeInfo.Enum(clazz, bridgedType)
TypeMirror.ByValue(clazz.nested("Var").type, info, clazz.type)
@@ -24,6 +24,10 @@ enum class BridgedType(val kotlinType: KotlinClassifierType, val convertor: Stri
SHORT(KotlinTypes.short, "toShort"),
INT(KotlinTypes.int, "toInt"),
LONG(KotlinTypes.long, "toLong"),
UBYTE(KotlinTypes.uByte, "toUByte"),
USHORT(KotlinTypes.uShort, "toUShort"),
UINT(KotlinTypes.uInt, "toUInt"),
ULONG(KotlinTypes.uLong, "toULong"),
FLOAT(KotlinTypes.float, "toFloat"),
DOUBLE(KotlinTypes.double, "toDouble"),
NATIVE_PTR(KotlinTypes.nativePtr),
@@ -38,6 +38,10 @@ class SimpleBridgeGeneratorImpl(
BridgedType.SHORT -> "jshort"
BridgedType.INT -> "jint"
BridgedType.LONG -> "jlong"
BridgedType.UBYTE -> "jbyte"
BridgedType.USHORT -> "jshort"
BridgedType.UINT -> "jint"
BridgedType.ULONG -> "jlong"
BridgedType.FLOAT -> "jfloat"
BridgedType.DOUBLE -> "jdouble"
BridgedType.NATIVE_PTR -> "jlong"
@@ -49,6 +53,10 @@ class SimpleBridgeGeneratorImpl(
BridgedType.SHORT -> "int16_t"
BridgedType.INT -> "int32_t"
BridgedType.LONG -> "int64_t"
BridgedType.UBYTE -> "uint8_t"
BridgedType.USHORT -> "uint16_t"
BridgedType.UINT -> "uint32_t"
BridgedType.ULONG -> "uint64_t"
BridgedType.FLOAT -> "float"
BridgedType.DOUBLE -> "double"
BridgedType.NATIVE_PTR -> "void*"
@@ -156,6 +156,12 @@ class StubGenerator(
override fun getPackageFor(declaration: TypeDeclaration): String {
return imports.getPackage(declaration.location) ?: pkgName
}
override val useUnsignedTypes: Boolean
get() = when (platform) {
KotlinPlatform.JVM -> false
KotlinPlatform.NATIVE -> true
}
}
fun mirror(type: Type): TypeMirror = mirror(declarationMapper, type)
@@ -472,7 +478,8 @@ class StubGenerator(
block("enum class ${kotlinFile.declare(clazz)}(override val value: $baseKotlinType) : CEnum") {
canonicalConstants.forEach {
out("${it.name.asSimpleName()}(${it.value}),")
val literal = integerLiteral(e.baseType, it.value)!!
out("${it.name.asSimpleName()}($literal),")
}
out(";")
out("")
@@ -720,20 +727,33 @@ class StubGenerator(
}
private fun integerLiteral(type: Type, value: Long): String? {
val integerType = type.unwrapTypedefs() as? IntegerType ?: return null
return integerLiteral(integerType.size, declarationMapper.isMappedToSigned(integerType), value)
}
private fun integerLiteral(size: Int, isSigned: Boolean, value: Long): String? {
if (!isSigned) {
val signedLiteral = integerLiteral(size, true, value)
val converter = when (size) {
1 -> "toUByte"
2 -> "toUShort"
4 -> "toUInt"
8 -> "toULong"
else -> return null
}
return "($signedLiteral).$converter()"
}
if (value == Long.MIN_VALUE) {
return "${value + 1} - 1" // Workaround for "The value is out of range" compile error.
}
val unwrappedType = type.unwrapTypedefs()
if (unwrappedType !is PrimitiveType) {
return null
}
val narrowedValue: Number = when (unwrappedType.kotlinType) {
KotlinTypes.byte -> value.toByte()
KotlinTypes.short -> value.toShort()
KotlinTypes.int -> value.toInt()
KotlinTypes.long -> value
val narrowedValue: Number = when (size) {
1 -> value.toByte()
2 -> value.toShort()
4 -> value.toInt()
8 -> value
else -> return null
}
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.cli.bc
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.Argument
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.AnalysisFlag
class K2NativeCompilerArguments : CommonCompilerArguments() {
// First go the options interesting to the general public.
@@ -147,5 +149,11 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
description = "Paths to friend modules"
)
var friendModules: String? = null
override fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> =
super.configureAnalysisFlags(collector).also {
val useExperimental = it[AnalysisFlag.useExperimental] as List<*>
it[AnalysisFlag.useExperimental] = useExperimental + listOf("kotlin.ExperimentalUnsignedTypes")
}
}
@@ -16,8 +16,10 @@
package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.descriptors.konan.interop.InteropFqNames
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.FqName
@@ -90,6 +92,8 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns, vararg konanPrimitives:
val narrow = packageScope.getContributedFunctions("narrow").single()
val convert = packageScope.getContributedFunctions("convert").toSet()
val readBits = packageScope.getContributedFunctions("readBits").single()
val writeBits = packageScope.getContributedFunctions("writeBits").single()
@@ -101,6 +105,9 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns, vararg konanPrimitives:
TypeUtils.getClassDescriptor(extensionReceiverParameter.type) == cPointer
}.toSet()
private fun KonanBuiltIns.getUnsignedClass(unsignedType: UnsignedType): ClassDescriptor =
this.builtInsModule.findClassAcrossModuleDependencies(unsignedType.classId)!!
val invokeImpls = mapOf(
builtIns.unit to "invokeImplUnitRet",
builtIns.boolean to "invokeImplBooleanRet",
@@ -108,6 +115,10 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns, vararg konanPrimitives:
builtIns.short to "invokeImplShortRet",
builtIns.int to "invokeImplIntRet",
builtIns.long to "invokeImplLongRet",
builtIns.getUnsignedClass(UnsignedType.UBYTE) to "invokeImplUByteRet",
builtIns.getUnsignedClass(UnsignedType.USHORT) to "invokeImplUShortRet",
builtIns.getUnsignedClass(UnsignedType.UINT) to "invokeImplUIntRet",
builtIns.getUnsignedClass(UnsignedType.ULONG) to "invokeImplULongRet",
builtIns.float to "invokeImplFloatRet",
builtIns.double to "invokeImplDoubleRet",
cPointer to "invokeImplPointerRet"
@@ -144,6 +144,35 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val
val uInt = unsignedClass(UnsignedType.UINT)
val uLong = unsignedClass(UnsignedType.ULONG)
val signedIntegerClasses = setOf(byte, short, int, long)
val unsignedIntegerClasses = setOf(uByte, uShort, uInt, uLong)
val allIntegerClasses = signedIntegerClasses + unsignedIntegerClasses
val integerConversions = allIntegerClasses.flatMap { fromClass ->
allIntegerClasses.map { toClass ->
val name = Name.identifier("to${toClass.descriptor.name.asString().capitalize()}")
val descriptor = if (fromClass in signedIntegerClasses && toClass in unsignedIntegerClasses) {
builtInsPackage("kotlin")
.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND)
.single {
it.dispatchReceiverParameter == null &&
it.extensionReceiverParameter?.type == fromClass.descriptor.defaultType &&
it.valueParameters.isEmpty()
}
} else {
fromClass.descriptor.unsubstitutedMemberScope
.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND)
.single {
it.extensionReceiverParameter == null && it.valueParameters.isEmpty()
}
}
val symbol = symbolTable.referenceSimpleFunction(descriptor)
(fromClass to toClass) to symbol
}
}.toMap()
val arrayList = symbolTable.referenceClass(getArrayListClassDescriptor(context))
val interopNativePointedGetRawPointer =
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.allOverriddenDescriptors
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.builtins.UnsignedTypes
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -901,6 +902,35 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
}
}
in interop.convert -> {
val integerClasses = symbols.allIntegerClasses
val typeOperand = expression.getTypeArgument(0)!!
val receiverType = expression.symbol.owner.extensionReceiverParameter!!.type
val receiverClass = receiverType.classifierOrFail as IrClassSymbol
assert(receiverClass in integerClasses)
if (typeOperand is IrSimpleType && typeOperand.classifier in integerClasses && !typeOperand.hasQuestionMark) {
val typeOperandClass = typeOperand.classifier as IrClassSymbol
val conversion = symbols.integerConversions[receiverClass to typeOperandClass]!!.owner
builder.irCall(conversion).apply {
val valueToConvert = expression.extensionReceiver!!
if (conversion.dispatchReceiverParameter != null) {
dispatchReceiver = valueToConvert
} else {
extensionReceiver = valueToConvert
}
}
} else {
context.reportCompilationError(
"unable to convert ${receiverType.toKotlinType()} to ${typeOperand.toKotlinType()}",
irFile,
expression
)
}
}
in interop.cFunctionPointerInvokes -> {
// Replace by `invokeImpl${type}Ret`:
@@ -968,6 +998,10 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
return
}
if (UnsignedTypes.isUnsignedType(this.toKotlinType()) && !this.containsNull()) {
return
}
if (this.getClass()?.descriptor == interop.cPointer) {
return
}
@@ -976,7 +1010,7 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
}
private fun IrType.checkCTypeNullability(reportError: (String) -> Nothing) {
if (this.isNullablePrimitiveType()) {
if (this.isNullablePrimitiveType() || UnsignedTypes.isUnsignedType(this.toKotlinType()) && this.containsNull()) {
reportError("Type ${this.toKotlinType()} must not be nullable when used in C function signature")
}
+1 -1
View File
@@ -4,7 +4,7 @@ fun main(args: Array<String>) {
val values = intArrayOf(14, 12, 9, 13, 8)
val count = values.size
cstdlib.qsort(values.refTo(0), count.toLong(), IntVar.size, staticCFunction { a, b ->
cstdlib.qsort(values.refTo(0), count.toULong(), IntVar.size.convert(), staticCFunction { a, b ->
val aValue = a!!.reinterpret<IntVar>()[0]
val bValue = b!!.reinterpret<IntVar>()[0]
+8 -8
View File
@@ -6,7 +6,7 @@ fun assertEquals(value1: Any?, value2: Any?) {
throw AssertionError("Expected $value1, got $value2")
}
fun check(s: S, x1: Long, x2: B2, x3: Short, x4: Int, x5: Int, x6: Long) {
fun check(s: S, x1: Long, x2: B2, x3: UShort, x4: UInt, x5: Int, x6: Long) {
assertEquals(x1, s.x1)
assertEquals(x1, getX1(s.ptr))
@@ -26,7 +26,7 @@ fun check(s: S, x1: Long, x2: B2, x3: Short, x4: Int, x5: Int, x6: Long) {
assertEquals(x6, getX6(s.ptr))
}
fun assign(s: S, x1: Long, x2: B2, x3: Short, x4: Int, x5: Int, x6: Long) {
fun assign(s: S, x1: Long, x2: B2, x3: UShort, x4: UInt, x5: Int, x6: Long) {
s.x1 = x1
s.x2 = x2
s.x3 = x3
@@ -35,7 +35,7 @@ fun assign(s: S, x1: Long, x2: B2, x3: Short, x4: Int, x5: Int, x6: Long) {
s.x6 = x6
}
fun assignReversed(s: S, x1: Long, x2: B2, x3: Short, x4: Int, x5: Int, x6: Long) {
fun assignReversed(s: S, x1: Long, x2: B2, x3: UShort, x4: UInt, x5: Int, x6: Long) {
s.x6 = x6
s.x5 = x5
s.x4 = x4
@@ -44,7 +44,7 @@ fun assignReversed(s: S, x1: Long, x2: B2, x3: Short, x4: Int, x5: Int, x6: Long
s.x1 = x1
}
fun test(s: S, x1: Long, x2: B2, x3: Short, x4: Int, x5: Int, x6: Long) {
fun test(s: S, x1: Long, x2: B2, x3: UShort, x4: UInt, x5: Int, x6: Long) {
assign(s, x1, x2, x3, x4, x5, x6)
check(s, x1, x2, x3, x4, x5, x6)
@@ -53,10 +53,10 @@ fun test(s: S, x1: Long, x2: B2, x3: Short, x4: Int, x5: Int, x6: Long) {
// Also check with some insignificant bits modified:
assign(s, x1 + 2, x2, (x3 + 8).toShort(), x4 - 16, x5 + 32, x6 + Long.MIN_VALUE)
assign(s, x1 + 2, x2, (x3 + 8u).toUShort(), x4 - 16u, x5 + 32, x6 + Long.MIN_VALUE)
check(s, x1, x2, x3, x4, x5, x6)
assignReversed(s, x1 + 2, x2, (x3 + 8).toShort(), x4 - 16, x5 + 32, x6 + Long.MIN_VALUE)
assignReversed(s, x1 + 2, x2, (x3 + 8u).toUShort(), x4 - 16u, x5 + 32, x6 + Long.MIN_VALUE)
check(s, x1, x2, x3, x4, x5, x6)
}
@@ -66,9 +66,9 @@ fun main(args: Array<String>) {
for (x1 in -1L..0L)
for (x2 in B2.values())
for (x3 in 0..7)
for (x4 in intArrayOf(0, 6, 15))
for (x4 in uintArrayOf(0u, 6u, 15u))
for (x5 in intArrayOf(-16, -2, -1, 0, 5, 15))
for (x6 in longArrayOf(Long.MIN_VALUE/2, -1L shl 36, -325L, 0, 1L shl 48, Long.MAX_VALUE/2))
test(s, x1, x2, x3.toShort(), x4, x5, x6)
test(s, x1, x2, x3.toUShort(), x4, x5, x6)
}
}
@@ -51,4 +51,12 @@ typedef _Bool (*isIntPositivePtrType)(int);
static isIntPositivePtrType getIsIntPositivePtr() {
return &__isIntPositive;
}
static unsigned int getMaxUInt(void) {
return 0xffffffff;
}
static typeof(&getMaxUInt) getMaxUIntGetter() {
return &getMaxUInt;
}
@@ -7,7 +7,7 @@ fun main(args: Array<String>) {
return
}
val port = atoi(args[0]).toShort()
val port = atoi(args[0]).toUShort()
memScoped {
@@ -19,13 +19,13 @@ fun main(args: Array<String>) {
.ensureUnixCallResult { it >= 0 }
with(serverAddr) {
memset(this.ptr, 0, sockaddr_in.size)
sin_family = AF_INET.narrow()
sin_addr.s_addr = htons(0).toInt()
memset(this.ptr, 0, sockaddr_in.size.convert())
sin_family = AF_INET.convert()
sin_addr.s_addr = htons(0u).convert()
sin_port = htons(port)
}
bind(listenFd, serverAddr.ptr.reinterpret(), sockaddr_in.size.toInt())
bind(listenFd, serverAddr.ptr.reinterpret(), sockaddr_in.size.toUInt())
.ensureUnixCallResult { it == 0 }
listen(listenFd, 10)
@@ -35,21 +35,21 @@ fun main(args: Array<String>) {
.ensureUnixCallResult { it >= 0 }
while (true) {
val length = read(commFd, buffer, bufferLength)
val length = read(commFd, buffer, bufferLength.convert())
.ensureUnixCallResult { it >= 0 }
if (length == 0L) {
break
}
write(commFd, buffer, length)
write(commFd, buffer, length.convert())
.ensureUnixCallResult { it >= 0 }
}
}
}
// Not available through interop because declared as macro:
fun htons(value: Short) = ((value.toInt() ushr 8) or (value.toInt() shl 8)).toShort()
fun htons(value: UShort) = ((value.toInt() ushr 8) or (value.toInt() shl 8)).toUShort()
fun throwUnixError(): Nothing {
perror(null) // TODO: store error message to exception instead.
@@ -1,5 +1,6 @@
import kotlinx.cinterop.*
import cfunptr.*
import kotlin.test.*
fun main(args: Array<String>) {
val atoiPtr = getAtoiPtr()!!
@@ -23,6 +24,8 @@ fun main(args: Array<String>) {
printIntPtr(isIntPositivePtr(42).ifThenOneElseZero())
printIntPtr(isIntPositivePtr(-42).ifThenOneElseZero())
assertEquals(getMaxUIntGetter()!!(), UInt.MAX_VALUE)
}
fun Boolean.ifThenOneElseZero() = if (this) 1 else 0
@@ -13,7 +13,7 @@ private val windowHeight = 480
fun display() {
// Clear Screen and Depth Buffer
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
glClear((GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT).convert())
glLoadIdentity()
// Define a viewing transformation
@@ -40,13 +40,13 @@ fun display() {
fun initialize() {
// select projection matrix
glMatrixMode(GL_PROJECTION)
glMatrixMode(GL_PROJECTION.convert())
// set the viewport
glViewport(0, 0, windowWidth, windowHeight)
// set matrix mode
glMatrixMode(GL_PROJECTION)
glMatrixMode(GL_PROJECTION.convert())
// reset projection matrix
glLoadIdentity()
@@ -56,29 +56,29 @@ fun initialize() {
gluPerspective(45.0, aspect, 1.0, 500.0)
// specify which matrix is the current matrix
glMatrixMode(GL_MODELVIEW)
glShadeModel(GL_SMOOTH)
glMatrixMode(GL_MODELVIEW.convert())
glShadeModel(GL_SMOOTH.convert())
// specify the clear value for the depth buffer
glClearDepth(1.0)
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LEQUAL)
glEnable(GL_DEPTH_TEST.convert())
glDepthFunc(GL_LEQUAL.convert())
// specify implementation-specific hints
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
glHint(GL_PERSPECTIVE_CORRECTION_HINT.convert(), GL_NICEST.convert())
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, cValuesOf(0.1f, 0.1f, 0.1f, 1.0f))
glLightfv(GL_LIGHT0, GL_DIFFUSE, cValuesOf(0.6f, 0.6f, 0.6f, 1.0f))
glLightfv(GL_LIGHT0, GL_SPECULAR, cValuesOf(0.7f, 0.7f, 0.3f, 1.0f))
glLightModelfv(GL_LIGHT_MODEL_AMBIENT.convert(), cValuesOf(0.1f, 0.1f, 0.1f, 1.0f))
glLightfv(GL_LIGHT0.convert(), GL_DIFFUSE.convert(), cValuesOf(0.6f, 0.6f, 0.6f, 1.0f))
glLightfv(GL_LIGHT0.convert(), GL_SPECULAR.convert(), cValuesOf(0.7f, 0.7f, 0.3f, 1.0f))
glEnable(GL_LIGHT0)
glEnable(GL_COLOR_MATERIAL)
glShadeModel(GL_SMOOTH)
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE)
glDepthFunc(GL_LEQUAL)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_LIGHT0.convert())
glEnable(GL_COLOR_MATERIAL.convert())
glShadeModel(GL_SMOOTH.convert())
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE.convert(), GL_FALSE)
glDepthFunc(GL_LEQUAL.convert())
glEnable(GL_DEPTH_TEST.convert())
glEnable(GL_LIGHTING.convert())
glEnable(GL_LIGHT0.convert())
glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
}
@@ -90,7 +90,7 @@ fun main(args: Array<String>) {
}
// Display Mode
glutInitDisplayMode(GLUT_RGB or GLUT_DOUBLE or GLUT_DEPTH)
glutInitDisplayMode((GLUT_RGB or GLUT_DOUBLE or GLUT_DEPTH).convert())
// Set window size
glutInitWindowSize(windowWidth, windowHeight)
+2 -2
View File
@@ -22,8 +22,8 @@ fun main(args: Array<String>) {
val destPtr = alloc<CArrayPointerVar<ByteVar>>()
destPtr.value = destBytes
sourceLength.value = sourceByteArray.size.signExtend();
destLength.value = golden.size.signExtend();
sourceLength.value = sourceByteArray.size.convert()
destLength.value = golden.size.convert()
val conversion = iconv_open("UTF-8", "LATIN1")
+3 -3
View File
@@ -118,9 +118,9 @@ fun testTypeOps() {
assertTrue(NSValue.asAny() is NSObjectProtocolMeta)
assertFalse(NSValue.asAny() is NSObjectProtocol) // Must be true, but not implemented properly yet.
assertEquals(3, ("foo" as NSString).length())
assertEquals(4, ((1..4).joinToString("") as NSString).length())
assertEquals(2, (listOf(0, 1) as NSArray).count())
assertEquals(3u, ("foo" as NSString).length())
assertEquals(4u, ((1..4).joinToString("") as NSString).length())
assertEquals(2u, (listOf(0, 1) as NSArray).count())
assertEquals(42L, (42 as NSNumber).longLongValue())
assertFails { "bar" as NSNumber }
@@ -2,7 +2,7 @@ import kotlinx.cinterop.*
import platform.zlib.*
val source = immutableBlobOf(0xF3, 0x48, 0xCD, 0xC9, 0xC9, 0x57, 0x04, 0x00).asCPointer()
val source = immutableBlobOf(0xF3, 0x48, 0xCD, 0xC9, 0xC9, 0x57, 0x04, 0x00).asCPointer().reinterpret<UByteVar>()
val golden = immutableBlobOf(0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x21, 0x00).asCPointer()
fun main(args: Array<String>) = memScoped {
@@ -10,9 +10,9 @@ fun main(args: Array<String>) = memScoped {
buffer.usePinned { pinned ->
val z = alloc<z_stream>().apply {
next_in = source
avail_in = 8
next_out = pinned.addressOf(0)
avail_out = buffer.size
avail_in = 8u
next_out = pinned.addressOf(0).reinterpret()
avail_out = buffer.size.toUInt()
}.ptr
if (inflateInit2(z, -15) == Z_OK && inflate(z, Z_FINISH) == Z_STREAM_END && inflateEnd(z) == Z_OK)
+2 -2
View File
@@ -1,8 +1,8 @@
import kotlinx.cinterop.signExtend
import kotlinx.cinterop.convert
import platform.posix.*
fun main(args: Array<String>) {
// Just check the typealias is in scope.
val sizet: size_t = 0.signExtend<size_t>()
val sizet: size_t = 0.convert<size_t>()
println("sizet = $sizet")
}
+2 -2
View File
@@ -1,9 +1,9 @@
import kotlinx.cinterop.signExtend
import kotlinx.cinterop.convert
import platform.posix.*
fun foo() {
println("linked library")
val size: size_t = 17.signExtend<size_t>()
val size: size_t = 17.convert<size_t>()
val e = fabs(1.toDouble())
println("and symbols from posix available: $size; $e")
}
+8
View File
@@ -40,6 +40,10 @@ const FfiTypeKind FFI_TYPE_KIND_SINT64 = 4;
const FfiTypeKind FFI_TYPE_KIND_FLOAT = 5;
const FfiTypeKind FFI_TYPE_KIND_DOUBLE = 6;
const FfiTypeKind FFI_TYPE_KIND_POINTER = 7;
const FfiTypeKind FFI_TYPE_KIND_UINT8 = 8;
const FfiTypeKind FFI_TYPE_KIND_UINT16 = 9;
const FfiTypeKind FFI_TYPE_KIND_UINT32 = 10;
const FfiTypeKind FFI_TYPE_KIND_UINT64 = 11;
ffi_type* convertFfiTypeKindToType(FfiTypeKind typeKind) {
switch (typeKind) {
@@ -51,6 +55,10 @@ ffi_type* convertFfiTypeKindToType(FfiTypeKind typeKind) {
case FFI_TYPE_KIND_FLOAT: return &ffi_type_float;
case FFI_TYPE_KIND_DOUBLE: return &ffi_type_double;
case FFI_TYPE_KIND_POINTER: return &ffi_type_pointer;
case FFI_TYPE_KIND_UINT8: return &ffi_type_uint8;
case FFI_TYPE_KIND_UINT16: return &ffi_type_uint16;
case FFI_TYPE_KIND_UINT32: return &ffi_type_uint32;
case FFI_TYPE_KIND_UINT64: return &ffi_type_uint64;
default: assert(false); return nullptr;
}
@@ -45,7 +45,7 @@ fun CPointer<ByteVar>.toKString(length: Int): String {
}
fun header_callback(buffer: CPointer<ByteVar>?, size: size_t, nitems: size_t, userdata: COpaquePointer?): size_t {
if (buffer == null) return 0
if (buffer == null) return 0u
if (userdata != null) {
val header = buffer.toKString((size * nitems).toInt()).trim()
val curl = userdata.asStableRef<CUrl>().get()
@@ -56,7 +56,7 @@ fun header_callback(buffer: CPointer<ByteVar>?, size: size_t, nitems: size_t, us
fun write_callback(buffer: CPointer<ByteVar>?, size: size_t, nitems: size_t, userdata: COpaquePointer?): size_t {
if (buffer == null) return 0
if (buffer == null) return 0u
if (userdata != null) {
val data = buffer.toKString((size * nitems).toInt()).trim()
val curl = userdata.asStableRef<CUrl>().get()
@@ -32,11 +32,11 @@ class GitCommit(val repository: GitRepository, val commit: CPointer<git_commit>)
}
val parents: List<GitCommit> get() = memScoped {
val count = git_commit_parentcount(commit)
val count = git_commit_parentcount(commit).toInt()
val result = ArrayList<GitCommit>(count)
for (index in 0..count - 1) {
val commitPtr = allocPointerTo<git_commit>()
git_commit_parent(commitPtr.ptr, commit, index).errorCheck()
git_commit_parent(commitPtr.ptr, commit, index.toUInt()).errorCheck()
result.add(GitCommit(repository, commitPtr.value!!))
}
result
@@ -21,10 +21,10 @@ import libgit2.*
class GitDiff(val repository: GitRepository, val handle: CPointer<git_diff>) {
fun deltas(): List<GifDiffDelta> {
val size = git_diff_num_deltas(handle)
val results = ArrayList<GifDiffDelta>(size.toInt())
val size = git_diff_num_deltas(handle).toInt()
val results = ArrayList<GifDiffDelta>(size)
for (index in 0..size - 1) {
val delta = git_diff_get_delta(handle, index)
val delta = git_diff_get_delta(handle, index.convert())
results.add(GifDiffDelta(this, delta!!))
}
return results
@@ -23,10 +23,10 @@ class GitTree(val repository: GitRepository, val handle: CPointer<git_tree>) {
fun close() = git_tree_free(handle)
fun entries(): List<GitTreeEntry> = memScoped {
val size = git_tree_entrycount(handle)
val entries = ArrayList<GitTreeEntry>(size.toInt())
val size = git_tree_entrycount(handle).toInt()
val entries = ArrayList<GitTreeEntry>(size)
for (index in 0..size - 1) {
val treeEntry = git_tree_entry_byindex(handle, index)!!
val treeEntry = git_tree_entry_byindex(handle, index.convert())!!
val entryType = git_tree_entry_type(treeEntry)
val entry = when (entryType) {
GIT_OBJ_TREE -> memScoped {
+1 -1
View File
@@ -19,7 +19,7 @@ import gtk3.*
// Note that all callback parameters must be primitive types or nullable C pointers.
fun <F : CFunction<*>> g_signal_connect(obj: CPointer<*>, actionName: String,
action: CPointer<F>, data: gpointer? = null, connect_flags: Int = 0) {
action: CPointer<F>, data: gpointer? = null, connect_flags: GConnectFlags = 0u) {
g_signal_connect_data(obj.reinterpret(), actionName, action.reinterpret(),
data = data, destroy_data = null, connect_flags = connect_flags)
@@ -32,16 +32,16 @@ fun main(args: Array<String>) {
val serverAddr = alloc<sockaddr_in>()
val listenFd = socket(AF_INET, SOCK_STREAM, 0)
.ensureUnixCallResult { it >= 0 }
.ensureUnixCallResult { !it.isMinusOne() }
with(serverAddr) {
memset(this.ptr, 0, sockaddr_in.size)
sin_family = AF_INET.narrow()
sin_addr.s_addr = posix_htons(0).toInt()
sin_port = posix_htons(port)
memset(this.ptr, 0, sockaddr_in.size.convert())
sin_family = AF_INET.convert()
sin_addr.s_addr = posix_htons(0).convert()
sin_port = posix_htons(port).convert()
}
bind(listenFd, serverAddr.ptr.reinterpret(), sockaddr_in.size.toInt())
bind(listenFd, serverAddr.ptr.reinterpret(), sockaddr_in.size.toUInt())
.ensureUnixCallResult { it == 0 }
fcntl(listenFd, F_SETFL, O_NONBLOCK)
@@ -53,8 +53,8 @@ fun main(args: Array<String>) {
var connectionId = 0
acceptClientsAndRun(listenFd) {
memScoped {
val bufferLength = 100L
val buffer = allocArray<ByteVar>(bufferLength)
val bufferLength = 100uL
val buffer = allocArray<ByteVar>(bufferLength.toLong())
val connectionIdString = "#${++connectionId}: ".cstr
val connectionIdBytes = connectionIdString.ptr
@@ -62,10 +62,10 @@ fun main(args: Array<String>) {
while (true) {
val length = read(buffer, bufferLength)
if (length == 0L)
if (length == 0uL)
break
write(connectionIdBytes, connectionIdString.size.toLong())
write(connectionIdBytes, connectionIdString.size.toULong())
write(buffer, length)
}
} catch (e: IOException) {
@@ -80,19 +80,19 @@ sealed class WaitingFor {
class Accept : WaitingFor()
class Read(val data: CArrayPointer<ByteVar>,
val length: Long,
val continuation: Continuation<Long>) : WaitingFor()
val length: ULong,
val continuation: Continuation<ULong>) : WaitingFor()
class Write(val data: CArrayPointer<ByteVar>,
val length: Long,
val length: ULong,
val continuation: Continuation<Unit>) : WaitingFor()
}
class Client(val clientFd: Int, val waitingList: MutableMap<Int, WaitingFor>) {
suspend fun read(data: CArrayPointer<ByteVar>, dataLength: Long): Long {
suspend fun read(data: CArrayPointer<ByteVar>, dataLength: ULong): ULong {
val length = read(clientFd, data, dataLength)
if (length >= 0)
return length
return length.toULong()
if (posix_errno() != EWOULDBLOCK)
throw IOException(getUnixError())
// Save continuation and suspend.
@@ -101,7 +101,7 @@ class Client(val clientFd: Int, val waitingList: MutableMap<Int, WaitingFor>) {
}
}
suspend fun write(data: CArrayPointer<ByteVar>, length: Long) {
suspend fun write(data: CArrayPointer<ByteVar>, length: ULong) {
val written = write(clientFd, data, length)
if (written >= 0)
return
@@ -153,7 +153,7 @@ fun acceptClientsAndRun(serverFd: Int, block: suspend Client.() -> Unit) {
// Accept new client.
val clientFd = accept(serverFd, null, null)
if (clientFd < 0) {
if (clientFd.isMinusOne()) {
if (posix_errno() != EWOULDBLOCK)
throw Error(getUnixError())
break@loop
@@ -173,7 +173,7 @@ fun acceptClientsAndRun(serverFd: Int, block: suspend Client.() -> Unit) {
val length = read(socketFd, waitingFor.data, waitingFor.length)
if (length < 0) // Read error.
waitingFor.continuation.resumeWithException(IOException(getUnixError()))
waitingFor.continuation.resume(length)
waitingFor.continuation.resume(length.toULong())
}
is WaitingFor.Write -> {
if (errorOccured)
@@ -210,3 +210,14 @@ inline fun Long.ensureUnixCallResult(predicate: (Long) -> Boolean): Long {
}
return this
}
inline fun ULong.ensureUnixCallResult(predicate: (ULong) -> Boolean): ULong {
if (!predicate(this)) {
throw Error(getUnixError())
}
return this
}
private fun Int.isMinusOne() = (this == -1)
private fun Long.isMinusOne() = (this == -1L)
private fun ULong.isMinusOne() = (this == ULong.MAX_VALUE)
+2 -2
View File
@@ -24,7 +24,7 @@ private fun runApp() {
app.run()
}
data class Data(val stamp: Long)
data class Data(val stamp: ULong)
private class Controller : NSObject() {
private val asyncQueue = dispatch_queue_create("com.jetbrains.CustomQueue", null)
@@ -33,7 +33,7 @@ private class Controller : NSObject() {
fun onClick() {
// Execute some async action on button click.
dispatch_async_f(asyncQueue, detachObjectGraph {
Data(clock_gettime_nsec_np(CLOCK_REALTIME))
Data(clock_gettime_nsec_np(CLOCK_REALTIME.convert()))
}, staticCFunction {
it ->
initRuntimeIfNeeded()
+20 -20
View File
@@ -29,7 +29,7 @@ private val windowHeight = 480
fun display() {
// Clear Screen and Depth Buffer
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
glClear((GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT).convert())
glLoadIdentity()
// Define a viewing transformation
@@ -56,13 +56,13 @@ fun display() {
fun initialize() {
// select projection matrix
glMatrixMode(GL_PROJECTION)
glMatrixMode(GL_PROJECTION.convert())
// set the viewport
glViewport(0, 0, windowWidth, windowHeight)
// set matrix mode
glMatrixMode(GL_PROJECTION)
glMatrixMode(GL_PROJECTION.convert())
// reset projection matrix
glLoadIdentity()
@@ -72,29 +72,29 @@ fun initialize() {
gluPerspective(45.0, aspect, 1.0, 500.0)
// specify which matrix is the current matrix
glMatrixMode(GL_MODELVIEW)
glShadeModel(GL_SMOOTH)
glMatrixMode(GL_MODELVIEW.convert())
glShadeModel(GL_SMOOTH.convert())
// specify the clear value for the depth buffer
glClearDepth(1.0)
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LEQUAL)
glEnable(GL_DEPTH_TEST.convert())
glDepthFunc(GL_LEQUAL.convert())
// specify implementation-specific hints
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
glHint(GL_PERSPECTIVE_CORRECTION_HINT.convert(), GL_NICEST.convert())
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, cValuesOf(0.1f, 0.1f, 0.1f, 1.0f))
glLightfv(GL_LIGHT0, GL_DIFFUSE, cValuesOf(0.6f, 0.6f, 0.6f, 1.0f))
glLightfv(GL_LIGHT0, GL_SPECULAR, cValuesOf(0.7f, 0.7f, 0.3f, 1.0f))
glLightModelfv(GL_LIGHT_MODEL_AMBIENT.convert(), cValuesOf(0.1f, 0.1f, 0.1f, 1.0f))
glLightfv(GL_LIGHT0.convert(), GL_DIFFUSE.convert(), cValuesOf(0.6f, 0.6f, 0.6f, 1.0f))
glLightfv(GL_LIGHT0.convert(), GL_SPECULAR.convert(), cValuesOf(0.7f, 0.7f, 0.3f, 1.0f))
glEnable(GL_LIGHT0)
glEnable(GL_COLOR_MATERIAL)
glShadeModel(GL_SMOOTH)
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE)
glDepthFunc(GL_LEQUAL)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_LIGHT0.convert())
glEnable(GL_COLOR_MATERIAL.convert())
glShadeModel(GL_SMOOTH.convert())
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE.convert(), GL_FALSE)
glDepthFunc(GL_LEQUAL.convert())
glEnable(GL_DEPTH_TEST.convert())
glEnable(GL_LIGHTING.convert())
glEnable(GL_LIGHT0.convert())
glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
}
@@ -106,7 +106,7 @@ fun main(args: Array<String>) {
}
// Display Mode
glutInitDisplayMode(GLUT_RGB or GLUT_DOUBLE or GLUT_DEPTH)
glutInitDisplayMode((GLUT_RGB or GLUT_DOUBLE or GLUT_DEPTH).convert())
// Set window size
glutInitWindowSize(windowWidth, windowHeight)
+20 -9
View File
@@ -35,35 +35,35 @@ fun main(args: Array<String>) {
val serverAddr = alloc<sockaddr_in>()
val listenFd = socket(AF_INET, SOCK_STREAM, 0)
.ensureUnixCallResult("socket") { it >= 0 }
.ensureUnixCallResult("socket") { !it.isMinusOne() }
with(serverAddr) {
memset(this.ptr, 0, sockaddr_in.size)
sin_family = AF_INET.narrow()
sin_port = posix_htons(port)
memset(this.ptr, 0, sockaddr_in.size.convert())
sin_family = AF_INET.convert()
sin_port = posix_htons(port).convert()
}
bind(listenFd, serverAddr.ptr.reinterpret(), sockaddr_in.size.toInt())
bind(listenFd, serverAddr.ptr.reinterpret(), sockaddr_in.size.convert())
.ensureUnixCallResult("bind") { it == 0 }
listen(listenFd, 10)
.ensureUnixCallResult("listen") { it == 0 }
val commFd = accept(listenFd, null, null)
.ensureUnixCallResult("accept") { it >= 0 }
.ensureUnixCallResult("accept") { !it.isMinusOne() }
buffer.usePinned { pinned ->
while (true) {
val length = recv(commFd, pinned.addressOf(0), buffer.size.signExtend(), 0).toInt()
val length = recv(commFd, pinned.addressOf(0), buffer.size.convert(), 0).toInt()
.ensureUnixCallResult("read") { it >= 0 }
if (length == 0) {
break
}
send(commFd, prefixBuffer.refTo(0), prefixBuffer.size.signExtend(), 0)
send(commFd, prefixBuffer.refTo(0), prefixBuffer.size.convert(), 0)
.ensureUnixCallResult("write") { it >= 0 }
send(commFd, pinned.addressOf(0), length.signExtend(), 0)
send(commFd, pinned.addressOf(0), length.convert(), 0)
.ensureUnixCallResult("write") { it >= 0 }
}
}
@@ -83,3 +83,14 @@ inline fun Long.ensureUnixCallResult(op: String, predicate: (Long) -> Boolean):
}
return this
}
inline fun ULong.ensureUnixCallResult(op: String, predicate: (ULong) -> Boolean): ULong {
if (!predicate(this)) {
throw Error("$op: ${strerror(posix_errno())!!.toKString()}")
}
return this
}
private fun Int.isMinusOne() = (this == -1)
private fun Long.isMinusOne() = (this == -1L)
private fun ULong.isMinusOne() = (this == ULong.MAX_VALUE)
@@ -1,4 +1,5 @@
import kotlinx.cinterop.*
import platform.posix.size_t
import tensorflow.*
typealias Status = CPointer<TF_Status>
@@ -31,13 +32,13 @@ fun scalarTensor(value: Int): Tensor {
return TF_NewTensor(TF_INT32,
dims = null, num_dims = 0,
data = data, len = IntVar.size,
data = data, len = IntVar.size.convert(),
deallocator = staticCFunction { dataToFree, _, _ -> nativeHeap.free(dataToFree!!.reinterpret<IntVar>()) },
deallocator_arg = null)!!
}
val Tensor.scalarIntValue: Int get() {
if (TF_INT32 != TF_TensorType(this) || IntVar.size != TF_TensorByteSize(this)) {
if (TF_INT32 != TF_TensorType(this) || IntVar.size.convert<size_t>() != TF_TensorByteSize(this)) {
throw Error("Tensor is not of type int.")
}
if (0 != TF_NumDims(this)) {
@@ -42,13 +42,13 @@ class AudioFrame(val buffer: CPointer<AVBufferRef>, var position: Int, val size:
private fun Int.checkAVError() {
if (this != 0) {
val buffer = ByteArray(1024)
av_strerror(this, buffer.refTo(0), buffer.size.signExtend())
av_strerror(this, buffer.refTo(0), buffer.size.convert())
throw Error("AVError: ${buffer.stringFromUtf8()}")
}
}
private val AVFormatContext.codecs: List<AVCodecContext?>
get() = List(nb_streams) { streams?.get(it)?.pointed?.codec?.pointed }
get() = List(nb_streams.toInt()) { streams?.get(it)?.pointed?.codec?.pointed }
private fun AVFormatContext.streamAt(index: Int): AVStream? =
if (index < 0) null else streams?.get(index)?.pointed
@@ -124,7 +124,7 @@ private class VideoDecoder(
dispose = ::sws_freeContext
)
private val scaledFrameSize = avpicture_get_size(avPixelFormat, windowSize.w, windowSize.h)
private val buffer: ByteArray = ByteArray(scaledFrameSize)
private val buffer: UByteArray = UByteArray(scaledFrameSize) { 0u }
private val videoQueue = Queue<VideoFrame>(100)
@@ -158,7 +158,7 @@ private class VideoDecoder(
val buffer = av_buffer_alloc(scaledFrameSize)!!
val ts = av_frame_get_best_effort_timestamp(videoFrame.ptr) *
av_q2d(videoCodecContext.time_base.readValue())
memcpy(buffer.pointed.data, scaledVideoFrame.data[0], scaledFrameSize.signExtend())
memcpy(buffer.pointed.data, scaledVideoFrame.data[0], scaledFrameSize.convert())
videoQueue.push(VideoFrame(buffer, scaledVideoFrame.linesize[0], ts))
}
}
@@ -204,11 +204,11 @@ private class AudioDecoder(
channels = output.channels
sample_rate = output.sampleRate
format = output.sampleFormat
channel_layout = output.channelLayout.signExtend()
channel_layout = output.channelLayout.convert()
}
with (audioCodecContext) {
setResampleOpt("in_channel_layout", channel_layout.narrow())
setResampleOpt("in_channel_layout", channel_layout.convert())
setResampleOpt("out_channel_layout", output.channelLayout)
setResampleOpt("in_sample_rate", sample_rate)
setResampleOpt("out_sample_rate", output.sampleRate)
@@ -255,7 +255,7 @@ private class AudioDecoder(
val buffer = av_buffer_alloc(audioFrameSize)!!
val ts = av_frame_get_best_effort_timestamp(audioFrame.ptr) *
av_q2d(audioCodecContext.time_base.readValue())
memcpy(buffer.pointed.data, data[0], audioFrameSize.signExtend())
memcpy(buffer.pointed.data, data[0], audioFrameSize.convert())
audioQueue.push(AudioFrame(buffer, 0, audioFrameSize, ts))
}
}
@@ -27,7 +27,7 @@ enum class SampleFormat {
data class AudioOutput(val sampleRate: Int, val channels: Int, val sampleFormat: SampleFormat)
private fun SampleFormat.toSDLFormat(): SDL_AudioFormat? = when (this) {
SampleFormat.S16 -> AUDIO_S16SYS.narrow()
SampleFormat.S16 -> AUDIO_S16SYS.convert()
SampleFormat.INVALID -> null
}
@@ -45,9 +45,9 @@ class SDLAudio(val player: VideoPlayer) : DisposableContainer() {
val spec = alloc<SDL_AudioSpec>().apply {
freq = audio.sampleRate
format = audioFormat
channels = audio.channels.narrow()
silence = 0
samples = 4096
channels = audio.channels.convert()
silence = 0u
samples = 4096u
userdata = threadData
callback = staticCFunction(::audioCallback)
}
@@ -89,12 +89,12 @@ private fun audioCallback(userdata: COpaquePointer?, buffer: CPointer<Uint8Var>?
val frame = decoder.nextAudioFrame(length - outPosition)
if (frame != null) {
val toCopy = minOf(length - outPosition, frame.size - frame.position)
memcpy(buffer + outPosition, frame.buffer.pointed.data + frame.position, toCopy.signExtend())
memcpy(buffer + outPosition, frame.buffer.pointed.data + frame.position, toCopy.convert())
frame.unref()
outPosition += toCopy
} else {
// println("Decoder returned nothing!")
memset(buffer + outPosition, 0, (length - outPosition).signExtend())
memset(buffer + outPosition, 0, (length - outPosition).convert())
break
}
}
@@ -81,7 +81,7 @@ class SDLRendererWindow(windowPos: Dimensions, videoSize: Dimensions) : Disposab
SDL_CreateTexture(renderer, SDL_GetWindowPixelFormat(window), 0, videoSize.w, videoSize.h),
::SDL_DestroyTexture)
private val rect = sdlDisposable("calloc(SDL_Rect)",
SDL_calloc(1, SDL_Rect.size), ::SDL_free)
SDL_calloc(1u, SDL_Rect.size.convert()), ::SDL_free)
.reinterpret<SDL_Rect>()
init {
@@ -71,7 +71,7 @@ class VideoPlayer(val requestedSize: Dimensions?) : DisposableContainer() {
}
private fun getTime(): Double {
clock_gettime(platform.posix.CLOCK_MONOTONIC, now)
clock_gettime(platform.posix.CLOCK_MONOTONIC.convert(), now)
return now.pointed.tv_sec + now.pointed.tv_nsec / 1e9
}
@@ -127,7 +127,7 @@ class VideoPlayer(val requestedSize: Dimensions?) : DisposableContainer() {
lastFrameTime += frameDuration // try to maintain perfect frame rate
// Wait for next frame, if needed
if (passedTime < frameDuration) {
usleep((1000_000 * (frameDuration - passedTime)).toInt())
usleep((1000_000 * (frameDuration - passedTime)).toInt().toUInt())
} else if (passedTime > frameDuration * 1.5){
lastFrameTime = now // we fell behind more than half frame, reset time
}
@@ -140,7 +140,7 @@ class VideoPlayer(val requestedSize: Dimensions?) : DisposableContainer() {
while (state == State.PAUSED) {
audio.pause()
input.check()
usleep(1 * 1000)
usleep(1u * 1000u)
}
audio.resume()
}
@@ -152,14 +152,14 @@ class VideoPlayer(val requestedSize: Dimensions?) : DisposableContainer() {
if (!decoder.audioVideoSynced()) {
println("Resynchronizing video with audio")
while (!decoder.audioVideoSynced() && state == State.PLAYING) {
usleep(500)
usleep(500u)
input.check()
}
}
}
} else {
// For pure sound, playback is driven by demand.
usleep(10 * 1000)
usleep(10u * 1000u)
}
}
}
+2 -1
View File
@@ -1,6 +1,7 @@
import kotlinx.cinterop.*
import platform.windows.*
fun main(args: Array<String>) {
MessageBoxW(null, "Konan говорит:\nЗДРАВСТВУЙ МИР!\n",
"Заголовок окна", MB_YESNOCANCEL or MB_ICONQUESTION)
"Заголовок окна", (MB_YESNOCANCEL or MB_ICONQUESTION).convert())
}