Always use EmptyByteBuf when a user attempts to construct a buffer with 0 maxCapacity / Make EmptyByteBuf remember the allocator it came from / Optimize EmptyByteBuf a little bit

This commit is contained in:
Trustin Lee 2013-03-08 11:03:11 +09:00
parent 096e4c95ef
commit 63116239ac
3 changed files with 54 additions and 33 deletions

View File

@ -41,7 +41,7 @@ public abstract class AbstractByteBufAllocator implements ByteBufAllocator {
*/ */
protected AbstractByteBufAllocator(boolean preferDirect) { protected AbstractByteBufAllocator(boolean preferDirect) {
directByDefault = preferDirect && PlatformDependent.hasUnsafe(); directByDefault = preferDirect && PlatformDependent.hasUnsafe();
emptyBuf = new UnpooledHeapByteBuf(this, 0, 0); emptyBuf = new EmptyByteBuf(this);
} }
@Override @Override

View File

@ -27,29 +27,44 @@ import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel; import java.nio.channels.ScatteringByteChannel;
import java.nio.charset.Charset; import java.nio.charset.Charset;
/**
* An empty {@link ByteBuf} whose capacity and maximum capacity are all {@code 0}.
*/
public final class EmptyByteBuf implements ByteBuf { public final class EmptyByteBuf implements ByteBuf {
private static final byte[] EMPTY_ARRAY = new byte[0]; private static final byte[] EMPTY_ARRAY = new byte[0];
private static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.allocateDirect(0);
private static final long EMPTY_BYTE_BUFFER_ADDRESS;
public static final EmptyByteBuf INSTANCE_BE = new EmptyByteBuf(ByteOrder.BIG_ENDIAN); static {
public static final EmptyByteBuf INSTANCE_LE = new EmptyByteBuf(ByteOrder.LITTLE_ENDIAN); long emptyByteBufferAddress = 0;
try {
private final ByteOrder order;
private final ByteBuffer nioBuf = ByteBuffer.allocateDirect(0);
private final long memoryAddress;
private final byte[] array = EMPTY_ARRAY;
private final String str;
private EmptyByteBuf(ByteOrder order) {
this.order = order;
nioBuf.order(order);
str = getClass().getSimpleName() + (order == ByteOrder.BIG_ENDIAN? "BE" : "LE");
if (PlatformDependent.hasUnsafe()) { if (PlatformDependent.hasUnsafe()) {
memoryAddress = PlatformDependent.directBufferAddress(nioBuf); emptyByteBufferAddress = PlatformDependent.directBufferAddress(EMPTY_BYTE_BUFFER);
} else {
memoryAddress = -1;
} }
} 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 = getClass().getSimpleName() + (order == ByteOrder.BIG_ENDIAN? "BE" : "LE");
} }
@Override @Override
@ -64,7 +79,7 @@ public final class EmptyByteBuf implements ByteBuf {
@Override @Override
public ByteBufAllocator alloc() { public ByteBufAllocator alloc() {
return UnpooledByteBufAllocator.DEFAULT; return alloc;
} }
@Override @Override
@ -79,7 +94,7 @@ public final class EmptyByteBuf implements ByteBuf {
@Override @Override
public boolean isDirect() { public boolean isDirect() {
return false; return true;
} }
@Override @Override
@ -92,11 +107,17 @@ public final class EmptyByteBuf implements ByteBuf {
if (endianness == null) { if (endianness == null) {
throw new NullPointerException("endianness"); throw new NullPointerException("endianness");
} }
if (endianness == ByteOrder.BIG_ENDIAN) { if (endianness == order()) {
return INSTANCE_BE; return this;
} }
return INSTANCE_LE; EmptyByteBuf swapped = this.swapped;
if (swapped != null) {
return swapped;
}
this.swapped = swapped = new EmptyByteBuf(alloc(), endianness);
return swapped;
} }
@Override @Override
@ -719,24 +740,24 @@ public final class EmptyByteBuf implements ByteBuf {
@Override @Override
public ByteBuffer nioBuffer() { public ByteBuffer nioBuffer() {
return nioBuf; return EMPTY_BYTE_BUFFER;
} }
@Override @Override
public ByteBuffer nioBuffer(int index, int length) { public ByteBuffer nioBuffer(int index, int length) {
checkIndex(index, length); checkIndex(index, length);
return nioBuf; return nioBuffer();
} }
@Override @Override
public ByteBuffer[] nioBuffers() { public ByteBuffer[] nioBuffers() {
return new ByteBuffer[] { nioBuf }; return new ByteBuffer[] { EMPTY_BYTE_BUFFER };
} }
@Override @Override
public ByteBuffer[] nioBuffers(int index, int length) { public ByteBuffer[] nioBuffers(int index, int length) {
checkIndex(index, length); checkIndex(index, length);
return new ByteBuffer[] { nioBuf }; return nioBuffers();
} }
@Override @Override
@ -746,7 +767,7 @@ public final class EmptyByteBuf implements ByteBuf {
@Override @Override
public byte[] array() { public byte[] array() {
return array; return EMPTY_ARRAY;
} }
@Override @Override
@ -756,13 +777,13 @@ public final class EmptyByteBuf implements ByteBuf {
@Override @Override
public boolean hasMemoryAddress() { public boolean hasMemoryAddress() {
return memoryAddress != -1; return EMPTY_BYTE_BUFFER_ADDRESS != 0;
} }
@Override @Override
public long memoryAddress() { public long memoryAddress() {
if (hasMemoryAddress()) { if (hasMemoryAddress()) {
return memoryAddress; return EMPTY_BYTE_BUFFER_ADDRESS;
} else { } else {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -776,7 +797,7 @@ public final class EmptyByteBuf implements ByteBuf {
@Override @Override
public String toString(int index, int length, Charset charset) { public String toString(int index, int length, Charset charset) {
checkIndex(index, length); checkIndex(index, length);
return ""; return toString(charset);
} }
@Override @Override

View File

@ -92,7 +92,7 @@ public final class Unpooled {
/** /**
* A buffer whose capacity is {@code 0}. * A buffer whose capacity is {@code 0}.
*/ */
public static final ByteBuf EMPTY_BUFFER = EmptyByteBuf.INSTANCE_BE; public static final ByteBuf EMPTY_BUFFER = ALLOC.buffer(0, 0);
public static <T> MessageBuf<T> messageBuffer() { public static <T> MessageBuf<T> messageBuffer() {
return new DefaultMessageBuf<T>(); return new DefaultMessageBuf<T>();