https://kotlinlang.org logo
#kotlin-native
Title
# kotlin-native
e

Edoardo Luppi

11/06/2023, 1:34 PM
Using:
Copy code
val array = allocArray<CHARVar>(size)
can I get the size of the array from the
array
itself? Or should I carry the
size
around?
m

mbonnin

11/06/2023, 1:36 PM
I'd say you have to carry
size
around. My mental model of
allocArray
is that it's just like C
malloc()
, all it returns is a pointer
e

Edoardo Luppi

11/06/2023, 1:37 PM
Yeah I guess so. Was looking at the code and it's really just an allocation of n * size of T
k

kevin.cianfarini

11/06/2023, 1:37 PM
Port the same C code that's used to get the size of arrays to K/N?
Copy code
int a[17];
size_t n = sizeof(a)/sizeof(a[0]);
e

Edoardo Luppi

11/06/2023, 1:39 PM
It probably works but at that point I'll just carry a
Pair
with the size.
m

mbonnin

11/06/2023, 1:39 PM
@kevin.cianfarini that's a compiler trick
I don't think the Kotlin compiler knows about
sizeof
?
That would leak internals about the packing of C structs and what not
Also
int a[17]
is not using
malloc()
e

Edoardo Luppi

11/06/2023, 1:40 PM
I'm not sure how
sizeOf
works in K/N honestly. Never bothered to investigate.
o

Oleg Yukhnevich

11/06/2023, 1:41 PM
There is
sizeOf<T: CVariable>()
there
m

mbonnin

11/06/2023, 1:41 PM
ooo so there's a
sizeof()
👀
👌 1
e

Edoardo Luppi

11/06/2023, 1:42 PM
I dream of the day C-interop will have KDocs
m

mbonnin

11/06/2023, 1:42 PM
Still,
allocArray()
is calling to
malloc()
under the hood, right? so the return value doesn't contain a size?
e

Edoardo Luppi

11/06/2023, 1:43 PM
This is the code, so yes
Copy code
alloc(sizeOf<T>() * length, alignOf<T>()).reinterpret<T>().ptr
m

mbonnin

11/06/2023, 1:44 PM
Kotlin might have its own
malloc()
that doesn't go through C-stdlib but looks like the semantics are the same and the size is not returned to the caller
o

Oleg Yukhnevich

11/06/2023, 1:44 PM
Yeah, that's true so the only way is to carry around size Because allocating array = allocating pointer in Kotlin - and pointer doesn't have size
👍 1
m

mbonnin

11/06/2023, 1:46 PM
To @kevin.cianfarini point, I guess there's no
sizeOf<Array<IntVar>(17)>()
because Kotlin doesn't carry size information in the type system itself
Like there's no way to tell: this variable is of type "Array of size exactly 17"
While it's somewhat possible in C (with the caveat that arrays are slighlty different from pointers and you can do all kinds of buffer overflow and alignement issues with them so... yay for Kotlin 😄 )
e

Edoardo Luppi

11/06/2023, 1:50 PM
In my case the easy solution is to stop thinking in C terms end embrace the Kotlin way, so from:
Copy code
internal fun LPWSTR.toLatin1Buffer(): Pair<Int, LPSTR> {
  val latin1BufferSize = WideCharToMultiByte(ISO_8859_1, 0u, this, 0, null, 0, null, null)
  val latin1buffer = allocArray<CHARVar>(latin1BufferSize)
  WideCharToMultiByte(ISO_8859_1, 0u, this, 0, latin1buffer, 0, null, null)
  return latin1BufferSize to latin1buffer
}
To:
Copy code
internal fun LPWSTR.toLatin1Buffer(): ByteArray {
  val latin1BufferSize = WideCharToMultiByte(ISO_8859_1, 0u, this, 0, null, 0, null, null)
  val latin1buffer = ByteArray(latin1BufferSize)
  latin1buffer.usePinned {
    WideCharToMultiByte(ISO_8859_1, 0u, this, 0, it.addressOf(0), 0, null, null)
  }
  return latin1buffer
}
👍 1
o

Oleg Yukhnevich

11/06/2023, 1:54 PM
If that's possible - yes, it's better to use Kotlin-way But sometimes, during interop with platform-specific APIs, it will force you to copy back and forth from foreign to Kotlin f.e. if you have an array of structs, not primitives
e

Edoardo Luppi

11/06/2023, 1:56 PM
It's also difficult to convert to the Kotlin way because you have to map platform typealiases to real Kotlin types. It's very tedious.
For example
allocArray<WCHARVar>(utf16BufferSize)
is
UShortArray(utf16BufferSize)
It's definitely not an immediate mapping.
nod 1
m

mbonnin

11/06/2023, 2:00 PM
This underlying issue is with C though, right? the fact that the same C type can have different sizes is 😒
Or maybe more of a preprocessor issue? (because Kotlin has (luckily) no preprocessor)
e

Edoardo Luppi

11/06/2023, 2:04 PM
This underlying issue is with C though
The real issue (at least in case of Windows) is the stupid hungarian notation and all the wide (W) type variants. Too many typealiases.
💯 1
m

mbonnin

11/06/2023, 2:04 PM
Ahahaha so many issues 😅
e

Edoardo Luppi

11/06/2023, 2:04 PM
I'm not sure how it's going on the Linux side because I do Windows mostly.
m

mbonnin

11/06/2023, 2:04 PM
Windows is tough...
sad panda 1
e

Edoardo Luppi

11/06/2023, 2:15 PM
In the end you can remove completely dealing with memory allocation. Value classes seem suited to represent this kind of abstraction.
Copy code
internal value class Utf16String(val buffer: UShortArray)
internal value class Latin1String(val buffer: ByteArray)

internal fun String.toUtf16String(): Utf16String {
  // Convert the Kotlin UTF-8 string into a UTF-16 buffer
  val utf16BufferSize = MultiByteToWideChar(UTF_8, 0u, this, -1, null, 0)
  val utf16Buffer = UShortArray(utf16BufferSize)
  utf16Buffer.usePinned {
    MultiByteToWideChar(UTF_8, 0u, this, -1, it.addressOf(0), 0)
  }

  return Utf16String(utf16Buffer)
}

internal fun Utf16String.toLatin1String(): Latin1String {
  buffer.usePinned { pinnedBuffer ->
    val bufferAddress = pinnedBuffer.addressOf(0)
    val latin1BufferSize = WideCharToMultiByte(ISO_8859_1, 0u, bufferAddress, 0, null, 0, null, null)
    val latin1Buffer = ByteArray(latin1BufferSize)
    latin1Buffer.usePinned {
      WideCharToMultiByte(ISO_8859_1, 0u, bufferAddress, 0, it.addressOf(0), 0, null, null)
    }

    return Latin1String(latin1Buffer)
  }
}
3 Views