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 Fuller/** 19e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * A segment of a buffer. 203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 21a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller * <p>Each segment in a buffer is a circularly-linked list node referencing the following and 22a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller * preceding segments in the buffer. 233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 24a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller * <p>Each segment in the pool is a singly-linked list node referencing the rest of segments in the 25a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller * pool. 26a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller * 27a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller * <p>The underlying byte arrays of segments may be shared between buffers and byte strings. When a 28a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller * segment's byte array is shared the segment may not be recycled, nor may its byte data be changed. 29a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller * The lone exception is that the owner segment is allowed to append to the segment, writing data at 30a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller * {@code limit} and beyond. There is a single owning segment for each byte array. Positions, 31a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller * limits, prev, and next references are not shared. 323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerfinal class Segment { 343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** The size of all segments in bytes. */ 35147e5ea75d85f64f2b051a11ed1879dfa56050e9Thierry Strudel static final int SIZE = 8192; 363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 37a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller final byte[] data; 383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** The next byte of application data byte to read in this segment. */ 403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int pos; 413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** The first byte of available data ready to be written to. */ 433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int limit; 443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 45a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller /** True if other segments or byte strings use the same byte array. */ 46a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller boolean shared; 47a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 48a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller /** True if this segment owns the byte array and can append to it, extending {@code limit}. */ 49a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller boolean owner; 50a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** Next segment in a linked or circularly-linked list. */ 523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment next; 533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** Previous segment in a circularly-linked list. */ 553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment prev; 563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 57a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller Segment() { 58a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller this.data = new byte[SIZE]; 59a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller this.owner = true; 60a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller this.shared = false; 61a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller } 62a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 63a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller Segment(Segment shareFrom) { 64a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller this(shareFrom.data, shareFrom.pos, shareFrom.limit); 65a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller shareFrom.shared = true; 66a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller } 67a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 68a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller Segment(byte[] data, int pos, int limit) { 69a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller this.data = data; 70a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller this.pos = pos; 71a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller this.limit = limit; 72a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller this.owner = false; 73a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller this.shared = true; 74a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller } 75a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Removes this segment of a circularly-linked list and returns its successor. 783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Returns null if the list is now empty. 793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public Segment pop() { 813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment result = next != this ? next : null; 823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller prev.next = next; 833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller next.prev = prev; 843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller next = null; 853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller prev = null; 863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return result; 873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Appends {@code segment} after this segment in the circularly-linked list. 913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Returns the pushed segment. 923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public Segment push(Segment segment) { 943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller segment.prev = this; 953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller segment.next = next; 963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller next.prev = segment; 973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller next = segment; 983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return segment; 993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 1023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Splits this head of a circularly-linked list into two segments. The first 1033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * segment contains the data in {@code [pos..pos+byteCount)}. The second 1043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * segment contains the data in {@code [pos+byteCount..limit)}. This can be 105e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * useful when moving partial segments from one buffer to another. 1063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 1073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * <p>Returns the new head of the circularly-linked list. 1083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 1093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public Segment split(int byteCount) { 110a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller if (byteCount <= 0 || byteCount > limit - pos) throw new IllegalArgumentException(); 111a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller Segment prefix = new Segment(this); 112a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller prefix.limit = prefix.pos + byteCount; 113a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller pos += byteCount; 114a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller prev.push(prefix); 115a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller return prefix; 1163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 1193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Call this when the tail and its predecessor may both be less than half 1203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * full. This will copy data so that segments can be recycled. 1213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 1223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public void compact() { 1233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (prev == this) throw new IllegalStateException(); 124a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller if (!prev.owner) return; // Cannot compact: prev isn't writable. 125a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller int byteCount = limit - pos; 126a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller int availableByteCount = SIZE - prev.limit + (prev.shared ? 0 : prev.pos); 127a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller if (byteCount > availableByteCount) return; // Cannot compact: not enough writable space. 128a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller writeTo(prev, byteCount); 1293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller pop(); 130a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller SegmentPool.recycle(this); 1313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 133e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** Moves {@code byteCount} bytes from this segment to {@code sink}. */ 1343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public void writeTo(Segment sink, int byteCount) { 135a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller if (!sink.owner) throw new IllegalArgumentException(); 1363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (sink.limit + byteCount > SIZE) { 137a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller // We can't fit byteCount bytes at the sink's current position. Shift sink first. 138a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller if (sink.shared) throw new IllegalArgumentException(); 139a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller if (sink.limit + byteCount - sink.pos > SIZE) throw new IllegalArgumentException(); 1403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller System.arraycopy(sink.data, sink.pos, sink.data, 0, sink.limit - sink.pos); 1413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller sink.limit -= sink.pos; 1423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller sink.pos = 0; 1433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller System.arraycopy(data, pos, sink.data, sink.limit, byteCount); 1463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller sink.limit += byteCount; 1473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller pos += byteCount; 1483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller} 150