Skip to content

Commit

Permalink
Merge branch 'master' into gh-pages
Browse files Browse the repository at this point in the history
  • Loading branch information
fzhinkin committed Jul 12, 2024
2 parents e1914c5 + c2ff370 commit a0ecbdc
Show file tree
Hide file tree
Showing 47 changed files with 3,385 additions and 363 deletions.
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# CHANGELOG

## 0.5.0
> Published 12 July 2024
### Features
- Provided an API allowing direct access to Buffer and Segment internals [#135](https://github.com/Kotlin/kotlinx-io/issues/135), [#166](https://github.com/Kotlin/kotlinx-io/issues/166)

The API is unsafe, delisted from public docs and requires explicit opt-in. It's recommended to
avoid this API unless you're working on integration with other APIs (like, `java.nio` or
`io_uring`, for example).

- Improved the way segment pooling is working on JVM [#352](https://github.com/Kotlin/kotlinx-io/pull/352)

Now sharing a segment won't make an original segment and all its copies recyclable.
Instead, the last remaining copy will be placed back into the pool when recycled.
Segments are no longer allocated or lost when taking or recycling a segment from pool
under a high contention due to concurrent requests.
Size of the segment pool on the JVM could now be statically configured by setting a system property
`kotlinx.io.pool.size.bytes`.

## 0.4.0
> Published 6 June 2024
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ repositories {
Add the library to dependencies:
```kotlin
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.4.0")
implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.5.0")
}
```

Expand All @@ -58,7 +58,7 @@ kotlin {
sourceSets {
commonMain {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.4.0")
implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.5.0")
}
}
}
Expand All @@ -72,7 +72,7 @@ Add the library to dependencies:
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-io-core-jvm</artifactId>
<version>0.4.0</version>
<version>0.5.0</version>
</dependency>
```

Expand Down
65 changes: 65 additions & 0 deletions benchmarks/src/commonMain/kotlin/BufferOps.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package kotlinx.io.benchmarks
import kotlinx.benchmark.*
import kotlinx.io.*
import kotlinx.io.bytestring.ByteString
import kotlin.random.Random

@State(Scope.Benchmark)
abstract class BufferRWBenchmarkBase {
Expand Down Expand Up @@ -415,3 +416,67 @@ open class IndexOfByteString {
@Benchmark
fun benchmark() = buffer.indexOf(byteString)
}

@State(Scope.Benchmark)
open class Utf8CodePointsBenchmark : BufferRWBenchmarkBase() {
private val codePointsCount = 128

// Encoding names follow naming from Utf8StringBenchmark
@Param("ascii", "utf8", "sparse", "2bytes", "3bytes", "4bytes", "bad")
var encoding: String = "ascii"

override fun padding(): ByteArray {
return ByteArray(minGap) { '.'.code.toByte() }
}

private val codePoints = IntArray(codePointsCount)
private var codePointIdx = 0

@Setup
fun fillCodePointsArray() {
fun IntArray.fill(generator: () -> Int) {
for (idx in this.indices) {
this[idx] = generator()
}
}

when (encoding) {
"ascii" -> codePoints.fill { Random.nextInt(' '.code, '~'.code) }
"utf8" -> codePoints.fill {
var cp: Int
do {
cp = Random.nextInt(0, 0x10ffff)
} while (cp in 0xd800 .. 0xdfff)
cp
}
"sparse" -> {
codePoints.fill { Random.nextInt(' '.code, '~'.code) }
codePoints[42] = ''.code
}
"2bytes" -> codePoints.fill { Random.nextInt(0x80, 0x800) }
"3bytes" -> codePoints.fill {
var cp: Int
do {
cp = Random.nextInt(0x800, 0x10000)
} while (cp in 0xd800 .. 0xdfff)
cp
}
"4bytes" -> codePoints.fill { Random.nextInt(0x10000, 0x10ffff) }
"bad" -> codePoints.fill { Random.nextInt(0xd800, 0xdfff) }
}
}


private fun nextCodePoint(): Int {
val idx = codePointIdx
val cp = codePoints[idx]
codePointIdx = (idx + 1) % codePointsCount
return cp
}

@Benchmark
fun benchmark(): Int {
buffer.writeCodePointValue(nextCodePoint())
return buffer.readCodePointValue()
}
}
38 changes: 24 additions & 14 deletions bytestring/api/kotlinx-io-bytestring.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,16 @@
// - Show declarations: true

// Library unique name: <org.jetbrains.kotlinx:kotlinx-io-bytestring>
open annotation class kotlinx.io.bytestring.unsafe/UnsafeByteStringApi : kotlin/Annotation { // kotlinx.io.bytestring.unsafe/UnsafeByteStringApi|null[0]
constructor <init>() // kotlinx.io.bytestring.unsafe/UnsafeByteStringApi.<init>|<init>(){}[0]
}

final class kotlinx.io.bytestring/ByteString : kotlin/Comparable<kotlinx.io.bytestring/ByteString> { // kotlinx.io.bytestring/ByteString|null[0]
constructor <init>(kotlin/ByteArray, kotlin/Int = ..., kotlin/Int = ...) // kotlinx.io.bytestring/ByteString.<init>|<init>(kotlin.ByteArray;kotlin.Int;kotlin.Int){}[0]

final val size // kotlinx.io.bytestring/ByteString.size|{}size[0]
final fun <get-size>(): kotlin/Int // kotlinx.io.bytestring/ByteString.size.<get-size>|<get-size>(){}[0]

final fun compareTo(kotlinx.io.bytestring/ByteString): kotlin/Int // kotlinx.io.bytestring/ByteString.compareTo|compareTo(kotlinx.io.bytestring.ByteString){}[0]
final fun copyInto(kotlin/ByteArray, kotlin/Int = ..., kotlin/Int = ..., kotlin/Int = ...) // kotlinx.io.bytestring/ByteString.copyInto|copyInto(kotlin.ByteArray;kotlin.Int;kotlin.Int;kotlin.Int){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.io.bytestring/ByteString.equals|equals(kotlin.Any?){}[0]
Expand All @@ -17,20 +25,31 @@ final class kotlinx.io.bytestring/ByteString : kotlin/Comparable<kotlinx.io.byte
final fun substring(kotlin/Int, kotlin/Int = ...): kotlinx.io.bytestring/ByteString // kotlinx.io.bytestring/ByteString.substring|substring(kotlin.Int;kotlin.Int){}[0]
final fun toByteArray(kotlin/Int = ..., kotlin/Int = ...): kotlin/ByteArray // kotlinx.io.bytestring/ByteString.toByteArray|toByteArray(kotlin.Int;kotlin.Int){}[0]
final fun toString(): kotlin/String // kotlinx.io.bytestring/ByteString.toString|toString(){}[0]

final object Companion // kotlinx.io.bytestring/ByteString.Companion|null[0]
final val size // kotlinx.io.bytestring/ByteString.size|{}size[0]
final fun <get-size>(): kotlin/Int // kotlinx.io.bytestring/ByteString.size.<get-size>|<get-size>(){}[0]
}

final class kotlinx.io.bytestring/ByteStringBuilder { // kotlinx.io.bytestring/ByteStringBuilder|null[0]
constructor <init>(kotlin/Int = ...) // kotlinx.io.bytestring/ByteStringBuilder.<init>|<init>(kotlin.Int){}[0]
final fun append(kotlin/Byte) // kotlinx.io.bytestring/ByteStringBuilder.append|append(kotlin.Byte){}[0]
final fun append(kotlin/ByteArray, kotlin/Int = ..., kotlin/Int = ...) // kotlinx.io.bytestring/ByteStringBuilder.append|append(kotlin.ByteArray;kotlin.Int;kotlin.Int){}[0]
final fun toByteString(): kotlinx.io.bytestring/ByteString // kotlinx.io.bytestring/ByteStringBuilder.toByteString|toByteString(){}[0]

final val capacity // kotlinx.io.bytestring/ByteStringBuilder.capacity|{}capacity[0]
final fun <get-capacity>(): kotlin/Int // kotlinx.io.bytestring/ByteStringBuilder.capacity.<get-capacity>|<get-capacity>(){}[0]
final val size // kotlinx.io.bytestring/ByteStringBuilder.size|{}size[0]
final fun <get-size>(): kotlin/Int // kotlinx.io.bytestring/ByteStringBuilder.size.<get-size>|<get-size>(){}[0]

final fun append(kotlin/Byte) // kotlinx.io.bytestring/ByteStringBuilder.append|append(kotlin.Byte){}[0]
final fun append(kotlin/ByteArray, kotlin/Int = ..., kotlin/Int = ...) // kotlinx.io.bytestring/ByteStringBuilder.append|append(kotlin.ByteArray;kotlin.Int;kotlin.Int){}[0]
final fun toByteString(): kotlinx.io.bytestring/ByteString // kotlinx.io.bytestring/ByteStringBuilder.toByteString|toByteString(){}[0]
}

final object kotlinx.io.bytestring.unsafe/UnsafeByteStringOperations { // kotlinx.io.bytestring.unsafe/UnsafeByteStringOperations|null[0]
final fun wrapUnsafe(kotlin/ByteArray): kotlinx.io.bytestring/ByteString // kotlinx.io.bytestring.unsafe/UnsafeByteStringOperations.wrapUnsafe|wrapUnsafe(kotlin.ByteArray){}[0]
final inline fun withByteArrayUnsafe(kotlinx.io.bytestring/ByteString, kotlin/Function1<kotlin/ByteArray, kotlin/Unit>) // kotlinx.io.bytestring.unsafe/UnsafeByteStringOperations.withByteArrayUnsafe|withByteArrayUnsafe(kotlinx.io.bytestring.ByteString;kotlin.Function1<kotlin.ByteArray,kotlin.Unit>){}[0]
}

final val kotlinx.io.bytestring/indices // kotlinx.io.bytestring/indices|@kotlinx.io.bytestring.ByteString{}indices[0]
final fun (kotlinx.io.bytestring/ByteString).<get-indices>(): kotlin.ranges/IntRange // kotlinx.io.bytestring/indices.<get-indices>|<get-indices>@kotlinx.io.bytestring.ByteString(){}[0]

final fun (kotlin.io.encoding/Base64).kotlinx.io.bytestring/decode(kotlinx.io.bytestring/ByteString, kotlin/Int = ..., kotlin/Int = ...): kotlin/ByteArray // kotlinx.io.bytestring/decode|[email protected](kotlinx.io.bytestring.ByteString;kotlin.Int;kotlin.Int){}[0]
final fun (kotlin.io.encoding/Base64).kotlinx.io.bytestring/decodeIntoByteArray(kotlinx.io.bytestring/ByteString, kotlin/ByteArray, kotlin/Int = ..., kotlin/Int = ..., kotlin/Int = ...): kotlin/Int // kotlinx.io.bytestring/decodeIntoByteArray|[email protected](kotlinx.io.bytestring.ByteString;kotlin.ByteArray;kotlin.Int;kotlin.Int;kotlin.Int){}[0]
final fun (kotlin.io.encoding/Base64).kotlinx.io.bytestring/decodeToByteString(kotlin/ByteArray, kotlin/Int = ..., kotlin/Int = ...): kotlinx.io.bytestring/ByteString // kotlinx.io.bytestring/decodeToByteString|[email protected](kotlin.ByteArray;kotlin.Int;kotlin.Int){}[0]
Expand Down Expand Up @@ -63,12 +82,3 @@ final fun (kotlinx.io.bytestring/ByteStringBuilder).kotlinx.io.bytestring/append
final fun <#A: kotlin.text/Appendable> (kotlin.io.encoding/Base64).kotlinx.io.bytestring/encodeToAppendable(kotlinx.io.bytestring/ByteString, #A, kotlin/Int = ..., kotlin/Int = ...): #A // kotlinx.io.bytestring/encodeToAppendable|[email protected](kotlinx.io.bytestring.ByteString;0:0;kotlin.Int;kotlin.Int){0§<kotlin.text.Appendable>}[0]
final fun kotlinx.io.bytestring/ByteString(kotlin/ByteArray...): kotlinx.io.bytestring/ByteString // kotlinx.io.bytestring/ByteString|ByteString(kotlin.ByteArray...){}[0]
final inline fun kotlinx.io.bytestring/buildByteString(kotlin/Int = ..., kotlin/Function1<kotlinx.io.bytestring/ByteStringBuilder, kotlin/Unit>): kotlinx.io.bytestring/ByteString // kotlinx.io.bytestring/buildByteString|buildByteString(kotlin.Int;kotlin.Function1<kotlinx.io.bytestring.ByteStringBuilder,kotlin.Unit>){}[0]
final object kotlinx.io.bytestring.unsafe/UnsafeByteStringOperations { // kotlinx.io.bytestring.unsafe/UnsafeByteStringOperations|null[0]
final fun wrapUnsafe(kotlin/ByteArray): kotlinx.io.bytestring/ByteString // kotlinx.io.bytestring.unsafe/UnsafeByteStringOperations.wrapUnsafe|wrapUnsafe(kotlin.ByteArray){}[0]
final inline fun withByteArrayUnsafe(kotlinx.io.bytestring/ByteString, kotlin/Function1<kotlin/ByteArray, kotlin/Unit>) // kotlinx.io.bytestring.unsafe/UnsafeByteStringOperations.withByteArrayUnsafe|withByteArrayUnsafe(kotlinx.io.bytestring.ByteString;kotlin.Function1<kotlin.ByteArray,kotlin.Unit>){}[0]
}
final val kotlinx.io.bytestring/indices // kotlinx.io.bytestring/indices|@kotlinx.io.bytestring.ByteString{}indices[0]
final fun (kotlinx.io.bytestring/ByteString).<get-indices>(): kotlin.ranges/IntRange // kotlinx.io.bytestring/indices.<get-indices>|<get-indices>@kotlinx.io.bytestring.ByteString(){}[0]
open annotation class kotlinx.io.bytestring.unsafe/UnsafeByteStringApi : kotlin/Annotation { // kotlinx.io.bytestring.unsafe/UnsafeByteStringApi|null[0]
constructor <init>() // kotlinx.io.bytestring.unsafe/UnsafeByteStringApi.<init>|<init>(){}[0]
}
76 changes: 76 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 All @@ -35,6 +43,10 @@ public final class kotlinx/io/Buffer : kotlinx/io/Sink, kotlinx/io/Source {
public fun writeShort (S)V
}

public final class kotlinx/io/BufferKt {
public static final synthetic fun seek (Lkotlinx/io/Buffer;JLkotlin/jvm/functions/Function2;)Ljava/lang/Object;
}

public final class kotlinx/io/BuffersJvmKt {
public static final fun asByteChannel (Lkotlinx/io/Buffer;)Ljava/nio/channels/ByteChannel;
public static final fun copyTo (Lkotlinx/io/Buffer;Ljava/io/OutputStream;JJ)V
Expand Down Expand Up @@ -92,6 +104,26 @@ 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> ([BIILkotlinx/io/SegmentCopyTracker;ZLkotlin/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 getPrev ()Lkotlinx/io/Segment;
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 setPrev (Lkotlinx/io/Segment;)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 +218,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 +288,44 @@ public final class kotlinx/io/files/PathsKt {
public static final fun sourceDeprecated (Lkotlinx/io/files/Path;)Lkotlinx/io/Source;
}

public abstract interface class kotlinx/io/unsafe/BufferIterationContext : kotlinx/io/unsafe/SegmentReadContext {
public abstract fun next (Lkotlinx/io/Segment;)Lkotlinx/io/Segment;
}

public abstract interface class kotlinx/io/unsafe/SegmentReadContext {
public abstract fun getUnchecked (Lkotlinx/io/Segment;I)B
}

public abstract interface class kotlinx/io/unsafe/SegmentWriteContext {
public abstract fun setUnchecked (Lkotlinx/io/Segment;IB)V
public abstract fun setUnchecked (Lkotlinx/io/Segment;IBB)V
public abstract fun setUnchecked (Lkotlinx/io/Segment;IBBB)V
public abstract fun setUnchecked (Lkotlinx/io/Segment;IBBBB)V
}

public final class kotlinx/io/unsafe/UnsafeBufferOperations {
public static final field INSTANCE Lkotlinx/io/unsafe/UnsafeBufferOperations;
public final fun getMaxSafeWriteCapacity ()I
public final fun iterate (Lkotlinx/io/Buffer;JLkotlin/jvm/functions/Function3;)V
public final fun iterate (Lkotlinx/io/Buffer;Lkotlin/jvm/functions/Function2;)V
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/Function2;)V
public final fun readFromHead (Lkotlinx/io/Buffer;Lkotlin/jvm/functions/Function3;)V
public final fun writeToTail (Lkotlinx/io/Buffer;ILkotlin/jvm/functions/Function2;)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
}

public final class kotlinx/io/unsafe/UnsafeBufferOperationsKt {
public static final synthetic fun getBufferIterationContextImpl ()Lkotlinx/io/unsafe/BufferIterationContext;
public static final synthetic fun getSegmentReadContextImpl ()Lkotlinx/io/unsafe/SegmentReadContext;
public static final synthetic fun getSegmentWriteContextImpl ()Lkotlinx/io/unsafe/SegmentWriteContext;
public static final synthetic fun withData (Lkotlinx/io/unsafe/SegmentReadContext;Lkotlinx/io/Segment;Lkotlin/jvm/functions/Function3;)V
}

Loading

0 comments on commit a0ecbdc

Please sign in to comment.