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/** 193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * A segment of an OkBuffer. 203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * <p>Each segment in an OkBuffer is a circularly-linked list node referencing 223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * the following and preceding segments in the buffer. 233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * <p>Each segment in the pool is a singly-linked list node referencing the rest 253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * of segments in the pool. 263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerfinal class Segment { 283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** The size of all segments in bytes. */ 293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // TODO: Using fixed-size segments makes pooling easier. But it harms memory 303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // efficiency and encourages copying. Try variable sized segments? 313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // TODO: Is 2 KiB a good default segment size? 323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller static final int SIZE = 2048; 333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller final byte[] data = new byte[SIZE]; 353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** The next byte of application data byte to read in this segment. */ 373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int pos; 383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** The first byte of available data ready to be written to. */ 403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int limit; 413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** Next segment in a linked or circularly-linked list. */ 433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment next; 443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** Previous segment in a circularly-linked list. */ 463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment prev; 473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Removes this segment of a circularly-linked list and returns its successor. 503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Returns null if the list is now empty. 513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public Segment pop() { 533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment result = next != this ? next : null; 543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller prev.next = next; 553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller next.prev = prev; 563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller next = null; 573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller prev = null; 583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return result; 593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Appends {@code segment} after this segment in the circularly-linked list. 633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Returns the pushed segment. 643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public Segment push(Segment segment) { 663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller segment.prev = this; 673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller segment.next = next; 683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller next.prev = segment; 693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller next = segment; 703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return segment; 713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Splits this head of a circularly-linked list into two segments. The first 753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * segment contains the data in {@code [pos..pos+byteCount)}. The second 763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * segment contains the data in {@code [pos+byteCount..limit)}. This can be 773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * useful when moving partial segments from one OkBuffer to another. 783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * <p>Returns the new head of the circularly-linked list. 803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public Segment split(int byteCount) { 823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int aSize = byteCount; 833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int bSize = (limit - pos) - byteCount; 843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (aSize <= 0 || bSize <= 0) throw new IllegalArgumentException(); 853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Which side of the split is larger? We want to copy as few bytes as possible. 873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (aSize < bSize) { 883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Create a segment of size 'aSize' before this segment. 893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment before = SegmentPool.INSTANCE.take(); 903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller System.arraycopy(data, pos, before.data, before.pos, aSize); 913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller pos += aSize; 923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller before.limit += aSize; 933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller prev.push(before); 943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return before; 953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else { 963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Create a new segment of size 'bSize' after this segment. 973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Segment after = SegmentPool.INSTANCE.take(); 983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller System.arraycopy(data, pos + aSize, after.data, after.pos, bSize); 993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller limit -= bSize; 1003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller after.limit += bSize; 1013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller push(after); 1023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return this; 1033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 1073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Call this when the tail and its predecessor may both be less than half 1083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * full. This will copy data so that segments can be recycled. 1093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 1103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public void compact() { 1113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (prev == this) throw new IllegalStateException(); 1123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if ((prev.limit - prev.pos) + (limit - pos) > SIZE) return; // Cannot compact. 1133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller writeTo(prev, limit - pos); 1143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller pop(); 1153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller SegmentPool.INSTANCE.recycle(this); 1163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** Moves {@code byteCount} bytes from {@code sink} to this segment. */ 1193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // TODO: if sink has fewer bytes than this, it may be cheaper to reverse the 1203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // direction of the copy and swap the segments! 1213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public void writeTo(Segment sink, int byteCount) { 1223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (byteCount + (sink.limit - sink.pos) > SIZE) throw new IllegalArgumentException(); 1233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (sink.limit + byteCount > SIZE) { 1253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // We can't fit byteCount bytes at the sink's current position. Compact sink first. 1263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller System.arraycopy(sink.data, sink.pos, sink.data, 0, sink.limit - sink.pos); 1273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller sink.limit -= sink.pos; 1283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller sink.pos = 0; 1293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller System.arraycopy(data, pos, sink.data, sink.limit, byteCount); 1323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller sink.limit += byteCount; 1333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller pos += byteCount; 1343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller} 136