@@ -89,7 +89,7 @@ public long size() {
89
89
return this ; // Nowhere to emit to!
90
90
}
91
91
92
- @ Override public BufferedSink emit () throws IOException {
92
+ @ Override public BufferedSink emit () {
93
93
return this ; // Nowhere to emit to!
94
94
}
95
95
@@ -101,7 +101,7 @@ public long size() {
101
101
if (size < byteCount ) throw new EOFException ();
102
102
}
103
103
104
- @ Override public boolean request (long byteCount ) throws IOException {
104
+ @ Override public boolean request (long byteCount ) {
105
105
return size >= byteCount ;
106
106
}
107
107
@@ -167,30 +167,26 @@ public Buffer copyTo(Buffer out, long offset, long byteCount) {
167
167
checkOffsetAndCount (size , offset , byteCount );
168
168
if (byteCount == 0 ) return this ;
169
169
170
- Segment source = head ;
171
- Segment target = out .writableSegment (1 );
172
170
out .size += byteCount ;
173
171
174
- while (byteCount > 0 ) {
175
- // If necessary, advance to a readable source segment. This won't repeat after the first copy.
176
- while (offset >= source .limit - source .pos ) {
177
- offset -= (source .limit - source .pos );
178
- source = source .next ;
179
- }
172
+ // Skip segments that we aren't copying from.
173
+ Segment s = head ;
174
+ for (; offset >= (s .limit - s .pos ); s = s .next ) {
175
+ offset -= (s .limit - s .pos );
176
+ }
180
177
181
- // If necessary, append another target segment.
182
- if (target .limit == Segment .SIZE ) {
183
- target = target .push (SegmentPool .INSTANCE .take ());
178
+ // Copy one segment at a time.
179
+ for (; byteCount > 0 ; s = s .next ) {
180
+ Segment copy = new Segment (s );
181
+ copy .pos += offset ;
182
+ copy .limit = Math .min (copy .pos + (int ) byteCount , copy .limit );
183
+ if (out .head == null ) {
184
+ out .head = copy .next = copy .prev = copy ;
185
+ } else {
186
+ out .head .prev .push (copy );
184
187
}
185
-
186
- // Copy bytes from the source segment to the target segment.
187
- long sourceReadable = Math .min (source .limit - (source .pos + offset ), byteCount );
188
- long targetWritable = Segment .SIZE - target .limit ;
189
- int toCopy = (int ) Math .min (sourceReadable , targetWritable );
190
- System .arraycopy (source .data , source .pos + (int ) offset , target .data , target .limit , toCopy );
191
- offset += toCopy ;
192
- target .limit += toCopy ;
193
- byteCount -= toCopy ;
188
+ byteCount -= copy .limit - copy .pos ;
189
+ offset = 0 ;
194
190
}
195
191
196
192
return this ;
@@ -218,7 +214,7 @@ public Buffer writeTo(OutputStream out, long byteCount) throws IOException {
218
214
if (s .pos == s .limit ) {
219
215
Segment toRecycle = s ;
220
216
head = s = toRecycle .pop ();
221
- SegmentPool .INSTANCE . recycle (toRecycle );
217
+ SegmentPool .recycle (toRecycle );
222
218
}
223
219
}
224
220
@@ -265,7 +261,7 @@ public long completeSegmentByteCount() {
265
261
266
262
// Omit the tail if it's still writable.
267
263
Segment tail = head .prev ;
268
- if (tail .limit < Segment .SIZE ) {
264
+ if (tail .limit < Segment .SIZE && tail . owner ) {
269
265
result -= tail .limit - tail .pos ;
270
266
}
271
267
@@ -285,7 +281,7 @@ public long completeSegmentByteCount() {
285
281
286
282
if (pos == limit ) {
287
283
head = segment .pop ();
288
- SegmentPool .INSTANCE . recycle (segment );
284
+ SegmentPool .recycle (segment );
289
285
} else {
290
286
segment .pos = pos ;
291
287
}
@@ -324,7 +320,7 @@ public byte getByte(long pos) {
324
320
325
321
if (pos == limit ) {
326
322
head = segment .pop ();
327
- SegmentPool .INSTANCE . recycle (segment );
323
+ SegmentPool .recycle (segment );
328
324
} else {
329
325
segment .pos = pos ;
330
326
}
@@ -356,7 +352,7 @@ public byte getByte(long pos) {
356
352
357
353
if (pos == limit ) {
358
354
head = segment .pop ();
359
- SegmentPool .INSTANCE . recycle (segment );
355
+ SegmentPool .recycle (segment );
360
356
} else {
361
357
segment .pos = pos ;
362
358
}
@@ -390,7 +386,7 @@ public byte getByte(long pos) {
390
386
391
387
if (pos == limit ) {
392
388
head = segment .pop ();
393
- SegmentPool .INSTANCE . recycle (segment );
389
+ SegmentPool .recycle (segment );
394
390
} else {
395
391
segment .pos = pos ;
396
392
}
@@ -588,7 +584,7 @@ public byte getByte(long pos) {
588
584
589
585
if (s .pos == s .limit ) {
590
586
head = s .pop ();
591
- SegmentPool .INSTANCE . recycle (s );
587
+ SegmentPool .recycle (s );
592
588
}
593
589
594
590
return result ;
@@ -675,7 +671,7 @@ String readUtf8Line(long newline) throws EOFException {
675
671
676
672
if (s .pos == s .limit ) {
677
673
head = s .pop ();
678
- SegmentPool .INSTANCE . recycle (s );
674
+ SegmentPool .recycle (s );
679
675
}
680
676
681
677
return toCopy ;
@@ -706,14 +702,15 @@ public void clear() {
706
702
if (head .pos == head .limit ) {
707
703
Segment toRecycle = head ;
708
704
head = toRecycle .pop ();
709
- SegmentPool .INSTANCE . recycle (toRecycle );
705
+ SegmentPool .recycle (toRecycle );
710
706
}
711
707
}
712
708
}
713
709
714
710
@ Override public Buffer write (ByteString byteString ) {
715
711
if (byteString == null ) throw new IllegalArgumentException ("byteString == null" );
716
- return write (byteString .data , 0 , byteString .data .length );
712
+ byteString .write (this );
713
+ return this ;
717
714
}
718
715
719
716
@ Override public Buffer writeUtf8 (String string ) {
@@ -977,13 +974,13 @@ Segment writableSegment(int minimumCapacity) {
977
974
if (minimumCapacity < 1 || minimumCapacity > Segment .SIZE ) throw new IllegalArgumentException ();
978
975
979
976
if (head == null ) {
980
- head = SegmentPool .INSTANCE . take (); // Acquire a first segment.
977
+ head = SegmentPool .take (); // Acquire a first segment.
981
978
return head .next = head .prev = head ;
982
979
}
983
980
984
981
Segment tail = head .prev ;
985
- if (tail .limit + minimumCapacity > Segment .SIZE ) {
986
- tail = tail .push (SegmentPool .INSTANCE . take ()); // Append a new empty segment to fill up.
982
+ if (tail .limit + minimumCapacity > Segment .SIZE || ! tail . owner ) {
983
+ tail = tail .push (SegmentPool .take ()); // Append a new empty segment to fill up.
987
984
}
988
985
return tail ;
989
986
}
@@ -1047,16 +1044,17 @@ Segment writableSegment(int minimumCapacity) {
1047
1044
// Is a prefix of the source's head segment all that we need to move?
1048
1045
if (byteCount < (source .head .limit - source .head .pos )) {
1049
1046
Segment tail = head != null ? head .prev : null ;
1050
- if (tail == null || byteCount + (tail .limit - tail .pos ) > Segment .SIZE ) {
1051
- // We're going to need another segment. Split the source's head
1052
- // segment in two, then move the first of those two to this buffer.
1053
- source .head = source .head .split ((int ) byteCount );
1054
- } else {
1047
+ if (tail != null && tail .owner
1048
+ && (byteCount + tail .limit - (tail .shared ? 0 : tail .pos ) <= Segment .SIZE )) {
1055
1049
// Our existing segments are sufficient. Move bytes from source's head to our tail.
1056
1050
source .head .writeTo (tail , (int ) byteCount );
1057
1051
source .size -= byteCount ;
1058
1052
size += byteCount ;
1059
1053
return ;
1054
+ } else {
1055
+ // We're going to need another segment. Split the source's head
1056
+ // segment in two, then move the first of those two to this buffer.
1057
+ source .head = source .head .split ((int ) byteCount );
1060
1058
}
1061
1059
}
1062
1060
@@ -1128,7 +1126,7 @@ Segment writableSegment(int minimumCapacity) {
1128
1126
Segment s = head ;
1129
1127
if (s == null ) return -1L ;
1130
1128
long offset = 0L ;
1131
- byte [] toFind = targetBytes .data ;
1129
+ byte [] toFind = targetBytes .toByteArray () ;
1132
1130
do {
1133
1131
int segmentByteCount = s .limit - s .pos ;
1134
1132
if (fromIndex >= segmentByteCount ) {
@@ -1244,11 +1242,28 @@ List<Integer> segmentSizes() {
1244
1242
Buffer result = new Buffer ();
1245
1243
if (size == 0 ) return result ;
1246
1244
1247
- result .write (head .data , head .pos , head .limit - head .pos );
1245
+ result .head = new Segment (head );
1246
+ result .head .next = result .head .prev = result .head ;
1248
1247
for (Segment s = head .next ; s != head ; s = s .next ) {
1249
- result .write ( s . data , s . pos , s . limit - s . pos );
1248
+ result .head . prev . push ( new Segment ( s ) );
1250
1249
}
1251
-
1250
+ result . size = size ;
1252
1251
return result ;
1253
1252
}
1253
+
1254
+ /** Returns an immutable copy of this buffer as a byte string. */
1255
+ public ByteString snapshot () {
1256
+ if (size > Integer .MAX_VALUE ) {
1257
+ throw new IllegalArgumentException ("size > Integer.MAX_VALUE: " + size );
1258
+ }
1259
+ return snapshot ((int ) size );
1260
+ }
1261
+
1262
+ /**
1263
+ * Returns an immutable copy of the first {@code byteCount} bytes of this buffer as a byte string.
1264
+ */
1265
+ public ByteString snapshot (int byteCount ) {
1266
+ if (byteCount == 0 ) return ByteString .EMPTY ;
1267
+ return new SegmentedByteString (this , byteCount );
1268
+ }
1254
1269
}
0 commit comments