13c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller/* 23c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Copyright (C) 2014 Square, Inc. 33c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 43c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Licensed under the Apache License, Version 2.0 (the "License"); 53c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * you may not use this file except in compliance with the License. 63c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * You may obtain a copy of the License at 73c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 83c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * http://www.apache.org/licenses/LICENSE-2.0 93c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Unless required by applicable law or agreed to in writing, software 113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * distributed under the License is distributed on an "AS IS" BASIS, 123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * See the License for the specific language governing permissions and 143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * limitations under the License. 153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerpackage okio; 173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.io.EOFException; 19c6bd683320121544811f481709b3fdbcbe9b3866Neil Fullerimport java.io.IOException; 203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.io.InputStream; 213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.io.OutputStream; 223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.security.MessageDigest; 233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.security.NoSuchAlgorithmException; 243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.ArrayList; 253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.Collections; 263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.List; 273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static okio.Util.UTF_8; 293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static okio.Util.checkOffsetAndCount; 30c6bd683320121544811f481709b3fdbcbe9b3866Neil Fullerimport static okio.Util.reverseBytesLong; 313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller/** 333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * A collection of bytes in memory. 343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * <p><strong>Moving data from one OkBuffer to another is fast.</strong> Instead 363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * of copying bytes from one place in memory to another, this class just changes 37c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller * ownership of the underlying byte arrays. 383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * <p><strong>This buffer grows with your data.</strong> Just like ArrayList, 403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * each OkBuffer starts small. It consumes only the memory it needs to. 413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * <p><strong>This buffer pools its byte arrays.</strong> When you allocate a 433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * byte array in Java, the runtime must zero-fill the requested array before 443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * returning it to you. Even if you're going to write over that space anyway. 453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * This class avoids zero-fill and GC churn by pooling byte arrays. 463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerpublic final class OkBuffer implements BufferedSource, BufferedSink, Cloneable { 483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment head; 493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller long size; 503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public OkBuffer() { 523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** Returns the number of bytes currently in this buffer. */ 553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public long size() { 563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return size; 573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public OkBuffer buffer() { 603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return this; 613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public OutputStream outputStream() { 643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return new OutputStream() { 653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void write(int b) { 663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller writeByte((byte) b); 673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void write(byte[] data, int offset, int byteCount) { 703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer.this.write(data, offset, byteCount); 713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void flush() { 743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void close() { 773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public String toString() { 803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return this + ".outputStream()"; 813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller }; 833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public OkBuffer emitCompleteSegments() { 863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return this; // Nowhere to emit to! 873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public boolean exhausted() { 903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return size == 0; 913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void require(long byteCount) throws EOFException { 943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (this.size < byteCount) throw new EOFException(); 953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public InputStream inputStream() { 983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return new InputStream() { 993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public int read() { 1003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return readByte() & 0xff; 1013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public int read(byte[] sink, int offset, int byteCount) { 1043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return OkBuffer.this.read(sink, offset, byteCount); 1053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public int available() { 1083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return (int) Math.min(size, Integer.MAX_VALUE); 1093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void close() { 1123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public String toString() { 1153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return OkBuffer.this + ".inputStream()"; 1163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller }; 1183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 1213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Returns the number of bytes in segments that are not writable. This is the 1223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * number of bytes that can be flushed immediately to an underlying sink 1233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * without harming throughput. 1243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 1253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public long completeSegmentByteCount() { 1263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller long result = size; 1273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (result == 0) return 0; 1283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Omit the tail if it's still writable. 1303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment tail = head.prev; 1313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (tail.limit < Segment.SIZE) { 1323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller result -= tail.limit - tail.pos; 1333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return result; 1363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public byte readByte() { 1393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (size == 0) throw new IllegalStateException("size == 0"); 1403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment segment = head; 1423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int pos = segment.pos; 1433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int limit = segment.limit; 1443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller byte[] data = segment.data; 1463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller byte b = data[pos++]; 1473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller size -= 1; 1483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (pos == limit) { 1503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller head = segment.pop(); 1513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller SegmentPool.INSTANCE.recycle(segment); 1523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else { 1533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller segment.pos = pos; 1543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return b; 1573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 159c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller /** Returns the byte at {@code pos}. */ 160c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller public byte getByte(long pos) { 161c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller checkOffsetAndCount(size, pos, 1); 1623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller for (Segment s = head; true; s = s.next) { 1633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int segmentByteCount = s.limit - s.pos; 164c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller if (pos < segmentByteCount) return s.data[s.pos + (int) pos]; 165c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller pos -= segmentByteCount; 1663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public short readShort() { 170c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller if (size < 2) throw new IllegalStateException("size < 2: " + size); 1713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment segment = head; 1733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int pos = segment.pos; 1743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int limit = segment.limit; 1753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // If the short is split across multiple segments, delegate to readByte(). 1773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (limit - pos < 2) { 1783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int s = (readByte() & 0xff) << 8 1793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller | (readByte() & 0xff); 1803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return (short) s; 1813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller byte[] data = segment.data; 1843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int s = (data[pos++] & 0xff) << 8 1853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller | (data[pos++] & 0xff); 1863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller size -= 2; 1873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (pos == limit) { 1893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller head = segment.pop(); 1903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller SegmentPool.INSTANCE.recycle(segment); 1913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else { 1923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller segment.pos = pos; 1933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return (short) s; 1963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public int readInt() { 199c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller if (size < 4) throw new IllegalStateException("size < 4: " + size); 2003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment segment = head; 2023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int pos = segment.pos; 2033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int limit = segment.limit; 2043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // If the int is split across multiple segments, delegate to readByte(). 2063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (limit - pos < 4) { 2073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return (readByte() & 0xff) << 24 2083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller | (readByte() & 0xff) << 16 209c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller | (readByte() & 0xff) << 8 2103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller | (readByte() & 0xff); 2113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller byte[] data = segment.data; 2143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int i = (data[pos++] & 0xff) << 24 2153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller | (data[pos++] & 0xff) << 16 216c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller | (data[pos++] & 0xff) << 8 2173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller | (data[pos++] & 0xff); 2183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller size -= 4; 2193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (pos == limit) { 2213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller head = segment.pop(); 2223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller SegmentPool.INSTANCE.recycle(segment); 2233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else { 2243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller segment.pos = pos; 2253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return i; 2283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 230c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller @Override public long readLong() { 231c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller if (size < 8) throw new IllegalStateException("size < 8: " + size); 232c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 233c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller Segment segment = head; 234c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller int pos = segment.pos; 235c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller int limit = segment.limit; 236c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 237c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller // If the long is split across multiple segments, delegate to readInt(). 238c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller if (limit - pos < 8) { 239c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller return (readInt() & 0xffffffffL) << 32 240c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller | (readInt() & 0xffffffffL); 241c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller } 242c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 243c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller byte[] data = segment.data; 244c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller long v = (data[pos++] & 0xffL) << 56 245c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller | (data[pos++] & 0xffL) << 48 246c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller | (data[pos++] & 0xffL) << 40 247c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller | (data[pos++] & 0xffL) << 32 248c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller | (data[pos++] & 0xffL) << 24 249c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller | (data[pos++] & 0xffL) << 16 250c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller | (data[pos++] & 0xffL) << 8 251c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller | (data[pos++] & 0xffL); 252c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller size -= 8; 253c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 254c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller if (pos == limit) { 255c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller head = segment.pop(); 256c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller SegmentPool.INSTANCE.recycle(segment); 257c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller } else { 258c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller segment.pos = pos; 259c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller } 260c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 261c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller return v; 262c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller } 263c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 264c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller @Override public short readShortLe() { 2653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return Util.reverseBytesShort(readShort()); 2663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 268c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller @Override public int readIntLe() { 2693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return Util.reverseBytesInt(readInt()); 2703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 272c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller @Override public long readLongLe() { 273c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller return Util.reverseBytesLong(readLong()); 274c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller } 275c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 276c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller @Override public ByteString readByteString(long byteCount) { 2773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return new ByteString(readBytes(byteCount)); 2783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 280c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller @Override public String readUtf8(long byteCount) { 2813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller checkOffsetAndCount(this.size, 0, byteCount); 2823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (byteCount > Integer.MAX_VALUE) { 2833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller throw new IllegalArgumentException("byteCount > Integer.MAX_VALUE: " + byteCount); 2843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (byteCount == 0) return ""; 2863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment head = this.head; 2883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (head.pos + byteCount > head.limit) { 2893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // If the string spans multiple segments, delegate to readBytes(). 2903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return new String(readBytes(byteCount), Util.UTF_8); 2913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String result = new String(head.data, head.pos, (int) byteCount, UTF_8); 2943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller head.pos += byteCount; 2953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.size -= byteCount; 2963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (head.pos == head.limit) { 2983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.head = head.pop(); 2993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller SegmentPool.INSTANCE.recycle(head); 3003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 3013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return result; 3033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 3043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 305c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller @Override public String readUtf8Line() throws IOException { 3063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller long newline = indexOf((byte) '\n'); 3073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (newline == -1) { 3093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return size != 0 ? readUtf8(size) : null; 3103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 3113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 312c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller return readUtf8Line(newline); 313c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller } 314c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 315c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller @Override public String readUtf8LineStrict() throws IOException { 316c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller long newline = indexOf((byte) '\n'); 317c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller if (newline == -1) throw new EOFException(); 318c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller return readUtf8Line(newline); 319c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller } 320c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 321c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller String readUtf8Line(long newline) { 3223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (newline > 0 && getByte(newline - 1) == '\r') { 3233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Read everything until '\r\n', then skip the '\r\n'. 3243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String result = readUtf8((newline - 1)); 3253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller skip(2); 3263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return result; 3273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else { 3293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Read everything until '\n', then skip the '\n'. 3303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String result = readUtf8(newline); 3313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller skip(1); 3323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return result; 3333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 3343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 3353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private byte[] readBytes(long byteCount) { 3373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller checkOffsetAndCount(this.size, 0, byteCount); 3383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (byteCount > Integer.MAX_VALUE) { 3393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller throw new IllegalArgumentException("byteCount > Integer.MAX_VALUE: " + byteCount); 3403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 3413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int offset = 0; 3433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller byte[] result = new byte[(int) byteCount]; 3443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller while (offset < byteCount) { 3463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int toCopy = (int) Math.min(byteCount - offset, head.limit - head.pos); 3473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller System.arraycopy(head.data, head.pos, result, offset, toCopy); 3483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller offset += toCopy; 3503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller head.pos += toCopy; 3513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (head.pos == head.limit) { 3533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment toRecycle = head; 3543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller head = toRecycle.pop(); 3553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller SegmentPool.INSTANCE.recycle(toRecycle); 3563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 3573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 3583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.size -= byteCount; 3603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return result; 3613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 3623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** Like {@link InputStream#read}. */ 3643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int read(byte[] sink, int offset, int byteCount) { 3653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment s = this.head; 366c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller if (s == null) return -1; 3673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int toCopy = Math.min(byteCount, s.limit - s.pos); 3683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller System.arraycopy(s.data, s.pos, sink, offset, toCopy); 3693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller s.pos += toCopy; 3713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.size -= toCopy; 3723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (s.pos == s.limit) { 3743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.head = s.pop(); 3753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller SegmentPool.INSTANCE.recycle(s); 3763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 3773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return toCopy; 3793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 3803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 3823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Discards all bytes in this buffer. Calling this method when you're done 3833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * with a buffer will return its segments to the pool. 3843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 3853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public void clear() { 3863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller skip(size); 3873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 3883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** Discards {@code byteCount} bytes from the head of this buffer. */ 390c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller @Override public void skip(long byteCount) { 3913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller checkOffsetAndCount(this.size, 0, byteCount); 3923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.size -= byteCount; 3943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller while (byteCount > 0) { 3953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int toSkip = (int) Math.min(byteCount, head.limit - head.pos); 3963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller byteCount -= toSkip; 3973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller head.pos += toSkip; 3983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (head.pos == head.limit) { 4003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment toRecycle = head; 4013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller head = toRecycle.pop(); 4023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller SegmentPool.INSTANCE.recycle(toRecycle); 4033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 4043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 4053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 4063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 4073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public OkBuffer write(ByteString byteString) { 4083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return write(byteString.data, 0, byteString.data.length); 4093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 4103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 4113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public OkBuffer writeUtf8(String string) { 412c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller // TODO: inline UTF-8 encoding to save allocating a byte[]? 4133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller byte[] data = string.getBytes(Util.UTF_8); 4143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return write(data, 0, data.length); 4153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 4163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 4173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public OkBuffer write(byte[] source) { 4183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return write(source, 0, source.length); 4193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 4203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 4213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public OkBuffer write(byte[] source, int offset, int byteCount) { 4223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int limit = offset + byteCount; 4233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller while (offset < limit) { 4243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment tail = writableSegment(1); 4253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 4263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int toCopy = Math.min(limit - offset, Segment.SIZE - tail.limit); 4273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller System.arraycopy(source, offset, tail.data, tail.limit, toCopy); 4283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 4293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller offset += toCopy; 4303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller tail.limit += toCopy; 4313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 4323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 4333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.size += byteCount; 4343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return this; 4353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 4363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 4373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public OkBuffer writeByte(int b) { 4383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment tail = writableSegment(1); 4393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller tail.data[tail.limit++] = (byte) b; 4403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller size += 1; 4413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return this; 4423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 4433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 4443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public OkBuffer writeShort(int s) { 4453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment tail = writableSegment(2); 4463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller byte[] data = tail.data; 4473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int limit = tail.limit; 448c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller data[limit++] = (byte) ((s >>> 8) & 0xff); 449c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller data[limit++] = (byte) (s & 0xff); 4503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller tail.limit = limit; 4513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller size += 2; 4523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return this; 4533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 4543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 455c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller @Override public BufferedSink writeShortLe(int s) { 456c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller return writeShort(Util.reverseBytesShort((short) s)); 457c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller } 458c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 4593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public OkBuffer writeInt(int i) { 4603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment tail = writableSegment(4); 4613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller byte[] data = tail.data; 4623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int limit = tail.limit; 463c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller data[limit++] = (byte) ((i >>> 24) & 0xff); 464c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller data[limit++] = (byte) ((i >>> 16) & 0xff); 465c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller data[limit++] = (byte) ((i >>> 8) & 0xff); 466c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller data[limit++] = (byte) (i & 0xff); 4673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller tail.limit = limit; 4683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller size += 4; 4693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return this; 4703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 4713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 472c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller @Override public BufferedSink writeIntLe(int i) { 473c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller return writeInt(Util.reverseBytesInt(i)); 474c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller } 475c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 476c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller @Override public OkBuffer writeLong(long v) { 477c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller Segment tail = writableSegment(8); 478c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller byte[] data = tail.data; 479c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller int limit = tail.limit; 480c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller data[limit++] = (byte) ((v >>> 56L) & 0xff); 481c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller data[limit++] = (byte) ((v >>> 48L) & 0xff); 482c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller data[limit++] = (byte) ((v >>> 40L) & 0xff); 483c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller data[limit++] = (byte) ((v >>> 32L) & 0xff); 484c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller data[limit++] = (byte) ((v >>> 24L) & 0xff); 485c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller data[limit++] = (byte) ((v >>> 16L) & 0xff); 486c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller data[limit++] = (byte) ((v >>> 8L) & 0xff); 487c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller data[limit++] = (byte) (v & 0xff); 488c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller tail.limit = limit; 489c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller size += 8; 490c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller return this; 491c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller } 492c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 493c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller @Override public BufferedSink writeLongLe(long v) { 494c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller return writeLong(reverseBytesLong(v)); 495c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller } 496c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 4973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 4983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Returns a tail segment that we can write at least {@code minimumCapacity} 4993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * bytes to, creating it if necessary. 5003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 5013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment writableSegment(int minimumCapacity) { 5023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (minimumCapacity < 1 || minimumCapacity > Segment.SIZE) throw new IllegalArgumentException(); 5033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 5043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (head == null) { 5053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller head = SegmentPool.INSTANCE.take(); // Acquire a first segment. 5063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return head.next = head.prev = head; 5073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 5083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 5093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment tail = head.prev; 5103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (tail.limit + minimumCapacity > Segment.SIZE) { 5113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller tail = tail.push(SegmentPool.INSTANCE.take()); // Append a new empty segment to fill up. 5123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 5133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return tail; 5143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 5153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 5163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void write(OkBuffer source, long byteCount) { 5173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Move bytes from the head of the source buffer to the tail of this buffer 5183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // while balancing two conflicting goals: don't waste CPU and don't waste 5193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // memory. 5203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // 5213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // 5223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Don't waste CPU (ie. don't copy data around). 5233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // 5243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Copying large amounts of data is expensive. Instead, we prefer to 5253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // reassign entire segments from one OkBuffer to the other. 5263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // 5273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // 5283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Don't waste memory. 5293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // 5303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // As an invariant, adjacent pairs of segments in an OkBuffer should be at 5313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // least 50% full, except for the head segment and the tail segment. 5323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // 5333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // The head segment cannot maintain the invariant because the application is 5343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // consuming bytes from this segment, decreasing its level. 5353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // 5363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // The tail segment cannot maintain the invariant because the application is 5373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // producing bytes, which may require new nearly-empty tail segments to be 5383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // appended. 5393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // 5403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // 5413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Moving segments between buffers 5423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // 5433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // When writing one buffer to another, we prefer to reassign entire segments 5443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // over copying bytes into their most compact form. Suppose we have a buffer 5453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // with these segment levels [91%, 61%]. If we append a buffer with a 5463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // single [72%] segment, that yields [91%, 61%, 72%]. No bytes are copied. 5473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // 5483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Or suppose we have a buffer with these segment levels: [100%, 2%], and we 5493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // want to append it to a buffer with these segment levels [99%, 3%]. This 5503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // operation will yield the following segments: [100%, 2%, 99%, 3%]. That 5513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // is, we do not spend time copying bytes around to achieve more efficient 5523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // memory use like [100%, 100%, 4%]. 5533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // 5543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // When combining buffers, we will compact adjacent buffers when their 5553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // combined level doesn't exceed 100%. For example, when we start with 5563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // [100%, 40%] and append [30%, 80%], the result is [100%, 70%, 80%]. 5573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // 5583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // 5593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Splitting segments 5603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // 5613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Occasionally we write only part of a source buffer to a sink buffer. For 5623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // example, given a sink [51%, 91%], we may want to write the first 30% of 5633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // a source [92%, 82%] to it. To simplify, we first transform the source to 5643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // an equivalent buffer [30%, 62%, 82%] and then move the head segment, 5653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // yielding sink [51%, 91%, 30%] and source [62%, 82%]. 5663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 5673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (source == this) { 5683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller throw new IllegalArgumentException("source == this"); 5693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 5703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller checkOffsetAndCount(source.size, 0, byteCount); 5713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 5723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller while (byteCount > 0) { 5733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Is a prefix of the source's head segment all that we need to move? 5743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (byteCount < (source.head.limit - source.head.pos)) { 5753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment tail = head != null ? head.prev : null; 5763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (tail == null || byteCount + (tail.limit - tail.pos) > Segment.SIZE) { 5773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // We're going to need another segment. Split the source's head 5783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // segment in two, then move the first of those two to this buffer. 5793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller source.head = source.head.split((int) byteCount); 5803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else { 5813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Our existing segments are sufficient. Move bytes from source's head to our tail. 5823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller source.head.writeTo(tail, (int) byteCount); 5833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller source.size -= byteCount; 5843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.size += byteCount; 5853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return; 5863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 5873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 5883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 5893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Remove the source's head segment and append it to our tail. 5903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment segmentToMove = source.head; 5913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller long movedByteCount = segmentToMove.limit - segmentToMove.pos; 5923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller source.head = segmentToMove.pop(); 5933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (head == null) { 5943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller head = segmentToMove; 5953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller head.next = head.prev = head; 5963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else { 5973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment tail = head.prev; 5983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller tail = tail.push(segmentToMove); 5993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller tail.compact(); 6003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller source.size -= movedByteCount; 6023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.size += movedByteCount; 6033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller byteCount -= movedByteCount; 6043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 6073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public long read(OkBuffer sink, long byteCount) { 6083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (this.size == 0) return -1L; 6093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (byteCount > this.size) byteCount = this.size; 6103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller sink.write(this, byteCount); 6113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return byteCount; 6123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 6143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public OkBuffer deadline(Deadline deadline) { 6153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // All operations are in memory so this class doesn't need to honor deadlines. 6163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return this; 6173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 619c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller @Override public long indexOf(byte b) { 6203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return indexOf(b, 0); 6213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 6233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 6243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Returns the index of {@code b} in this at or beyond {@code fromIndex}, or 6253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * -1 if this buffer does not contain {@code b} in that range. 6263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 6273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public long indexOf(byte b, long fromIndex) { 6283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment s = head; 6293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (s == null) return -1L; 6303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller long offset = 0L; 6313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller do { 6323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int segmentByteCount = s.limit - s.pos; 6333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (fromIndex > segmentByteCount) { 6343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller fromIndex -= segmentByteCount; 6353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else { 6363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller byte[] data = s.data; 6373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller for (long pos = s.pos + fromIndex, limit = s.limit; pos < limit; pos++) { 6383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (data[(int) pos] == b) return offset + pos - s.pos; 6393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller fromIndex = 0; 6413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller offset += segmentByteCount; 6433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller s = s.next; 6443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } while (s != head); 6453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return -1L; 6463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 6483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void flush() { 6493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 6513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void close() { 6523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 6543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** For testing. This returns the sizes of the segments in this buffer. */ 6553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller List<Integer> segmentSizes() { 6563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (head == null) return Collections.emptyList(); 6573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller List<Integer> result = new ArrayList<Integer>(); 6583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller result.add(head.limit - head.pos); 6593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller for (Segment s = head.next; s != head; s = s.next) { 6603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller result.add(s.limit - s.pos); 6613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return result; 6633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 6653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public boolean equals(Object o) { 6663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (!(o instanceof OkBuffer)) return false; 6673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer that = (OkBuffer) o; 6683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (size != that.size) return false; 6693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (size == 0) return true; // Both buffers are empty. 6703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 6713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment sa = this.head; 6723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment sb = that.head; 6733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int posA = sa.pos; 6743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int posB = sb.pos; 6753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 6763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller for (long pos = 0, count; pos < size; pos += count) { 6773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller count = Math.min(sa.limit - posA, sb.limit - posB); 6783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 6793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller for (int i = 0; i < count; i++) { 6803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (sa.data[posA++] != sb.data[posB++]) return false; 6813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 6833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (posA == sa.limit) { 6843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller sa = sa.next; 6853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller posA = sa.pos; 6863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 6883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (posB == sb.limit) { 6893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller sb = sb.next; 6903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller posB = sb.pos; 6913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 6943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return true; 6953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 6963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 6973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public int hashCode() { 6983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment s = head; 6993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (s == null) return 0; 7003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int result = 1; 7013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller do { 7023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller for (int pos = s.pos, limit = s.limit; pos < limit; pos++) { 7033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller result = 31 * result + s.data[pos]; 7043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 7053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller s = s.next; 7063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } while (s != head); 7073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return result; 7083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 7093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 7103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public String toString() { 7113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (size == 0) { 7123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return "OkBuffer[size=0]"; 7133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 7143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 7153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (size <= 16) { 7163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller ByteString data = clone().readByteString(size); 7173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return String.format("OkBuffer[size=%s data=%s]", size, data.hex()); 7183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 7193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 7203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller try { 7213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller MessageDigest md5 = MessageDigest.getInstance("MD5"); 7223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller md5.update(head.data, head.pos, head.limit - head.pos); 7233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller for (Segment s = head.next; s != head; s = s.next) { 7243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller md5.update(s.data, s.pos, s.limit - s.pos); 7253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 7263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return String.format("OkBuffer[size=%s md5=%s]", 7273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller size, ByteString.of(md5.digest()).hex()); 7283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } catch (NoSuchAlgorithmException e) { 7293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller throw new AssertionError(); 7303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 7313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 7323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 7333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** Returns a deep copy of this buffer. */ 7343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public OkBuffer clone() { 7353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer result = new OkBuffer(); 7363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (size() == 0) return result; 7373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 7383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller result.write(head.data, head.pos, head.limit - head.pos); 7393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller for (Segment s = head.next; s != head; s = s.next) { 7403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller result.write(s.data, s.pos, s.limit - s.pos); 7413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 7423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 7433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return result; 7443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 7453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller} 746