@@ -42,6 +42,9 @@ public class Buffer : Source, Sink {
42
42
@JvmField
43
43
internal var head: Segment ? = null
44
44
45
+ @JvmField
46
+ internal var tail: Segment ? = null
47
+
45
48
/* *
46
49
* The number of bytes accessible for read from this buffer.
47
50
*/
@@ -76,8 +79,7 @@ public class Buffer : Source, Sink {
76
79
val b = data[pos++ ]
77
80
size - = 1L
78
81
if (pos == limit) {
79
- head = segment.pop()
80
- SegmentPool .recycle(segment)
82
+ recycleHead()
81
83
} else {
82
84
segment.pos = pos
83
85
}
@@ -102,8 +104,7 @@ public class Buffer : Source, Sink {
102
104
size - = 2L
103
105
104
106
if (pos == limit) {
105
- head = segment.pop()
106
- SegmentPool .recycle(segment)
107
+ recycleHead()
107
108
} else {
108
109
segment.pos = pos
109
110
}
@@ -138,8 +139,7 @@ public class Buffer : Source, Sink {
138
139
size - = 4L
139
140
140
141
if (pos == limit) {
141
- head = segment.pop()
142
- SegmentPool .recycle(segment)
142
+ recycleHead()
143
143
} else {
144
144
segment.pos = pos
145
145
}
@@ -176,8 +176,7 @@ public class Buffer : Source, Sink {
176
176
size - = 8L
177
177
178
178
if (pos == limit) {
179
- head = segment.pop()
180
- SegmentPool .recycle(segment)
179
+ recycleHead()
181
180
} else {
182
181
segment.pos = pos
183
182
}
@@ -242,11 +241,10 @@ public class Buffer : Source, Sink {
242
241
copy.pos + = currentOffset.toInt()
243
242
copy.limit = minOf(copy.pos + remainingByteCount.toInt(), copy.limit)
244
243
if (out .head == null ) {
245
- copy.prev = copy
246
- copy.next = copy.prev
247
- out .head = copy.next
244
+ out .head = copy
245
+ out .tail = copy
248
246
} else {
249
- out .head !! .prev !! .push(copy)
247
+ out .tail = out .tail !! .push(copy)
250
248
}
251
249
remainingByteCount - = (copy.limit - copy.pos).toLong()
252
250
currentOffset = 0L
@@ -264,7 +262,7 @@ public class Buffer : Source, Sink {
264
262
if (result == 0L ) return 0L
265
263
266
264
// Omit the tail if it's still writable.
267
- val tail = head !! .prev !!
265
+ val tail = tail !!
268
266
if (tail.limit < Segment .SIZE && tail.owner) {
269
267
result - = (tail.limit - tail.pos).toLong()
270
268
}
@@ -317,8 +315,7 @@ public class Buffer : Source, Sink {
317
315
head.pos + = toSkip
318
316
319
317
if (head.pos == head.limit) {
320
- this .head = head.pop()
321
- SegmentPool .recycle(head)
318
+ recycleHead()
322
319
}
323
320
}
324
321
}
@@ -336,8 +333,7 @@ public class Buffer : Source, Sink {
336
333
size - = toCopy.toLong()
337
334
338
335
if (s.pos == s.limit) {
339
- head = s.pop()
340
- SegmentPool .recycle(s)
336
+ recycleHead()
341
337
}
342
338
343
339
return toCopy
@@ -377,19 +373,20 @@ public class Buffer : Source, Sink {
377
373
internal fun writableSegment (minimumCapacity : Int ): Segment {
378
374
require(minimumCapacity >= 1 && minimumCapacity <= Segment .SIZE ) { " unexpected capacity" }
379
375
380
- if (head == null ) {
376
+ if (tail == null ) {
381
377
val result = SegmentPool .take() // Acquire a first segment.
382
378
head = result
383
- result.prev = result
384
- result.next = result
379
+ tail = result
385
380
return result
386
381
}
387
382
388
- var tail = head!! .prev
389
- if (tail!! .limit + minimumCapacity > Segment .SIZE || ! tail.owner) {
390
- tail = tail.push(SegmentPool .take()) // Append a new empty segment to fill up.
383
+ val t = tail!!
384
+ if (t.limit + minimumCapacity > Segment .SIZE || ! t.owner) {
385
+ val newTail = t.push(SegmentPool .take()) // Append a new empty segment to fill up.
386
+ tail = newTail
387
+ return newTail
391
388
}
392
- return tail
389
+ return t
393
390
}
394
391
395
392
override fun write (source : ByteArray , startIndex : Int , endIndex : Int ) {
@@ -486,7 +483,7 @@ public class Buffer : Source, Sink {
486
483
while (remainingByteCount > 0L ) {
487
484
// Is a prefix of the source's head segment all that we need to move?
488
485
if (remainingByteCount < source.head!! .limit - source.head!! .pos) {
489
- val tail = if (head != null ) head !! .prev else null
486
+ val tail = tail
490
487
if (tail != null && tail.owner &&
491
488
remainingByteCount + tail.limit - (if (tail.shared) 0 else tail.pos) <= Segment .SIZE
492
489
) {
@@ -498,22 +495,32 @@ public class Buffer : Source, Sink {
498
495
} else {
499
496
// We're going to need another segment. Split the source's head
500
497
// segment in two, then move the first of those two to this buffer.
501
- source.head = source.head!! .split(remainingByteCount.toInt())
498
+ val newHead = source.head!! .split(remainingByteCount.toInt())
499
+ if (source.head == = source.tail) {
500
+ source.tail = newHead
501
+ }
502
+ source.head = newHead
502
503
}
503
504
}
504
505
505
506
// Remove the source's head segment and append it to our tail.
506
507
val segmentToMove = source.head
507
508
val movedByteCount = (segmentToMove!! .limit - segmentToMove.pos).toLong()
508
509
source.head = segmentToMove.pop()
510
+ if (source.head == null ) {
511
+ source.tail = null
512
+ }
509
513
if (head == null ) {
510
514
head = segmentToMove
511
- segmentToMove.prev = segmentToMove
512
- segmentToMove.next = segmentToMove.prev
515
+ tail = segmentToMove
516
+ segmentToMove.prev = null
517
+ segmentToMove.next = null
513
518
} else {
514
- var tail = head!! .prev
515
- tail = tail!! .push(segmentToMove)
516
- tail.compact()
519
+ val newTail = tail!! .push(segmentToMove).compact()
520
+ tail = newTail
521
+ if (newTail.prev == null ) {
522
+ this .head = newTail
523
+ }
517
524
}
518
525
source.size - = movedByteCount
519
526
size + = movedByteCount
@@ -582,16 +589,15 @@ public class Buffer : Source, Sink {
582
589
val result = Buffer ()
583
590
if (size == 0L ) return result
584
591
585
- val head = head!!
592
+ val head = this . head!!
586
593
val headCopy = head.sharedCopy()
587
594
588
595
result.head = headCopy
589
- headCopy.prev = result.head
590
- headCopy.next = headCopy.prev
596
+ result.tail = headCopy
591
597
592
598
var s = head.next
593
- while (s != = head ) {
594
- headCopy.prev !! .push(s!! .sharedCopy())
599
+ while (s != null ) {
600
+ result.tail = result.tail !! .push(s.sharedCopy())
595
601
s = s.next
596
602
}
597
603
@@ -642,6 +648,48 @@ public class Buffer : Source, Sink {
642
648
643
649
return " Buffer(size=$size hex=$builder )"
644
650
}
651
+
652
+ /* *
653
+ * Unlinks and recycles this buffer's head.
654
+ *
655
+ * If head had a successor, it'll become a new head.
656
+ * Otherwise, both [head] and [tail] will be set to null.
657
+ *
658
+ * It's up to a caller to ensure that the head exists.
659
+ */
660
+ internal fun recycleHead () {
661
+ val oldHead = head!!
662
+ val nextHead = oldHead.next
663
+ head = nextHead
664
+ if (nextHead == null ) {
665
+ tail = null
666
+ } else {
667
+ nextHead.prev = null
668
+ }
669
+ oldHead.next = null
670
+ SegmentPool .recycle(oldHead)
671
+ }
672
+
673
+ /* *
674
+ * Unlinks and recycles this buffer's tail segment.
675
+ *
676
+ * If tail had a predecessor, it'll become a new tail.
677
+ * Otherwise, both [head] and [tail] will be set to null.
678
+ *
679
+ * It's up to a caller to ensure that the tail exists.
680
+ */
681
+ internal fun recycleTail () {
682
+ val oldTail = tail!!
683
+ val newTail = oldTail.prev
684
+ tail = newTail
685
+ if (newTail == null ) {
686
+ head = null
687
+ } else {
688
+ newTail.next = null
689
+ }
690
+ oldTail.prev = null
691
+ SegmentPool .recycle(oldTail)
692
+ }
645
693
}
646
694
647
695
/* *
@@ -652,23 +700,26 @@ internal inline fun <T> Buffer.seek(
652
700
fromIndex : Long ,
653
701
lambda : (Segment ? , Long ) -> T
654
702
): T {
655
- var s : Segment = head ? : return lambda(null , - 1L )
703
+ if ( this .head == null ) lambda(null , - 1L )
656
704
657
705
if (size - fromIndex < fromIndex) {
706
+ var s = tail
658
707
// We're scanning in the back half of this buffer. Find the segment starting at the back.
659
708
var offset = size
660
- while (offset > fromIndex) {
661
- s = s.prev!!
709
+ while (s != null && offset > fromIndex) {
662
710
offset - = (s.limit - s.pos).toLong()
711
+ if (offset <= fromIndex) break
712
+ s = s.prev
663
713
}
664
714
return lambda(s, offset)
665
715
} else {
716
+ var s = this .head
666
717
// We're scanning in the front half of this buffer. Find the segment starting at the front.
667
718
var offset = 0L
668
- while (true ) {
719
+ while (s != null ) {
669
720
val nextOffset = offset + (s.limit - s.pos)
670
721
if (nextOffset > fromIndex) break
671
- s = s.next!!
722
+ s = s.next
672
723
offset = nextOffset
673
724
}
674
725
return lambda(s, offset)
0 commit comments