Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PR 2/5] Introduce unsafe API for bulk read/write ops #334

Merged
merged 6 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions core/api/kotlinx-io-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ public final class kotlinx/io/Buffer : kotlinx/io/Sink, kotlinx/io/Source {
public fun flush ()V
public final fun get (J)B
public fun getBuffer ()Lkotlinx/io/Buffer;
public final synthetic fun getHead ()Lkotlinx/io/Segment;
public final fun getSize ()J
public final synthetic fun getSizeMut ()J
public final synthetic fun getTail ()Lkotlinx/io/Segment;
public fun hintEmit ()V
public fun peek ()Lkotlinx/io/Source;
public fun readAtMostTo (Lkotlinx/io/Buffer;J)J
Expand All @@ -20,12 +23,17 @@ public final class kotlinx/io/Buffer : kotlinx/io/Sink, kotlinx/io/Source {
public fun readLong ()J
public fun readShort ()S
public fun readTo (Lkotlinx/io/RawSink;J)V
public final synthetic fun recycleTail ()V
public fun request (J)Z
public fun require (J)V
public final synthetic fun setHead (Lkotlinx/io/Segment;)V
public final synthetic fun setSizeMut (J)V
public final synthetic fun setTail (Lkotlinx/io/Segment;)V
public fun skip (J)V
public fun toString ()Ljava/lang/String;
public fun transferFrom (Lkotlinx/io/RawSource;)J
public fun transferTo (Lkotlinx/io/RawSink;)J
public final synthetic fun writableSegment (I)Lkotlinx/io/Segment;
public fun write (Lkotlinx/io/Buffer;J)V
public fun write (Lkotlinx/io/RawSource;J)V
public fun write ([BII)V
Expand Down Expand Up @@ -92,6 +100,24 @@ public abstract interface class kotlinx/io/RawSource : java/lang/AutoCloseable {
public abstract fun readAtMostTo (Lkotlinx/io/Buffer;J)J
}

public final class kotlinx/io/Segment {
public synthetic fun <init> ([BIIZZLkotlin/jvm/internal/DefaultConstructorMarker;)V
public final synthetic fun dataAsByteArray (Z)[B
public final synthetic fun getLimit ()I
public final synthetic fun getNext ()Lkotlinx/io/Segment;
public final synthetic fun getPos ()I
public final synthetic fun getRemainingCapacity ()I
public final synthetic fun getSize ()I
public final synthetic fun setLimit (I)V
public final synthetic fun setNext (Lkotlinx/io/Segment;)V
public final synthetic fun setPos (I)V
public final synthetic fun writeBackData ([BI)V
}

public final class kotlinx/io/SegmentKt {
public static final fun isEmpty (Lkotlinx/io/Segment;)Z
}

public abstract interface class kotlinx/io/Sink : kotlinx/io/RawSink {
public abstract fun emit ()V
public abstract fun flush ()V
Expand Down Expand Up @@ -186,6 +212,9 @@ public final class kotlinx/io/SourcesKt {
public static final fun startsWith (Lkotlinx/io/Source;B)Z
}

public abstract interface annotation class kotlinx/io/UnsafeIoApi : java/lang/annotation/Annotation {
}

public final class kotlinx/io/Utf8Kt {
public static final fun readCodePointValue (Lkotlinx/io/Source;)I
public static final fun readLine (Lkotlinx/io/Source;)Ljava/lang/String;
Expand Down Expand Up @@ -253,3 +282,18 @@ public final class kotlinx/io/files/PathsKt {
public static final fun sourceDeprecated (Lkotlinx/io/files/Path;)Lkotlinx/io/Source;
}

public final class kotlinx/io/unsafe/UnsafeBufferOperations {
public static final field INSTANCE Lkotlinx/io/unsafe/UnsafeBufferOperations;
public final fun getMaxSafeWriteCapacity ()I
public final fun moveToTail (Lkotlinx/io/Buffer;[BII)V
public static synthetic fun moveToTail$default (Lkotlinx/io/unsafe/UnsafeBufferOperations;Lkotlinx/io/Buffer;[BIIILjava/lang/Object;)V
public final fun readFromHead (Lkotlinx/io/Buffer;Lkotlin/jvm/functions/Function3;)V
public final fun writeToTail (Lkotlinx/io/Buffer;ILkotlin/jvm/functions/Function3;)V
}

public final class kotlinx/io/unsafe/UnsafeBufferOperationsJvmKt {
public static final fun readBulk (Lkotlinx/io/unsafe/UnsafeBufferOperations;Lkotlinx/io/Buffer;[Ljava/nio/ByteBuffer;Lkotlin/jvm/functions/Function2;)V
public static final fun readFromHead (Lkotlinx/io/unsafe/UnsafeBufferOperations;Lkotlinx/io/Buffer;Lkotlin/jvm/functions/Function1;)V
public static final fun writeToTail (Lkotlinx/io/unsafe/UnsafeBufferOperations;Lkotlinx/io/Buffer;ILkotlin/jvm/functions/Function1;)V
}

41 changes: 40 additions & 1 deletion core/api/kotlinx-io-core.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,14 @@ final class kotlinx.io/Buffer : kotlinx.io/Sink, kotlinx.io/Source { // kotlinx.
final fun readLong(): kotlin/Long // kotlinx.io/Buffer.readLong|readLong(){}[0]
final fun readShort(): kotlin/Short // kotlinx.io/Buffer.readShort|readShort(){}[0]
final fun readTo(kotlinx.io/RawSink, kotlin/Long) // kotlinx.io/Buffer.readTo|readTo(kotlinx.io.RawSink;kotlin.Long){}[0]
final fun recycleTail() // kotlinx.io/Buffer.recycleTail|recycleTail(){}[0]
final fun request(kotlin/Long): kotlin/Boolean // kotlinx.io/Buffer.request|request(kotlin.Long){}[0]
final fun require(kotlin/Long) // kotlinx.io/Buffer.require|require(kotlin.Long){}[0]
final fun skip(kotlin/Long) // kotlinx.io/Buffer.skip|skip(kotlin.Long){}[0]
final fun toString(): kotlin/String // kotlinx.io/Buffer.toString|toString(){}[0]
final fun transferFrom(kotlinx.io/RawSource): kotlin/Long // kotlinx.io/Buffer.transferFrom|transferFrom(kotlinx.io.RawSource){}[0]
final fun transferTo(kotlinx.io/RawSink): kotlin/Long // kotlinx.io/Buffer.transferTo|transferTo(kotlinx.io.RawSink){}[0]
final fun writableSegment(kotlin/Int): kotlinx.io/Segment // kotlinx.io/Buffer.writableSegment|writableSegment(kotlin.Int){}[0]
final fun write(kotlin/ByteArray, kotlin/Int, kotlin/Int) // kotlinx.io/Buffer.write|write(kotlin.ByteArray;kotlin.Int;kotlin.Int){}[0]
final fun write(kotlinx.io/Buffer, kotlin/Long) // kotlinx.io/Buffer.write|write(kotlinx.io.Buffer;kotlin.Long){}[0]
final fun write(kotlinx.io/RawSource, kotlin/Long) // kotlinx.io/Buffer.write|write(kotlinx.io.RawSource;kotlin.Long){}[0]
Expand All @@ -70,8 +72,34 @@ final class kotlinx.io/Buffer : kotlinx.io/Sink, kotlinx.io/Source { // kotlinx.
final fun writeShort(kotlin/Short) // kotlinx.io/Buffer.writeShort|writeShort(kotlin.Short){}[0]
final val buffer // kotlinx.io/Buffer.buffer|{}buffer[0]
final fun <get-buffer>(): kotlinx.io/Buffer // kotlinx.io/Buffer.buffer.<get-buffer>|<get-buffer>(){}[0]
final var size // kotlinx.io/Buffer.size|{}size[0]
final val size // kotlinx.io/Buffer.size|{}size[0]
final fun <get-size>(): kotlin/Long // kotlinx.io/Buffer.size.<get-size>|<get-size>(){}[0]
final var head // kotlinx.io/Buffer.head|{}head[0]
final fun <get-head>(): kotlinx.io/Segment? // kotlinx.io/Buffer.head.<get-head>|<get-head>(){}[0]
final fun <set-head>(kotlinx.io/Segment?) // kotlinx.io/Buffer.head.<set-head>|<set-head>(kotlinx.io.Segment?){}[0]
final var sizeMut // kotlinx.io/Buffer.sizeMut|{}sizeMut[0]
final fun <get-sizeMut>(): kotlin/Long // kotlinx.io/Buffer.sizeMut.<get-sizeMut>|<get-sizeMut>(){}[0]
final fun <set-sizeMut>(kotlin/Long) // kotlinx.io/Buffer.sizeMut.<set-sizeMut>|<set-sizeMut>(kotlin.Long){}[0]
final var tail // kotlinx.io/Buffer.tail|{}tail[0]
final fun <get-tail>(): kotlinx.io/Segment? // kotlinx.io/Buffer.tail.<get-tail>|<get-tail>(){}[0]
final fun <set-tail>(kotlinx.io/Segment?) // kotlinx.io/Buffer.tail.<set-tail>|<set-tail>(kotlinx.io.Segment?){}[0]
}
final class kotlinx.io/Segment { // kotlinx.io/Segment|null[0]
final fun dataAsByteArray(kotlin/Boolean): kotlin/ByteArray // kotlinx.io/Segment.dataAsByteArray|dataAsByteArray(kotlin.Boolean){}[0]
final fun writeBackData(kotlin/ByteArray, kotlin/Int) // kotlinx.io/Segment.writeBackData|writeBackData(kotlin.ByteArray;kotlin.Int){}[0]
final val remainingCapacity // kotlinx.io/Segment.remainingCapacity|{}remainingCapacity[0]
final fun <get-remainingCapacity>(): kotlin/Int // kotlinx.io/Segment.remainingCapacity.<get-remainingCapacity>|<get-remainingCapacity>(){}[0]
final val size // kotlinx.io/Segment.size|{}size[0]
final fun <get-size>(): kotlin/Int // kotlinx.io/Segment.size.<get-size>|<get-size>(){}[0]
final var limit // kotlinx.io/Segment.limit|{}limit[0]
final fun <get-limit>(): kotlin/Int // kotlinx.io/Segment.limit.<get-limit>|<get-limit>(){}[0]
final fun <set-limit>(kotlin/Int) // kotlinx.io/Segment.limit.<set-limit>|<set-limit>(kotlin.Int){}[0]
final var next // kotlinx.io/Segment.next|{}next[0]
final fun <get-next>(): kotlinx.io/Segment? // kotlinx.io/Segment.next.<get-next>|<get-next>(){}[0]
final fun <set-next>(kotlinx.io/Segment?) // kotlinx.io/Segment.next.<set-next>|<set-next>(kotlinx.io.Segment?){}[0]
final var pos // kotlinx.io/Segment.pos|{}pos[0]
final fun <get-pos>(): kotlin/Int // kotlinx.io/Segment.pos.<get-pos>|<get-pos>(){}[0]
final fun <set-pos>(kotlin/Int) // kotlinx.io/Segment.pos.<set-pos>|<set-pos>(kotlin.Int){}[0]
}
final fun (kotlinx.io.files/Path).kotlinx.io.files/sink(): kotlinx.io/Sink // kotlinx.io.files/sink|sink@kotlinx.io.files.Path(){}[0]
final fun (kotlinx.io.files/Path).kotlinx.io.files/source(): kotlinx.io/Source // kotlinx.io.files/source|source@kotlinx.io.files.Path(){}[0]
Expand All @@ -81,6 +109,7 @@ final fun (kotlinx.io/Buffer).kotlinx.io/readString(): kotlin/String // kotlinx.
final fun (kotlinx.io/Buffer).kotlinx.io/snapshot(): kotlinx.io.bytestring/ByteString // kotlinx.io/snapshot|snapshot@kotlinx.io.Buffer(){}[0]
final fun (kotlinx.io/RawSink).kotlinx.io/buffered(): kotlinx.io/Sink // kotlinx.io/buffered|buffered@kotlinx.io.RawSink(){}[0]
final fun (kotlinx.io/RawSource).kotlinx.io/buffered(): kotlinx.io/Source // kotlinx.io/buffered|buffered@kotlinx.io.RawSource(){}[0]
final fun (kotlinx.io/Segment).kotlinx.io/isEmpty(): kotlin/Boolean // kotlinx.io/isEmpty|isEmpty@kotlinx.io.Segment(){}[0]
final fun (kotlinx.io/Sink).kotlinx.io/write(kotlinx.io.bytestring/ByteString, kotlin/Int = ..., kotlin/Int = ...) // kotlinx.io/write|write@kotlinx.io.Sink(kotlinx.io.bytestring.ByteString;kotlin.Int;kotlin.Int){}[0]
final fun (kotlinx.io/Sink).kotlinx.io/writeCodePointValue(kotlin/Int) // kotlinx.io/writeCodePointValue|writeCodePointValue@kotlinx.io.Sink(kotlin.Int){}[0]
final fun (kotlinx.io/Sink).kotlinx.io/writeDecimalLong(kotlin/Long) // kotlinx.io/writeDecimalLong|writeDecimalLong@kotlinx.io.Sink(kotlin.Long){}[0]
Expand Down Expand Up @@ -135,6 +164,13 @@ final fun kotlinx.io.files/Path(kotlin/String, kotlin/Array<out kotlin/String>..
final fun kotlinx.io.files/Path(kotlinx.io.files/Path, kotlin/Array<out kotlin/String>...): kotlinx.io.files/Path // kotlinx.io.files/Path|Path(kotlinx.io.files.Path;kotlin.Array<out|kotlin.String>...){}[0]
final fun kotlinx.io/discardingSink(): kotlinx.io/RawSink // kotlinx.io/discardingSink|discardingSink(){}[0]
final inline fun (kotlinx.io/Sink).kotlinx.io/writeToInternalBuffer(kotlin/Function1<kotlinx.io/Buffer, kotlin/Unit>) // kotlinx.io/writeToInternalBuffer|writeToInternalBuffer@kotlinx.io.Sink(kotlin.Function1<kotlinx.io.Buffer,kotlin.Unit>){}[0]
final object kotlinx.io.unsafe/UnsafeBufferOperations { // kotlinx.io.unsafe/UnsafeBufferOperations|null[0]
final fun moveToTail(kotlinx.io/Buffer, kotlin/ByteArray, kotlin/Int = ..., kotlin/Int = ...) // kotlinx.io.unsafe/UnsafeBufferOperations.moveToTail|moveToTail(kotlinx.io.Buffer;kotlin.ByteArray;kotlin.Int;kotlin.Int){}[0]
final inline fun readFromHead(kotlinx.io/Buffer, kotlin/Function3<kotlin/ByteArray, kotlin/Int, kotlin/Int, kotlin/Int>) // kotlinx.io.unsafe/UnsafeBufferOperations.readFromHead|readFromHead(kotlinx.io.Buffer;kotlin.Function3<kotlin.ByteArray,kotlin.Int,kotlin.Int,kotlin.Int>){}[0]
final inline fun writeToTail(kotlinx.io/Buffer, kotlin/Int, kotlin/Function3<kotlin/ByteArray, kotlin/Int, kotlin/Int, kotlin/Int>) // kotlinx.io.unsafe/UnsafeBufferOperations.writeToTail|writeToTail(kotlinx.io.Buffer;kotlin.Int;kotlin.Function3<kotlin.ByteArray,kotlin.Int,kotlin.Int,kotlin.Int>){}[0]
final val maxSafeWriteCapacity // kotlinx.io.unsafe/UnsafeBufferOperations.maxSafeWriteCapacity|{}maxSafeWriteCapacity[0]
final fun <get-maxSafeWriteCapacity>(): kotlin/Int // kotlinx.io.unsafe/UnsafeBufferOperations.maxSafeWriteCapacity.<get-maxSafeWriteCapacity>|<get-maxSafeWriteCapacity>(){}[0]
}
final val kotlinx.io.files/SystemFileSystem // kotlinx.io.files/SystemFileSystem|{}SystemFileSystem[0]
final fun <get-SystemFileSystem>(): kotlinx.io.files/FileSystem // kotlinx.io.files/SystemFileSystem.<get-SystemFileSystem>|<get-SystemFileSystem>(){}[0]
final val kotlinx.io.files/SystemPathSeparator // kotlinx.io.files/SystemPathSeparator|{}SystemPathSeparator[0]
Expand All @@ -147,6 +183,9 @@ open annotation class kotlinx.io/DelicateIoApi : kotlin/Annotation { // kotlinx.
open annotation class kotlinx.io/InternalIoApi : kotlin/Annotation { // kotlinx.io/InternalIoApi|null[0]
constructor <init>() // kotlinx.io/InternalIoApi.<init>|<init>(){}[0]
}
open annotation class kotlinx.io/UnsafeIoApi : kotlin/Annotation { // kotlinx.io/UnsafeIoApi|null[0]
constructor <init>() // kotlinx.io/UnsafeIoApi.<init>|<init>(){}[0]
}
open class kotlinx.io.files/FileNotFoundException : kotlinx.io/IOException { // kotlinx.io.files/FileNotFoundException|null[0]
constructor <init>(kotlin/String?) // kotlinx.io.files/FileNotFoundException.<init>|<init>(kotlin.String?){}[0]
}
Expand Down
4 changes: 2 additions & 2 deletions core/apple/src/AppleCore.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ private open class OutputStreamSink(

head.pos += bytesWritten.toInt()
remaining -= bytesWritten
source.size -= bytesWritten
source.sizeMut -= bytesWritten

if (head.pos == head.limit) {
source.recycleHead()
Expand Down Expand Up @@ -105,7 +105,7 @@ private open class NSInputStreamSource(
return -1
}
tail.limit += bytesRead.toInt()
sink.size += bytesRead
sink.sizeMut += bytesRead
return bytesRead
}

Expand Down
4 changes: 2 additions & 2 deletions core/apple/src/BuffersApple.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ internal fun Buffer.write(source: CPointer<uint8_tVar>, maxLength: Int) {
currentOffset += toCopy
tail.limit += toCopy
}
size += maxLength
this.sizeMut += maxLength
}

internal fun Buffer.readAtMostTo(sink: CPointer<uint8_tVar>, maxLength: Int): Int {
Expand All @@ -43,7 +43,7 @@ internal fun Buffer.readAtMostTo(sink: CPointer<uint8_tVar>, maxLength: Int): In
}

s.pos += toCopy
size -= toCopy.toLong()
this.sizeMut -= toCopy.toLong()

if (s.pos == s.limit) {
recycleHead()
Expand Down
18 changes: 16 additions & 2 deletions core/common/src/Annotations.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
*/

Expand Down Expand Up @@ -38,4 +38,18 @@ public annotation class DelicateIoApi
"Make sure you fully read and understand documentation of the declaration that " +
"is marked as an internal API."
)
public annotation class InternalIoApi
public annotation class InternalIoApi

/**
* Marks API that may cause data corruption or loss or behave unpredictable when used with invalid argument values.
*
* Consider using other APIs instead when possible.
* Otherwise, make sure to read documentation describing an unsafe API.
*/
@Retention(AnnotationRetention.BINARY)
@RequiresOptIn(
level = RequiresOptIn.Level.WARNING,
message = "This is an unsafe API and its use requires care. " +
"Make sure you fully understand documentation of the declaration marked as UnsafeIoApi"
)
public annotation class UnsafeIoApi
Loading