Skip to content

Commit

Permalink
Encapsulate native CPointer<FILE> and size_t types in wrapper (value)…
Browse files Browse the repository at this point in the history
… classes that deal with the pointer size differences.
  • Loading branch information
pdvrieze committed Jan 2, 2024
1 parent 7ae26ce commit b5b4ee3
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 86 deletions.
16 changes: 12 additions & 4 deletions buildSrc/src/main/kotlin/nativeTargets.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021.
* Copyright (c) 2024.
*
* This file is part of xmlutil.
*
Expand Down Expand Up @@ -30,7 +30,10 @@ import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.kpm.external.ExternalVariantApi
import org.jetbrains.kotlin.gradle.kpm.external.project
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.KotlinHierarchyTemplate
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree
import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeHostTest
import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeTest
import org.jetbrains.kotlin.konan.target.HostManager
Expand Down Expand Up @@ -122,9 +125,14 @@ fun Project.addNativeTargets() {
"all", "true" -> NativeState.ALL
"host" -> NativeState.HOST
"disabled" -> NativeState.DISABLED
else -> NativeState.SINGLE
"single" -> NativeState.SINGLE
else -> {
logger.lifecycle("set the native.deploy=[all|host|disabled|single] property to specify the native mode." +
"Defaulting to single")
NativeState.SINGLE
}
}
val singleTargetMode = ideaActive || nativeState == NativeState.SINGLE
val singleTargetMode = /*ideaActive || */nativeState == NativeState.SINGLE

val ext = extensions.getByName<ExtraPropertiesExtension>("ext")
val manager = HostManager()//ext["hostManager"] as HostManager
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023.
* Copyright (c) 2024.
*
* This file is part of xmlutil.
*
Expand Down Expand Up @@ -30,29 +30,29 @@ import platform.posix.*
* @constructor Directly wrap (and take ownership of) the file pointer given.
*/
@OptIn(ExperimentalForeignApi::class)
public class FileInputStream(public val filePtr: CPointer<FILE>) : InputStream() {
public class FileInputStream(public val filePtr: FilePtr) : InputStream() {

/**
* Create an input stream for a file handle. Will create the needed file pointer.
* @param fileHandle The file handle to use
* @param mode The mode to use to open the file.
*/
public constructor(fileHandle: Int, mode: FileMode = Mode.READ) : this(
fdopen(fileHandle, mode.modeString) ?: throw IOException.fromErrno())
FilePtr(fdopen(fileHandle, mode.modeString) ?: throw IOException.fromErrno()))

/**
* Create an input stream for a file name. Will create the needed file pointer.
* @param pathName The name of the file to open. If relative depends on the current working directory.
* @param mode The mode to use to open the file.
*/
public constructor(pathName: String, mode: FileMode = Mode.READ) : this(
fopen(pathName, mode.modeString) ?: throw IOException.fromErrno())
FilePtr(fopen(pathName, mode.modeString) ?: throw IOException.fromErrno()))

