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