/*
 * 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 ByteBuf whose capacity and maximum capacity are all 0.
/** * 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 markReaderIndex() { return this; } @Override public ByteBuf resetReaderIndex() { return this; } @Override public ByteBuf markWriterIndex() { return this; } @Override public ByteBuf resetWriterIndex() { 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; } }