/**
* Close the file (neither this object is valid afterwards, nor the pointer.
*/
override fun close() {
if (fclose(filePtr) != 0) {
if (fclose(filePtr.value) != 0) {
throw IOException.fromErrno()
}
}
Expand All @@ -61,7 +61,7 @@ public class FileInputStream(public val filePtr: CPointer<FILE>) : InputStream()
* Determine whether the end of the file has been reached.
*/
public override val eof: Boolean
get() = feof(filePtr) != 0
get() = feof(filePtr.value) != 0

/**
* Read into the given native buffer. It will check for errors, but does not indicate end of file.
Expand All @@ -70,11 +70,13 @@ public class FileInputStream(public val filePtr: CPointer<FILE>) : InputStream()
* @param size The size of individual items (in bytes)
* @param bufferSize The maximum amount of items to be read.
*/
public override fun <T : CPointed> read(buffer: CArrayPointer<T>, size: MPSizeT, bufferSize: MPSizeT): MPSizeT {
clearerr(filePtr)
val itemsRead = MPSizeT(fread(buffer, size.value.convert<size_t>(), bufferSize.value.convert<size_t>(), filePtr))
if (itemsRead.value == 0uL) {
val error = ferror(filePtr)
@OptIn(UnsafeNumber::class)
public override fun <T : CPointed> read(buffer: CArrayPointer<T>, size: SizeT, bufferSize: SizeT): SizeT {
clearerr(filePtr.value)
val itemsRead = SizeT(
fread(buffer, size.value.convert<size_t>(), bufferSize.value.convert<size_t>(), filePtr.value))
if (itemsRead.toULong() == 0uL) {
val error = ferror(filePtr.value)
if (error != 0) {
throw IOException.fromErrno(error)
}
Expand All @@ -86,16 +88,17 @@ public class FileInputStream(public val filePtr: CPointer<FILE>) : InputStream()
* Read a single byte value. This is not buffered in any way, and possibly slow.
* @return -1 if end of file, otherwise the byte value
*/
@OptIn(UnsafeNumber::class)
public override fun read(): Int {
clearerr(filePtr)
clearerr(filePtr.value)
memScoped {
val bytePtr = alloc<UByteVar>()
val itemsRead: ULong = fread(bytePtr.ptr, 1u.convert(), 1u.convert(), filePtr).convert()
val itemsRead: ULong = fread(bytePtr.ptr, 1u.convert(), 1u.convert(), filePtr.value).convert()
if (itemsRead == 0uL) {
val error = ferror(filePtr)
val error = ferror(filePtr.value)
if (error != 0) {
throw IOException.fromErrno(error)
} else if (feof(filePtr) != 0) {
} else if (feof(filePtr.value) != 0) {
return -1
}
}
Expand All @@ -110,12 +113,13 @@ public class FileInputStream(public val filePtr: CPointer<FILE>) : InputStream()
* @param len The amount of data to read.
* @return The amount of bytes read or -1 if end of file.
*/
@OptIn(UnsafeNumber::class)
override fun read(buffer: ByteArray, offset: Int, len: Int): Int {
val endIdx = offset + len
require(offset in buffer.indices) { "Offset before start of array" }
require(endIdx <= buffer.size) { "Range size beyond buffer size" }
val result = buffer.usePinned { buf ->
read(buf.addressOf(offset), MPSizeT(sizeOf<ByteVar>().toULong()), MPSizeT(len.toULong())).value.toInt()
read(buf.addressOf(offset), sizeT(sizeOf<ByteVar>()), sizeT(len)).toInt()
}
if (result == 0 && eof) return -1
return result
Expand All @@ -130,7 +134,7 @@ public class FileInputStream(public val filePtr: CPointer<FILE>) : InputStream()
*/
public fun read(buffer: UByteArray, offset: Int = 0, len: Int = buffer.size - offset): Int {
val result = buffer.usePinned { buf ->
read(buf.addressOf(offset), MPSizeT(1u), MPSizeT(len.toULong())).value.toInt()
read(buf.addressOf(offset), sizeT(1), sizeT(len)).toInt()
}
if (result == 0 && eof) return -1
return result
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023.
* Copyright (c) 2024.
*
* This file is part of xmlutil.
*
Expand All @@ -26,26 +26,27 @@ import nl.adaptivity.xmlutil.ExperimentalXmlUtilApi
import platform.posix.*

@ExperimentalXmlUtilApi
public class FileOutputStream(public val filePtr: CPointer<FILE>) : NativeOutputStream() {
public class FileOutputStream(public val filePtr: FilePtr) : NativeOutputStream() {

public constructor(pathName: String, mode: FileMode = Mode.TRUNCATED) : this(
fopen(pathName, mode.modeString) ?: kotlin.run {
FilePtr(fopen(pathName, mode.modeString) ?: kotlin.run {
throw IOException.fromErrno()
})
}))

public constructor(fileHandle: Int, mode: FileMode = Mode.TRUNCATED) : this(
fdopen(fileHandle, mode.modeString) ?: kotlin.run {
FilePtr(fdopen(fileHandle, mode.modeString) ?: kotlin.run {
throw IOException.fromErrno()
})
}))

public fun write(buffer: UByteArray, begin: Int = 0, end: Int = buffer.size - begin): Unit {
@OptIn(ExperimentalForeignApi::class)
public fun write(buffer: UByteArray, begin: Int = 0, end: Int = buffer.size - begin) {
var loopBegin: Int = begin
var remaining = MPSizeT((end - loopBegin).toULong())
var remaining = sizeT((end - loopBegin).toULong())
buffer.usePinned { buf ->
while (remaining.value > 0uL) {
while (remaining.toULong() > 0uL) {
val bufferPtr = buf.addressOf(loopBegin)
val written = writePtr(bufferPtr, remaining)
loopBegin += written.value.toInt()
loopBegin += written.toInt()
remaining -= written
}
}
Expand All @@ -55,14 +56,14 @@ public class FileOutputStream(public val filePtr: CPointer<FILE>) : NativeOutput
write(byteArrayOf(b.toByte()))
}

public override fun write(b: ByteArray, off: Int, len: Int): Unit {
public override fun write(b: ByteArray, off: Int, len: Int) {
var loopBegin: Int = off
var remaining = MPSizeT((len - loopBegin).toULong())
var remaining = sizeT((len - loopBegin).toULong())
b.usePinned { buf ->
while (remaining.value > 0uL) {
while (remaining.toULong() > 0uL) {
val bufStart = buf.addressOf(loopBegin)
val written = writePtr(bufStart, remaining)
loopBegin += written.value.toInt()
loopBegin += written.toInt()
remaining -= written
}
}
Expand All @@ -71,30 +72,32 @@ public class FileOutputStream(public val filePtr: CPointer<FILE>) : NativeOutput
/** Write buffers to the underlying file (where valid). */
@OptIn(ExperimentalForeignApi::class)
public fun flush() {
if (fflush(filePtr) != 0) {
if (fflush(filePtr.value) != 0) {
throw IOException.fromErrno()
}
}

public override fun <T : CPointed> writePtr(buffer: CArrayPointer<T>, size: MPSizeT, count: MPSizeT): MPSizeT {
clearerr(filePtr)
val elemsWritten = MPSizeT(fwrite(buffer, size.value.convert(), count.value.convert(), filePtr))
if (elemsWritten.value == 0uL && count.value != 0uL) {
val e = ferror(filePtr)
@OptIn(UnsafeNumber::class)
public override fun <T : CPointed> writePtr(buffer: CArrayPointer<T>, size: SizeT, count: SizeT): SizeT {
clearerr(filePtr.value)
val elemsWritten = SizeT(fwrite(buffer, size.value.convert(), count.value.convert(), filePtr.value))
if (elemsWritten.toULong() == 0uL && count.toULong() != 0uL) {
val e = ferror(filePtr.value)
throw IOException.fromErrno(e)
}
return elemsWritten
}

public override fun <T : CPointed> writeAllPtr(buffer: CArrayPointer<T>, size: MPSizeT, count: MPSizeT) {
@OptIn(UnsafeNumber::class)
public override fun <T : CPointed> writeAllPtr(buffer: CArrayPointer<T>, size: SizeT, count: SizeT) {

clearerr(filePtr)
var elemsRemaining: ULong = count.value
clearerr(filePtr.value)
var elemsRemaining: ULong = count.toULong()
var currentBufferPointer = buffer
while (elemsRemaining > 0u) {
val elemsWritten: ULong = fwrite(currentBufferPointer, size.value.convert(), count.value.convert(), filePtr).convert()
val elemsWritten: ULong = fwrite(currentBufferPointer, size.value.convert(), count.value.convert(), filePtr.value).convert()
if (elemsWritten == 0uL) {
val e = ferror(filePtr)
val e = ferror(filePtr.value)
throw IOException.fromErrno(e)
}
elemsRemaining -= elemsWritten
Expand All @@ -105,7 +108,7 @@ public class FileOutputStream(public val filePtr: CPointer<FILE>) : NativeOutput
}

override fun close() {
if (fclose(filePtr) != 0) {
if (fclose(filePtr.value) != 0) {
throw IOException.fromErrno()
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2024.
*
* This file is part of xmlutil.
*
* This file is licenced to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You should have received a copy of the license with the source distribution.
* Alternatively, you may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package nl.adaptivity.xmlutil.core.impl.multiplatform

import kotlinx.cinterop.CPointer
import kotlinx.cinterop.ExperimentalForeignApi
import platform.posix.FILE

@OptIn(ExperimentalForeignApi::class)
public value class FilePtr(public val value: CPointer<FILE>) {
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023.
* Copyright (c) 2024.
*
* This file is part of xmlutil.
*
Expand Down Expand Up @@ -53,15 +53,7 @@ public actual abstract class InputStream : Closeable {
public actual abstract fun read(): Int

@ExperimentalForeignApi
public abstract fun <T : CPointed> read(buffer: CArrayPointer<T>, size: MPSizeT, bufferSize: MPSizeT): MPSizeT
public abstract fun <T : CPointed> read(buffer: CArrayPointer<T>, size: SizeT, bufferSize: SizeT): SizeT
actual override fun close() {}
}

/**
* Wrapper type to stand in for `size_t` as that type has inconsistent sizes in different architectures.
*/
public value class MPSizeT(public val value: ULong) {
public constructor(value: UInt): this(value.toULong())
public operator fun minus(other: MPSizeT): MPSizeT = MPSizeT(value - other.value)
public operator fun plus(other: MPSizeT): MPSizeT = MPSizeT(value + other.value)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023.
* Copyright (c) 2024.
*
* This file is part of xmlutil.
*
Expand All @@ -20,12 +20,10 @@

package nl.adaptivity.xmlutil.core.impl.multiplatform

import kotlinx.cinterop.CPointer
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.addressOf
import kotlinx.cinterop.usePinned
import nl.adaptivity.xmlutil.core.impl.multiplatform.FileInputStream.Mode
import platform.posix.FILE

/**
* An implementation of a reader that reads (UTF-8 only) input streams.
Expand All @@ -37,7 +35,7 @@ public class InputStreamReader(public val inputStream: InputStream) : Reader() {
private var inputBufferEnd = 0
private var pendingLowSurrogate: Char = '\u0000'

public constructor(filePtr: CPointer<FILE>) : this(FileInputStream(filePtr))
public constructor(filePtr: FilePtr) : this(FileInputStream(filePtr))

public constructor(pathName: String, mode: FileMode = Mode.READ) :
this(FileInputStream(pathName, mode))
Expand All @@ -54,9 +52,9 @@ public class InputStreamReader(public val inputStream: InputStream) : Reader() {
inputBufferEnd = inputBuffer.usePinned { b ->
inputStream.read(
b.addressOf(inputBufferOffset),
MPSizeT(1u),
MPSizeT((inputBuffer.size - inputBufferOffset).toULong())
).value.toInt() + inputBufferOffset
SizeT(1u),
sizeT((inputBuffer.size - inputBufferOffset).toULong())
).toInt() + inputBufferOffset
}
}
}
Expand Down
Loading

0 comments on commit b5b4ee3

Please sign in to comment.