151 lines
4.9 KiB
Java
151 lines
4.9 KiB
Java
/* GENERATED SOURCE. DO NOT MODIFY. */
|
|
/*
|
|
* Copyright (C) 2014 Square, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package com.android.okhttp.okio;
|
|
|
|
/**
|
|
* A segment of a buffer.
|
|
*
|
|
* <p>Each segment in a buffer is a circularly-linked list node referencing the following and
|
|
* preceding segments in the buffer.
|
|
*
|
|
* <p>Each segment in the pool is a singly-linked list node referencing the rest of segments in the
|
|
* pool.
|
|
*
|
|
* <p>The underlying byte arrays of segments may be shared between buffers and byte strings. When a
|
|
* segment's byte array is shared the segment may not be recycled, nor may its byte data be changed.
|
|
* The lone exception is that the owner segment is allowed to append to the segment, writing data at
|
|
* {@code limit} and beyond. There is a single owning segment for each byte array. Positions,
|
|
* limits, prev, and next references are not shared.
|
|
*/
|
|
final class Segment {
|
|
/** The size of all segments in bytes. */
|
|
static final int SIZE = 8192;
|
|
|
|
final byte[] data;
|
|
|
|
/** The next byte of application data byte to read in this segment. */
|
|
int pos;
|
|
|
|
/** The first byte of available data ready to be written to. */
|
|
int limit;
|
|
|
|
/** True if other segments or byte strings use the same byte array. */
|
|
boolean shared;
|
|
|
|
/** True if this segment owns the byte array and can append to it, extending {@code limit}. */
|
|
boolean owner;
|
|
|
|
/** Next segment in a linked or circularly-linked list. */
|
|
Segment next;
|
|
|
|
/** Previous segment in a circularly-linked list. */
|
|
Segment prev;
|
|
|
|
Segment() {
|
|
this.data = new byte[SIZE];
|
|
this.owner = true;
|
|
this.shared = false;
|
|
}
|
|
|
|
Segment(Segment shareFrom) {
|
|
this(shareFrom.data, shareFrom.pos, shareFrom.limit);
|
|
shareFrom.shared = true;
|
|
}
|
|
|
|
Segment(byte[] data, int pos, int limit) {
|
|
this.data = data;
|
|
this.pos = pos;
|
|
this.limit = limit;
|
|
this.owner = false;
|
|
this.shared = true;
|
|
}
|
|
|
|
/**
|
|
* Removes this segment of a circularly-linked list and returns its successor.
|
|
* Returns null if the list is now empty.
|
|
*/
|
|
public Segment pop() {
|
|
Segment result = next != this ? next : null;
|
|
prev.next = next;
|
|
next.prev = prev;
|
|
next = null;
|
|
prev = null;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Appends {@code segment} after this segment in the circularly-linked list.
|
|
* Returns the pushed segment.
|
|
*/
|
|
public Segment push(Segment segment) {
|
|
segment.prev = this;
|
|
segment.next = next;
|
|
next.prev = segment;
|
|
next = segment;
|
|
return segment;
|
|
}
|
|
|
|
/**
|
|
* Splits this head of a circularly-linked list into two segments. The first
|
|
* segment contains the data in {@code [pos..pos+byteCount)}. The second
|
|
* segment contains the data in {@code [pos+byteCount..limit)}. This can be
|
|
* useful when moving partial segments from one buffer to another.
|
|
*
|
|
* <p>Returns the new head of the circularly-linked list.
|
|
*/
|
|
public Segment split(int byteCount) {
|
|
if (byteCount <= 0 || byteCount > limit - pos) throw new IllegalArgumentException();
|
|
Segment prefix = new Segment(this);
|
|
prefix.limit = prefix.pos + byteCount;
|
|
pos += byteCount;
|
|
prev.push(prefix);
|
|
return prefix;
|
|
}
|
|
|
|
/**
|
|
* Call this when the tail and its predecessor may both be less than half
|
|
* full. This will copy data so that segments can be recycled.
|
|
*/
|
|
public void compact() {
|
|
if (prev == this) throw new IllegalStateException();
|
|
if (!prev.owner) return; // Cannot compact: prev isn't writable.
|
|
int byteCount = limit - pos;
|
|
int availableByteCount = SIZE - prev.limit + (prev.shared ? 0 : prev.pos);
|
|
if (byteCount > availableByteCount) return; // Cannot compact: not enough writable space.
|
|
writeTo(prev, byteCount);
|
|
pop();
|
|
SegmentPool.recycle(this);
|
|
}
|
|
|
|
/** Moves {@code byteCount} bytes from this segment to {@code sink}. */
|
|
public void writeTo(Segment sink, int byteCount) {
|
|
if (!sink.owner) throw new IllegalArgumentException();
|
|
if (sink.limit + byteCount > SIZE) {
|
|
// We can't fit byteCount bytes at the sink's current position. Shift sink first.
|
|
if (sink.shared) throw new IllegalArgumentException();
|
|
if (sink.limit + byteCount - sink.pos > SIZE) throw new IllegalArgumentException();
|
|
System.arraycopy(sink.data, sink.pos, sink.data, 0, sink.limit - sink.pos);
|
|
sink.limit -= sink.pos;
|
|
sink.pos = 0;
|
|
}
|
|
|
|
System.arraycopy(data, pos, sink.data, sink.limit, byteCount);
|
|
sink.limit += byteCount;
|
|
pos += byteCount;
|
|
}
|
|
}
|