All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.lark.oapi.okio.Segment Maven / Gradle / Ivy

/*
 *
 *  * Copyright (C) 2015 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.lark.oapi.okio;

import javax.annotation.Nullable;

/**
 * A segment of a buffer.
 *
 * 

Each segment in a buffer is a circularly-linked list node referencing the following and * preceding segments in the buffer. * *

Each segment in the pool is a singly-linked list node referencing the rest of segments in the * pool. * *

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; /** * Segments will be shared when doing so avoids {@code arraycopy()} of this many bytes. */ static final int SHARE_MINIMUM = 1024; 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(byte[] data, int pos, int limit, boolean shared, boolean owner) { this.data = data; this.pos = pos; this.limit = limit; this.shared = shared; this.owner = owner; } /** * Returns a new segment that shares the underlying byte array with this. Adjusting pos and limit * are safe but writes are forbidden. This also marks the current segment as shared, which * prevents it from being pooled. */ final Segment sharedCopy() { shared = true; return new Segment(data, pos, limit, true, false); } /** * Returns a new segment that its own private copy of the underlying byte array. */ final Segment unsharedCopy() { return new Segment(data.clone(), pos, limit, false, true); } /** * Removes this segment of a circularly-linked list and returns its successor. Returns null if the * list is now empty. */ public final @Nullable 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 final 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. * *

Returns the new head of the circularly-linked list. */ public final Segment split(int byteCount) { if (byteCount <= 0 || byteCount > limit - pos) { throw new IllegalArgumentException(); } Segment prefix; // We have two competing performance goals: // - Avoid copying data. We accomplish this by sharing segments. // - Avoid short shared segments. These are bad for performance because they are readonly and // may lead to long chains of short segments. // To balance these goals we only share segments when the copy will be large. if (byteCount >= SHARE_MINIMUM) { prefix = sharedCopy(); } else { prefix = SegmentPool.take(); System.arraycopy(data, pos, prefix.data, 0, byteCount); } 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 final 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 final 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; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy