Skip to content

Commit 92e0214

Browse files
authored
Minor cleanup and simplification of readString (#376)
* Request Long.MAX_VALUE from the source at once (note: no need for a loop as we are unable to build the string of such size anyway) * Get rid of redundant checks in commonReadUtf8 Ticks one of the boxes in #342
1 parent 8a86a68 commit 92e0214

File tree

3 files changed

+57
-13
lines changed

3 files changed

+57
-13
lines changed

benchmarks/README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,13 @@ Currently, the suite includes benchmarks on:
88
- segment pooling performance.
99

1010
The suite doesn't include benchmarks for more complex APIs inherited from Okio as these APIs are subject to change.
11-
Such benchmarks will be added later along with corresponding changes in the library.
11+
Such benchmarks will be added later along with corresponding changes in the library.
12+
13+
### Quickstart
14+
15+
For JVM:
16+
```
17+
./gradlew :kotlinx-io-benchmarks:jvmJar
18+
19+
java -jar benchmarks/build/benchmarks/jvm/jars/kotlinx-io-benchmarks-jvm-jmh-0.6.0-SNAPSHOT-JMH.jar ReadStringBenchmark -f 1 -wi 5 -i 5 -tu us -w 1 -r 1
20+
```
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package kotlinx.io.benchmarks
2+
3+
import kotlinx.benchmark.Benchmark
4+
import kotlinx.benchmark.Param
5+
import kotlinx.benchmark.Scope
6+
import kotlinx.benchmark.Setup
7+
import kotlinx.benchmark.State
8+
import kotlinx.io.Buffer
9+
import kotlinx.io.Source
10+
import kotlinx.io.readCodePointValue
11+
import kotlinx.io.readString
12+
import kotlinx.io.writeCodePointValue
13+
import kotlinx.io.writeString
14+
import kotlin.random.Random
15+
16+
17+
@State(Scope.Benchmark)
18+
open class ReadStringBenchmark() {
19+
20+
@Param("16", "64", "512") // Fits into a single segment, so the benchmark does not measure segment boundaries crossing
21+
var size: Int = 0
22+
23+
val buffer: Buffer = Buffer()
24+
25+
@Setup
26+
fun setup() {
27+
val string = buildString { repeat(size) { append(('a'..'z').random()) } }
28+
buffer.writeString(string)
29+
}
30+
31+
32+
@Benchmark
33+
fun bufferReadString(): String {
34+
return buffer.copy().readString()
35+
}
36+
37+
@Benchmark
38+
fun sourceReadString(): String {
39+
val source: Source = buffer.copy()
40+
return source.readString()
41+
}
42+
}

core/common/src/Utf8.kt

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -206,10 +206,7 @@ public fun Sink.writeString(chars: CharSequence, startIndex: Int = 0, endIndex:
206206
*/
207207
@OptIn(InternalIoApi::class)
208208
public fun Source.readString(): String {
209-
var req: Long = Segment.SIZE.toLong()
210-
while (request(req)) {
211-
req *= 2
212-
}
209+
request(Long.MAX_VALUE) // Request all data
213210
return buffer.commonReadUtf8(buffer.size)
214211
}
215212

@@ -607,10 +604,7 @@ private fun Buffer.commonWriteUtf8CodePoint(codePoint: Int) {
607604

608605
@OptIn(UnsafeIoApi::class)
609606
private fun Buffer.commonReadUtf8(byteCount: Long): String {
610-
require(byteCount >= 0 && byteCount <= Int.MAX_VALUE) {
611-
"byteCount ($byteCount) is not within the range [0..${Int.MAX_VALUE})"
612-
}
613-
require(byteCount)
607+
// Invariant: byteCount was request()'ed into this buffer beforehand
614608
if (byteCount == 0L) return ""
615609

616610
UnsafeBufferOperations.iterate(this) { ctx, head ->
@@ -624,7 +618,6 @@ private fun Buffer.commonReadUtf8(byteCount: Long): String {
624618
}
625619
}
626620
}
627-
628-
// If the string spans multiple segments, delegate to readBytes().
629-
return readByteArray(byteCount.toInt()).commonToUtf8String()
630-
}
621+
// If the string spans multiple segments, delegate to readBytes()
622+
return readByteArray(byteCount.toInt()).commonToUtf8String()
623+
}

0 commit comments

Comments
 (0)