netty5/buffer/src/main/java/io/netty/buffer/AbstractChannelBuffer.java

704 lines
18 KiB
Java

/*
* Copyright 2011 The Netty Project
*
* The Netty Project licenses this file to you 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 io.netty.buffer;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.nio.charset.Charset;
/**
* A skeletal implementation of a buffer.
*/
public abstract class AbstractChannelBuffer implements ChannelBuffer {
private int readerIndex;
private int writerIndex;
private int markedReaderIndex;
private int markedWriterIndex;
@Override
public int readerIndex() {
return readerIndex;
}
@Override
public void readerIndex(int readerIndex) {
if (readerIndex < 0 || readerIndex > writerIndex) {
throw new IndexOutOfBoundsException();
}
this.readerIndex = readerIndex;
}
@Override
public int writerIndex() {
return writerIndex;
}
@Override
public void writerIndex(int writerIndex) {
if (writerIndex < readerIndex || writerIndex > capacity()) {
throw new IndexOutOfBoundsException();
}
this.writerIndex = writerIndex;
}
@Override
public void setIndex(int readerIndex, int writerIndex) {
if (readerIndex < 0 || readerIndex > writerIndex || writerIndex > capacity()) {
throw new IndexOutOfBoundsException();
}
this.readerIndex = readerIndex;
this.writerIndex = writerIndex;
}
@Override
public void clear() {
readerIndex = writerIndex = 0;
}
@Override
public boolean readable() {
return readableBytes() > 0;
}
@Override
public boolean writable() {
return writableBytes() > 0;
}
@Override
public int readableBytes() {
return writerIndex - readerIndex;
}
@Override
public int writableBytes() {
return capacity() - writerIndex;
}
@Override
public void markReaderIndex() {
markedReaderIndex = readerIndex;
}
@Override
public void resetReaderIndex() {
readerIndex(markedReaderIndex);
}
@Override
public void markWriterIndex() {
markedWriterIndex = writerIndex;
}
@Override
public void resetWriterIndex() {
writerIndex = markedWriterIndex;
}
@Override
public void discardReadBytes() {
if (readerIndex == 0) {
return;
}
setBytes(0, this, readerIndex, writerIndex - readerIndex);
writerIndex -= readerIndex;
markedReaderIndex = Math.max(markedReaderIndex - readerIndex, 0);
markedWriterIndex = Math.max(markedWriterIndex - readerIndex, 0);
readerIndex = 0;
}
@Override
public void ensureWritableBytes(int writableBytes) {
if (writableBytes > writableBytes()) {
throw new IndexOutOfBoundsException();
}
}
@Override
public boolean getBoolean(int index) {
return getByte(index) != 0;
}
@Override
public short getUnsignedByte(int index) {
return (short) (getByte(index) & 0xFF);
}
@Override
public int getUnsignedShort(int index) {
return getShort(index) & 0xFFFF;
}
@Override
public int getMedium(int index) {
int value = getUnsignedMedium(index);
if ((value & 0x800000) != 0) {
value |= 0xff000000;
}
return value;
}
@Override
public long getUnsignedInt(int index) {
return getInt(index) & 0xFFFFFFFFL;
}
@Override
public char getChar(int index) {
return (char) getShort(index);
}
@Override
public float getFloat(int index) {
return Float.intBitsToFloat(getInt(index));
}
@Override
public double getDouble(int index) {
return Double.longBitsToDouble(getLong(index));
}
@Override
public void getBytes(int index, byte[] dst) {
getBytes(index, dst, 0, dst.length);
}
@Override
public void getBytes(int index, ChannelBuffer dst) {
getBytes(index, dst, dst.writableBytes());
}
@Override
public void getBytes(int index, ChannelBuffer dst, int length) {
if (length > dst.writableBytes()) {
throw new IndexOutOfBoundsException();
}
getBytes(index, dst, dst.writerIndex(), length);
dst.writerIndex(dst.writerIndex() + length);
}
@Override
public void setBoolean(int index, boolean value) {
setByte(index, value ? 1 : 0);
}
@Override
public void setChar(int index, int value) {
setShort(index, value);
}
@Override
public void setFloat(int index, float value) {
setInt(index, Float.floatToRawIntBits(value));
}
@Override
public void setDouble(int index, double value) {
setLong(index, Double.doubleToRawLongBits(value));
}
@Override
public void setBytes(int index, byte[] src) {
setBytes(index, src, 0, src.length);
}
@Override
public void setBytes(int index, ChannelBuffer src) {
setBytes(index, src, src.readableBytes());
}
@Override
public void setBytes(int index, ChannelBuffer src, int length) {
if (length > src.readableBytes()) {
throw new IndexOutOfBoundsException();
}
setBytes(index, src, src.readerIndex(), length);
src.readerIndex(src.readerIndex() + length);
}
@Override
public void setZero(int index, int length) {
if (length == 0) {
return;
}
if (length < 0) {
throw new IllegalArgumentException(
"length must be 0 or greater than 0.");
}
int nLong = length >>> 3;
int nBytes = length & 7;
for (int i = nLong; i > 0; i --) {
setLong(index, 0);
index += 8;
}
if (nBytes == 4) {
setInt(index, 0);
} else if (nBytes < 4) {
for (int i = nBytes; i > 0; i --) {
setByte(index, (byte) 0);
index ++;
}
} else {
setInt(index, 0);
index += 4;
for (int i = nBytes - 4; i > 0; i --) {
setByte(index, (byte) 0);
index ++;
}
}
}
@Override
public byte readByte() {
if (readerIndex == writerIndex) {
throw new IndexOutOfBoundsException();
}
return getByte(readerIndex ++);
}
@Override
public boolean readBoolean() {
return readByte() != 0;
}
@Override
public short readUnsignedByte() {
return (short) (readByte() & 0xFF);
}
@Override
public short readShort() {
checkReadableBytes(2);
short v = getShort(readerIndex);
readerIndex += 2;
return v;
}
@Override
public int readUnsignedShort() {
return readShort() & 0xFFFF;
}
@Override
public int readMedium() {
int value = readUnsignedMedium();
if ((value & 0x800000) != 0) {
value |= 0xff000000;
}
return value;
}
@Override
public int readUnsignedMedium() {
checkReadableBytes(3);
int v = getUnsignedMedium(readerIndex);
readerIndex += 3;
return v;
}
@Override
public int readInt() {
checkReadableBytes(4);
int v = getInt(readerIndex);
readerIndex += 4;
return v;
}
@Override
public long readUnsignedInt() {
return readInt() & 0xFFFFFFFFL;
}
@Override
public long readLong() {
checkReadableBytes(8);
long v = getLong(readerIndex);
readerIndex += 8;
return v;
}
@Override
public char readChar() {
return (char) readShort();
}
@Override
public float readFloat() {
return Float.intBitsToFloat(readInt());
}
@Override
public double readDouble() {
return Double.longBitsToDouble(readLong());
}
@Override
public ChannelBuffer readBytes(int length) {
checkReadableBytes(length);
if (length == 0) {
return ChannelBuffers.EMPTY_BUFFER;
}
ChannelBuffer buf = factory().getBuffer(order(), length);
buf.writeBytes(this, readerIndex, length);
readerIndex += length;
return buf;
}
@Override
public ChannelBuffer readSlice(int length) {
ChannelBuffer slice = slice(readerIndex, length);
readerIndex += length;
return slice;
}
@Override
public void readBytes(byte[] dst, int dstIndex, int length) {
checkReadableBytes(length);
getBytes(readerIndex, dst, dstIndex, length);
readerIndex += length;
}
@Override
public void readBytes(byte[] dst) {
readBytes(dst, 0, dst.length);
}
@Override
public void readBytes(ChannelBuffer dst) {
readBytes(dst, dst.writableBytes());
}
@Override
public void readBytes(ChannelBuffer dst, int length) {
if (length > dst.writableBytes()) {
throw new IndexOutOfBoundsException();
}
readBytes(dst, dst.writerIndex(), length);
dst.writerIndex(dst.writerIndex() + length);
}
@Override
public void readBytes(ChannelBuffer dst, int dstIndex, int length) {
checkReadableBytes(length);
getBytes(readerIndex, dst, dstIndex, length);
readerIndex += length;
}
@Override
public void readBytes(ByteBuffer dst) {
int length = dst.remaining();
checkReadableBytes(length);
getBytes(readerIndex, dst);
readerIndex += length;
}
@Override
public int readBytes(GatheringByteChannel out, int length)
throws IOException {
checkReadableBytes(length);
int readBytes = getBytes(readerIndex, out, length);
readerIndex += readBytes;
return readBytes;
}
@Override
public void readBytes(OutputStream out, int length) throws IOException {
checkReadableBytes(length);
getBytes(readerIndex, out, length);
readerIndex += length;
}
@Override
public void skipBytes(int length) {
int newReaderIndex = readerIndex + length;
if (newReaderIndex > writerIndex) {
throw new IndexOutOfBoundsException();
}
readerIndex = newReaderIndex;
}
@Override
public void writeBoolean(boolean value) {
writeByte(value ? 1 : 0);
}
@Override
public void writeByte(int value) {
setByte(writerIndex ++, value);
}
@Override
public void writeShort(int value) {
setShort(writerIndex, value);
writerIndex += 2;
}
@Override
public void writeMedium(int value) {
setMedium(writerIndex, value);
writerIndex += 3;
}
@Override
public void writeInt(int value) {
setInt(writerIndex, value);
writerIndex += 4;
}
@Override
public void writeLong(long value) {
setLong(writerIndex, value);
writerIndex += 8;
}
@Override
public void writeChar(int value) {
writeShort(value);
}
@Override
public void writeFloat(float value) {
writeInt(Float.floatToRawIntBits(value));
}
@Override
public void writeDouble(double value) {
writeLong(Double.doubleToRawLongBits(value));
}
@Override
public void writeBytes(byte[] src, int srcIndex, int length) {
setBytes(writerIndex, src, srcIndex, length);
writerIndex += length;
}
@Override
public void writeBytes(byte[] src) {
writeBytes(src, 0, src.length);
}
@Override
public void writeBytes(ChannelBuffer src) {
writeBytes(src, src.readableBytes());
}
@Override
public void writeBytes(ChannelBuffer src, int length) {
if (length > src.readableBytes()) {
throw new IndexOutOfBoundsException();
}
writeBytes(src, src.readerIndex(), length);
src.readerIndex(src.readerIndex() + length);
}
@Override
public void writeBytes(ChannelBuffer src, int srcIndex, int length) {
setBytes(writerIndex, src, srcIndex, length);
writerIndex += length;
}
@Override
public void writeBytes(ByteBuffer src) {
int length = src.remaining();
setBytes(writerIndex, src);
writerIndex += length;
}
@Override
public int writeBytes(InputStream in, int length)
throws IOException {
int writtenBytes = setBytes(writerIndex, in, length);
if (writtenBytes > 0) {
writerIndex += writtenBytes;
}
return writtenBytes;
}
@Override
public int writeBytes(ScatteringByteChannel in, int length)
throws IOException {
int writtenBytes = setBytes(writerIndex, in, length);
if (writtenBytes > 0) {
writerIndex += writtenBytes;
}
return writtenBytes;
}
@Override
public void writeZero(int length) {
if (length == 0) {
return;
}
if (length < 0) {
throw new IllegalArgumentException(
"length must be 0 or greater than 0.");
}
int nLong = length >>> 3;
int nBytes = length & 7;
for (int i = nLong; i > 0; i --) {
writeLong(0);
}
if (nBytes == 4) {
writeInt(0);
} else if (nBytes < 4) {
for (int i = nBytes; i > 0; i --) {
writeByte((byte) 0);
}
} else {
writeInt(0);
for (int i = nBytes - 4; i > 0; i --) {
writeByte((byte) 0);
}
}
}
@Override
public ChannelBuffer copy() {
return copy(readerIndex, readableBytes());
}
@Override
public ChannelBuffer slice() {
return slice(readerIndex, readableBytes());
}
@Override
public ByteBuffer toByteBuffer() {
return toByteBuffer(readerIndex, readableBytes());
}
@Override
public ByteBuffer[] toByteBuffers() {
return toByteBuffers(readerIndex, readableBytes());
}
@Override
public ByteBuffer[] toByteBuffers(int index, int length) {
return new ByteBuffer[] { toByteBuffer(index, length) };
}
@Override
public String toString(Charset charset) {
return toString(readerIndex, readableBytes(), charset);
}
@Override
public String toString(int index, int length, Charset charset) {
if (length == 0) {
return "";
}
return ChannelBuffers.decodeString(
toByteBuffer(index, length), charset);
}
@Override
public int indexOf(int fromIndex, int toIndex, byte value) {
return ChannelBuffers.indexOf(this, fromIndex, toIndex, value);
}
@Override
public int indexOf(int fromIndex, int toIndex, ChannelBufferIndexFinder indexFinder) {
return ChannelBuffers.indexOf(this, fromIndex, toIndex, indexFinder);
}
@Override
public int bytesBefore(byte value) {
return bytesBefore(readerIndex(), readableBytes(), value);
}
@Override
public int bytesBefore(ChannelBufferIndexFinder indexFinder) {
return bytesBefore(readerIndex(), readableBytes(), indexFinder);
}
@Override
public int bytesBefore(int length, byte value) {
checkReadableBytes(length);
return bytesBefore(readerIndex(), length, value);
}
@Override
public int bytesBefore(int length, ChannelBufferIndexFinder indexFinder) {
checkReadableBytes(length);
return bytesBefore(readerIndex(), length, indexFinder);
}
@Override
public int bytesBefore(int index, int length, byte value) {
int endIndex = indexOf(index, index + length, value);
if (endIndex < 0) {
return -1;
}
return endIndex - index;
}
@Override
public int bytesBefore(int index, int length,
ChannelBufferIndexFinder indexFinder) {
int endIndex = indexOf(index, index + length, indexFinder);
if (endIndex < 0) {
return -1;
}
return endIndex - index;
}
@Override
public int hashCode() {
return ChannelBuffers.hashCode(this);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ChannelBuffer)) {
return false;
}
return ChannelBuffers.equals(this, (ChannelBuffer) o);
}
@Override
public int compareTo(ChannelBuffer that) {
return ChannelBuffers.compare(this, that);
}
@Override
public String toString() {
return getClass().getSimpleName() + '(' +
"ridx=" + readerIndex + ", " +
"widx=" + writerIndex + ", " +
"cap=" + capacity() +
')';
}
/**
* Throws an {@link IndexOutOfBoundsException} if the current
* {@linkplain #readableBytes() readable bytes} of this buffer is less
* than the specified value.
*/
protected void checkReadableBytes(int minimumReadableBytes) {
if (readableBytes() < minimumReadableBytes) {
throw new IndexOutOfBoundsException();
}
}
}