@@ -5,7 +5,6 @@ package kotlinx.coroutines.experimental.io
5
5
import kotlinx.atomicfu.*
6
6
import kotlinx.coroutines.experimental.*
7
7
import kotlinx.coroutines.experimental.channels.*
8
- import kotlinx.coroutines.experimental.internal.*
9
8
import kotlinx.coroutines.experimental.io.internal.*
10
9
import kotlinx.coroutines.experimental.io.packet.*
11
10
import kotlinx.io.core.*
@@ -368,30 +367,35 @@ internal class ByteBufferChannel(
368
367
}
369
368
}
370
369
371
- private tailrec fun readAsMuchAsPossible (dst : ByteBuffer , consumed0 : Int = 0 ): Int {
370
+ private fun readAsMuchAsPossible (dst : ByteBuffer ): Int {
372
371
var consumed = 0
373
372
374
- val rc = reading {
375
- val position = position()
376
- val remaining = limit () - position
373
+ reading { state ->
374
+ val buffer = this
375
+ val bufferLimit = buffer.capacity () - reservedSize
377
376
378
- val part = it.tryReadAtMost(minOf(remaining, dst.remaining()))
379
- if (part > 0 ) {
380
- consumed + = part
377
+ while ( true ) {
378
+ val dstRemaining = dst.remaining()
379
+ if (dstRemaining == 0 ) break
381
380
382
- limit( position + part)
383
- dst.put( this )
381
+ val position = readPosition
382
+ val bufferRemaining = bufferLimit - position
384
383
385
- bytesRead(it, part)
386
- true
387
- } else {
388
- false
384
+ val part = state.tryReadAtMost(minOf(bufferRemaining, dstRemaining))
385
+ if (part == 0 ) break
386
+
387
+ buffer.limit(position + part)
388
+ buffer.position(position)
389
+ dst.put(buffer)
390
+
391
+ bytesRead(state, part)
392
+ consumed + = part
389
393
}
394
+
395
+ false
390
396
}
391
397
392
- return if (rc && dst.hasRemaining() && state.capacity.availableForRead > 0 )
393
- readAsMuchAsPossible(dst, consumed0 + consumed)
394
- else consumed + consumed0
398
+ return consumed
395
399
}
396
400
397
401
private tailrec fun readAsMuchAsPossible (dst : BufferView , consumed0 : Int = 0): Int {
@@ -421,25 +425,34 @@ internal class ByteBufferChannel(
421
425
}
422
426
423
427
424
- private tailrec fun readAsMuchAsPossible (dst : ByteArray , offset : Int , length : Int , consumed0 : Int = 0 ): Int {
428
+ private fun readAsMuchAsPossible (dst : ByteArray , offset : Int , length : Int ): Int {
425
429
var consumed = 0
426
430
427
- val rc = reading {
428
- val part = it.tryReadAtMost(minOf(remaining(), length))
429
- if (part > 0 ) {
430
- consumed + = part
431
- get(dst, offset, part)
431
+ reading { state ->
432
+ val buffer = this
433
+ val bufferLimit = buffer.capacity() - reservedSize
432
434
433
- bytesRead(it, part)
434
- true
435
- } else {
436
- false
435
+ while (true ) {
436
+ val lengthRemaining = length - consumed
437
+ if (lengthRemaining == 0 ) break
438
+ val position = readPosition
439
+ val bufferRemaining = bufferLimit - position
440
+
441
+ val part = state.tryReadAtMost(minOf(bufferRemaining, lengthRemaining))
442
+ if (part == 0 ) break
443
+
444
+ buffer.limit(position + part)
445
+ buffer.position(position)
446
+ buffer.get(dst, offset + consumed, part)
447
+
448
+ bytesRead(state, part)
449
+ consumed + = part
437
450
}
451
+
452
+ false
438
453
}
439
454
440
- return if (rc && consumed < length && state.capacity.availableForRead > 0 )
441
- readAsMuchAsPossible(dst, offset + consumed, length - consumed, consumed0 + consumed)
442
- else consumed + consumed0
455
+ return consumed
443
456
}
444
457
445
458
final suspend override fun readFully (dst : ByteArray , offset : Int , length : Int ) {
@@ -1451,6 +1464,78 @@ internal class ByteBufferChannel(
1451
1464
return write(min, block)
1452
1465
}
1453
1466
1467
+ override suspend fun writeWhile (block : (ByteBuffer ) -> Boolean ) {
1468
+ if (! writeWhileNoSuspend(block)) return
1469
+ closed?.let { throw it.sendException }
1470
+ return writeWhileSuspend(block)
1471
+ }
1472
+
1473
+ private fun writeWhileNoSuspend (block : (ByteBuffer ) -> Boolean ): Boolean {
1474
+ var continueWriting = true
1475
+
1476
+ writing { dst, capacity ->
1477
+ continueWriting = writeWhileLoop(dst, capacity, block)
1478
+ }
1479
+
1480
+ return continueWriting
1481
+ }
1482
+
1483
+ private suspend fun writeWhileSuspend (block : (ByteBuffer ) -> Boolean ) {
1484
+ var continueWriting = true
1485
+
1486
+ writing { dst, capacity ->
1487
+ while (true ) {
1488
+ writeSuspend(1 )
1489
+ if (joining != null ) break
1490
+ if (! writeWhileLoop(dst, capacity, block)) {
1491
+ continueWriting = false
1492
+ break
1493
+ }
1494
+ if (closed != null ) break
1495
+ }
1496
+ }
1497
+
1498
+ if (! continueWriting) return
1499
+ closed?.let { throw it.sendException }
1500
+ joining?.let { return writeWhile(block) }
1501
+ }
1502
+
1503
+ // it should be writing state set to use this function
1504
+ private fun writeWhileLoop (dst : ByteBuffer , capacity : RingBufferCapacity , block : (ByteBuffer ) -> Boolean ): Boolean {
1505
+ var continueWriting = true
1506
+ val bufferLimit = dst.capacity() - reservedSize
1507
+
1508
+ while (continueWriting) {
1509
+ val locked = capacity.tryWriteAtLeast(1 ) // see comments in [write]
1510
+ if (locked == 0 ) break
1511
+
1512
+ val position = writePosition
1513
+ val l = (position + locked).coerceAtMost(bufferLimit)
1514
+ dst.limit(l)
1515
+ dst.position(position)
1516
+
1517
+ continueWriting = try {
1518
+ block(dst)
1519
+ } catch (t: Throwable ) {
1520
+ capacity.completeRead(locked)
1521
+ throw t
1522
+ }
1523
+
1524
+ if (dst.limit() != l) throw IllegalStateException (" buffer limit modified" )
1525
+ val actuallyWritten = dst.position() - position
1526
+ if (actuallyWritten < 0 ) throw IllegalStateException (" position has been moved backward: pushback is not supported" )
1527
+
1528
+ dst.bytesWritten(capacity, actuallyWritten)
1529
+ if (actuallyWritten < locked) {
1530
+ capacity.completeRead(locked - actuallyWritten) // return back extra bytes
1531
+ // it is important to use completeRead in spite of that we are writing here
1532
+ // no need to resume read here
1533
+ }
1534
+ }
1535
+
1536
+ return continueWriting
1537
+ }
1538
+
1454
1539
override suspend fun read (min : Int , block : (ByteBuffer ) -> Unit ) {
1455
1540
require(min >= 0 ) { " min should be positive or zero" }
1456
1541
0 commit comments