Using: ```val array = allocArray<CHARVar>(si...
# kotlin-native
e
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
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
Yeah I guess so. Was looking at the code and it's really just an allocation of n * size of T
k
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
It probably works but at that point I'll just carry a
Pair
with the size.
m
@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
I'm not sure how
sizeOf
works in K/N honestly. Never bothered to investigate.
o
There is
sizeOf<T: CVariable>()
there
m
ooo so there's a
sizeof()
๐Ÿ‘€
๐Ÿ‘Œ 1
e
I dream of the day C-interop will have KDocs
m
Still,
allocArray()
is calling to
malloc()
under the hood, right? so the return value doesn't contain a size?
e
This is the code, so yes
Copy code
alloc(sizeOf<T>() * length, alignOf<T>()).reinterpret<T>().ptr
m
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
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
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
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
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
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
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
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
Ahahaha so many issues ๐Ÿ˜…
e
I'm not sure how it's going on the Linux side because I do Windows mostly.
m
Windows is tough...
sad panda 1
e
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)
  }
}