netty5/buffer/src/main/java/io/netty/buffer/EmptyByteBuf.java
Norman Maurer d9a6cf341c
Remove support for marking reader and writerIndex in ByteBuf to reduce overhead and complexity. (#8636)
Motivation:

ByteBuf supports “marker indexes”. The intended use case for these is if a speculative operation (e.g. decode) is in process the user can “mark” and interface and refer to it later if the operation isn’t successful (e.g. not enough data). However this is rarely used in practice,
requires extra memory to maintain, and introduces complexity in the state management for derived/pooled buffer initialization, resizing, and other operations which may modify reader/writer indexes.

Modifications:

Remove support for marking and adjust testcases / code.

Result:

Fixes https://github.com/netty/netty/issues/8535.
2018-12-11 14:00:49 +01:00

1050 lines
23 KiB
Java

/*
* Copyright 2013 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 io.netty.util.ByteProcessor;
import io.netty.util.internal.EmptyArrays;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.StringUtil;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ReadOnlyBufferException;
import java.nio.channels.FileChannel;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.nio.charset.Charset;
/**
* An empty {@link ByteBuf} whose capacity and maximum capacity are all {@code 0}.
*/
public final class EmptyByteBuf extends ByteBuf {
static final int EMPTY_BYTE_BUF_HASH_CODE = 1;
private static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.allocateDirect(0);
private static final long EMPTY_BYTE_BUFFER_ADDRESS;
static {
long emptyByteBufferAddress = 0;
try {
if (PlatformDependent.hasUnsafe()) {
emptyByteBufferAddress = PlatformDependent.directBufferAddress(EMPTY_BYTE_BUFFER);
}
} catch (Throwable t) {
// Ignore
}
EMPTY_BYTE_BUFFER_ADDRESS = emptyByteBufferAddress;
}
private final ByteBufAllocator alloc;
private final ByteOrder order;
private final String str;
private EmptyByteBuf swapped;
public EmptyByteBuf(ByteBufAllocator alloc) {
this(alloc, ByteOrder.BIG_ENDIAN);
}
private EmptyByteBuf(ByteBufAllocator alloc, ByteOrder order) {
if (alloc == null) {
throw new NullPointerException("alloc");
}
this.alloc = alloc;
this.order = order;
str = StringUtil.simpleClassName(this) + (order == ByteOrder.BIG_ENDIAN? "BE" : "LE");
}
@Override
public int capacity() {
return 0;
}
@Override
public ByteBuf capacity(int newCapacity) {
throw new ReadOnlyBufferException();
}
@Override
public ByteBufAllocator alloc() {
return alloc;
}
@Override
public ByteOrder order() {
return order;
}
@Override
public ByteBuf unwrap() {
return null;
}
@Override
public ByteBuf asReadOnly() {
return Unpooled.unmodifiableBuffer(this);
}
@Override
public boolean isReadOnly() {
return false;
}
@Override
public boolean isDirect() {
return true;
}
@Override
public int maxCapacity() {
return 0;
}
@Override
public ByteBuf order(ByteOrder endianness) {
if (endianness == null) {
throw new NullPointerException("endianness");
}
if (endianness == order()) {
return this;
}
EmptyByteBuf swapped = this.swapped;
if (swapped != null) {
return swapped;
}
this.swapped = swapped = new EmptyByteBuf(alloc(), endianness);
return swapped;
}
@Override
public int readerIndex() {
return 0;
}
@Override
public ByteBuf readerIndex(int readerIndex) {
return checkIndex(readerIndex);
}
@Override
public int writerIndex() {
return 0;
}
@Override
public ByteBuf writerIndex(int writerIndex) {
return checkIndex(writerIndex);
}
@Override
public ByteBuf setIndex(int readerIndex, int writerIndex) {
checkIndex(readerIndex);
checkIndex(writerIndex);
return this;
}
@Override
public int readableBytes() {
return 0;
}
@Override
public int writableBytes() {
return 0;
}
@Override
public int maxWritableBytes() {
return 0;
}
@Override
public boolean isReadable() {
return false;
}
@Override
public boolean isWritable() {
return false;
}
@Override
public ByteBuf clear() {
return this;
}
@Override
public ByteBuf discardReadBytes() {
return this;
}
@Override
public ByteBuf discardSomeReadBytes() {
return this;
}
@Override
public ByteBuf ensureWritable(int minWritableBytes) {
if (minWritableBytes < 0) {
throw new IllegalArgumentException("minWritableBytes: " + minWritableBytes + " (expected: >= 0)");
}
if (minWritableBytes != 0) {
throw new IndexOutOfBoundsException();
}
return this;
}
@Override
public int ensureWritable(int minWritableBytes, boolean force) {
if (minWritableBytes < 0) {
throw new IllegalArgumentException("minWritableBytes: " + minWritableBytes + " (expected: >= 0)");
}
if (minWritableBytes == 0) {
return 0;
}
return 1;
}
@Override
public boolean getBoolean(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public byte getByte(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public short getUnsignedByte(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public short getShort(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public short getShortLE(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public int getUnsignedShort(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public int getUnsignedShortLE(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public int getMedium(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public int getMediumLE(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public int getUnsignedMedium(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public int getUnsignedMediumLE(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public int getInt(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public int getIntLE(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public long getUnsignedInt(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public long getUnsignedIntLE(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public long getLong(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public long getLongLE(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public char getChar(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public float getFloat(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public double getDouble(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf getBytes(int index, ByteBuf dst) {
return checkIndex(index, dst.writableBytes());
}
@Override
public ByteBuf getBytes(int index, ByteBuf dst, int length) {
return checkIndex(index, length);
}
@Override
public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
return checkIndex(index, length);
}
@Override
public ByteBuf getBytes(int index, byte[] dst) {
return checkIndex(index, dst.length);
}
@Override
public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
return checkIndex(index, length);
}
@Override
public ByteBuf getBytes(int index, ByteBuffer dst) {
return checkIndex(index, dst.remaining());
}
@Override
public ByteBuf getBytes(int index, OutputStream out, int length) {
return checkIndex(index, length);
}
@Override
public int getBytes(int index, GatheringByteChannel out, int length) {
checkIndex(index, length);
return 0;
}
@Override
public int getBytes(int index, FileChannel out, long position, int length) {
checkIndex(index, length);
return 0;
}
@Override
public CharSequence getCharSequence(int index, int length, Charset charset) {
checkIndex(index, length);
return null;
}
@Override
public ByteBuf setBoolean(int index, boolean value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setByte(int index, int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setShort(int index, int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setShortLE(int index, int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setMedium(int index, int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setMediumLE(int index, int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setInt(int index, int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setIntLE(int index, int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setLong(int index, long value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setLongLE(int index, long value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setChar(int index, int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setFloat(int index, float value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setDouble(int index, double value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setBytes(int index, ByteBuf src) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf setBytes(int index, ByteBuf src, int length) {
return checkIndex(index, length);
}
@Override
public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
return checkIndex(index, length);
}
@Override
public ByteBuf setBytes(int index, byte[] src) {
return checkIndex(index, src.length);
}
@Override
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
return checkIndex(index, length);
}
@Override
public ByteBuf setBytes(int index, ByteBuffer src) {
return checkIndex(index, src.remaining());
}
@Override
public int setBytes(int index, InputStream in, int length) {
checkIndex(index, length);
return 0;
}
@Override
public int setBytes(int index, ScatteringByteChannel in, int length) {
checkIndex(index, length);
return 0;
}
@Override
public int setBytes(int index, FileChannel in, long position, int length) {
checkIndex(index, length);
return 0;
}
@Override
public ByteBuf setZero(int index, int length) {
return checkIndex(index, length);
}
@Override
public int setCharSequence(int index, CharSequence sequence, Charset charset) {
throw new IndexOutOfBoundsException();
}
@Override
public boolean readBoolean() {
throw new IndexOutOfBoundsException();
}
@Override
public byte readByte() {
throw new IndexOutOfBoundsException();
}
@Override
public short readUnsignedByte() {
throw new IndexOutOfBoundsException();
}
@Override
public short readShort() {
throw new IndexOutOfBoundsException();
}
@Override
public short readShortLE() {
throw new IndexOutOfBoundsException();
}
@Override
public int readUnsignedShort() {
throw new IndexOutOfBoundsException();
}
@Override
public int readUnsignedShortLE() {
throw new IndexOutOfBoundsException();
}
@Override
public int readMedium() {
throw new IndexOutOfBoundsException();
}
@Override
public int readMediumLE() {
throw new IndexOutOfBoundsException();
}
@Override
public int readUnsignedMedium() {
throw new IndexOutOfBoundsException();
}
@Override
public int readUnsignedMediumLE() {
throw new IndexOutOfBoundsException();
}
@Override
public int readInt() {
throw new IndexOutOfBoundsException();
}
@Override
public int readIntLE() {
throw new IndexOutOfBoundsException();
}
@Override
public long readUnsignedInt() {
throw new IndexOutOfBoundsException();
}
@Override
public long readUnsignedIntLE() {
throw new IndexOutOfBoundsException();
}
@Override
public long readLong() {
throw new IndexOutOfBoundsException();
}
@Override
public long readLongLE() {
throw new IndexOutOfBoundsException();
}
@Override
public char readChar() {
throw new IndexOutOfBoundsException();
}
@Override
public float readFloat() {
throw new IndexOutOfBoundsException();
}
@Override
public double readDouble() {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf readBytes(int length) {
return checkLength(length);
}
@Override
public ByteBuf readSlice(int length) {
return checkLength(length);
}
@Override
public ByteBuf readRetainedSlice(int length) {
return checkLength(length);
}
@Override
public ByteBuf readBytes(ByteBuf dst) {
return checkLength(dst.writableBytes());
}
@Override
public ByteBuf readBytes(ByteBuf dst, int length) {
return checkLength(length);
}
@Override
public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
return checkLength(length);
}
@Override
public ByteBuf readBytes(byte[] dst) {
return checkLength(dst.length);
}
@Override
public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
return checkLength(length);
}
@Override
public ByteBuf readBytes(ByteBuffer dst) {
return checkLength(dst.remaining());
}
@Override
public ByteBuf readBytes(OutputStream out, int length) {
return checkLength(length);
}
@Override
public int readBytes(GatheringByteChannel out, int length) {
checkLength(length);
return 0;
}
@Override
public int readBytes(FileChannel out, long position, int length) {
checkLength(length);
return 0;
}
@Override
public CharSequence readCharSequence(int length, Charset charset) {
checkLength(length);
return null;
}
@Override
public ByteBuf skipBytes(int length) {
return checkLength(length);
}
@Override
public ByteBuf writeBoolean(boolean value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeByte(int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeShort(int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeShortLE(int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeMedium(int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeMediumLE(int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeInt(int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeIntLE(int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeLong(long value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeLongLE(long value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeChar(int value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeFloat(float value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeDouble(double value) {
throw new IndexOutOfBoundsException();
}
@Override
public ByteBuf writeBytes(ByteBuf src) {
return checkLength(src.readableBytes());
}
@Override
public ByteBuf writeBytes(ByteBuf src, int length) {
return checkLength(length);
}
@Override
public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
return checkLength(length);
}
@Override
public ByteBuf writeBytes(byte[] src) {
return checkLength(src.length);
}
@Override
public ByteBuf writeBytes(byte[] src, int srcIndex, int length) {
return checkLength(length);
}
@Override
public ByteBuf writeBytes(ByteBuffer src) {
return checkLength(src.remaining());
}
@Override
public int writeBytes(InputStream in, int length) {
checkLength(length);
return 0;
}
@Override
public int writeBytes(ScatteringByteChannel in, int length) {
checkLength(length);
return 0;
}
@Override
public int writeBytes(FileChannel in, long position, int length) {
checkLength(length);
return 0;
}
@Override
public ByteBuf writeZero(int length) {
return checkLength(length);
}
@Override
public int writeCharSequence(CharSequence sequence, Charset charset) {
throw new IndexOutOfBoundsException();
}
@Override
public int indexOf(int fromIndex, int toIndex, byte value) {
checkIndex(fromIndex);
checkIndex(toIndex);
return -1;
}
@Override
public int bytesBefore(byte value) {
return -1;
}
@Override
public int bytesBefore(int length, byte value) {
checkLength(length);
return -1;
}
@Override
public int bytesBefore(int index, int length, byte value) {
checkIndex(index, length);
return -1;
}
@Override
public int forEachByte(ByteProcessor processor) {
return -1;
}
@Override
public int forEachByte(int index, int length, ByteProcessor processor) {
checkIndex(index, length);
return -1;
}
@Override
public int forEachByteDesc(ByteProcessor processor) {
return -1;
}
@Override
public int forEachByteDesc(int index, int length, ByteProcessor processor) {
checkIndex(index, length);
return -1;
}
@Override
public ByteBuf copy() {
return this;
}
@Override
public ByteBuf copy(int index, int length) {
return checkIndex(index, length);
}
@Override
public ByteBuf slice() {
return this;
}
@Override
public ByteBuf retainedSlice() {
return this;
}
@Override
public ByteBuf slice(int index, int length) {
return checkIndex(index, length);
}
@Override
public ByteBuf retainedSlice(int index, int length) {
return checkIndex(index, length);
}
@Override
public ByteBuf duplicate() {
return this;
}
@Override
public ByteBuf retainedDuplicate() {
return this;
}
@Override
public int nioBufferCount() {
return 1;
}
@Override
public ByteBuffer nioBuffer() {
return EMPTY_BYTE_BUFFER;
}
@Override
public ByteBuffer nioBuffer(int index, int length) {
checkIndex(index, length);
return nioBuffer();
}
@Override
public ByteBuffer[] nioBuffers() {
return new ByteBuffer[] { EMPTY_BYTE_BUFFER };
}
@Override
public ByteBuffer[] nioBuffers(int index, int length) {
checkIndex(index, length);
return nioBuffers();
}
@Override
public ByteBuffer internalNioBuffer(int index, int length) {
return EMPTY_BYTE_BUFFER;
}
@Override
public boolean hasArray() {
return true;
}
@Override
public byte[] array() {
return EmptyArrays.EMPTY_BYTES;
}
@Override
public int arrayOffset() {
return 0;
}
@Override
public boolean hasMemoryAddress() {
return EMPTY_BYTE_BUFFER_ADDRESS != 0;
}
@Override
public long memoryAddress() {
if (hasMemoryAddress()) {
return EMPTY_BYTE_BUFFER_ADDRESS;
} else {
throw new UnsupportedOperationException();
}
}
@Override
public String toString(Charset charset) {
return "";
}
@Override
public String toString(int index, int length, Charset charset) {
checkIndex(index, length);
return toString(charset);
}
@Override
public int hashCode() {
return EMPTY_BYTE_BUF_HASH_CODE;
}
@Override
public boolean equals(Object obj) {
return obj instanceof ByteBuf && !((ByteBuf) obj).isReadable();
}
@Override
public int compareTo(ByteBuf buffer) {
return buffer.isReadable()? -1 : 0;
}
@Override
public String toString() {
return str;
}
@Override
public boolean isReadable(int size) {
return false;
}
@Override
public boolean isWritable(int size) {
return false;
}
@Override
public int refCnt() {
return 1;
}
@Override
public ByteBuf retain() {
return this;
}
@Override
public ByteBuf retain(int increment) {
return this;
}
@Override
public ByteBuf touch() {
return this;
}
@Override
public ByteBuf touch(Object hint) {
return this;
}
@Override
public boolean release() {
return false;
}
@Override
public boolean release(int decrement) {
return false;
}
private ByteBuf checkIndex(int index) {
if (index != 0) {
throw new IndexOutOfBoundsException();
}
return this;
}
private ByteBuf checkIndex(int index, int length) {
if (length < 0) {
throw new IllegalArgumentException("length: " + length);
}
if (index != 0 || length != 0) {
throw new IndexOutOfBoundsException();
}
return this;
}
private ByteBuf checkLength(int length) {
if (length < 0) {
throw new IllegalArgumentException("length: " + length + " (expected: >= 0)");
}
if (length != 0) {
throw new IndexOutOfBoundsException();
}
return this;
}
}