/*
* Copyright 2012 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.
Recycler;
import io.netty.util.
Recycler.
Handle;
import java.nio.
ByteBuffer;
import java.nio.
ByteOrder;
abstract class
PooledByteBuf<T> extends
AbstractReferenceCountedByteBuf {
private final
Recycler.
Handle<
PooledByteBuf<T>>
recyclerHandle;
protected
PoolChunk<T>
chunk;
protected long
handle;
protected T
memory;
protected int
offset;
protected int
length;
int
maxLength;
PoolThreadCache cache;
private
ByteBuffer tmpNioBuf;
private
ByteBufAllocator allocator;
@
SuppressWarnings("unchecked")
protected
PooledByteBuf(
Recycler.
Handle<? extends
PooledByteBuf<T>>
recyclerHandle, int
maxCapacity) {
super(
maxCapacity);
this.
recyclerHandle = (
Handle<
PooledByteBuf<T>>)
recyclerHandle;
}
void
init(
PoolChunk<T>
chunk, long
handle, int
offset, int
length, int
maxLength,
PoolThreadCache cache) {
init0(
chunk,
handle,
offset,
length,
maxLength,
cache);
}
void
initUnpooled(
PoolChunk<T>
chunk, int
length) {
init0(
chunk, 0,
chunk.
offset,
length,
length, null);
}
private void
init0(
PoolChunk<T>
chunk, long
handle, int
offset, int
length, int
maxLength,
PoolThreadCache cache) {
assert
handle >= 0;
assert
chunk != null;
this.
chunk =
chunk;
memory =
chunk.
memory;
allocator =
chunk.
arena.
parent;
this.
cache =
cache;
this.
handle =
handle;
this.
offset =
offset;
this.
length =
length;
this.
maxLength =
maxLength;
tmpNioBuf = null;
}
/**
* Method must be called before reuse this {@link PooledByteBufAllocator}
*/
final void
reuse(int
maxCapacity) {
maxCapacity(
maxCapacity);
setRefCnt(1);
setIndex0(0, 0);
discardMarks();
}
@
Override
public final int
capacity() {
return
length;
}
@
Override
public final
ByteBuf capacity(int
newCapacity) {
checkNewCapacity(
newCapacity);
// If the request capacity does not require reallocation, just update the length of the memory.
if (
chunk.
unpooled) {
if (
newCapacity ==
length) {
return this;
}
} else {
if (
newCapacity >
length) {
if (
newCapacity <=
maxLength) {
length =
newCapacity;
return this;
}
} else if (
newCapacity <
length) {
if (
newCapacity >
maxLength >>> 1) {
if (
maxLength <= 512) {
if (
newCapacity >
maxLength - 16) {
length =
newCapacity;
setIndex(
Math.
min(
readerIndex(),
newCapacity),
Math.
min(
writerIndex(),
newCapacity));
return this;
}
} else { // > 512 (i.e. >= 1024)
length =
newCapacity;
setIndex(
Math.
min(
readerIndex(),
newCapacity),
Math.
min(
writerIndex(),
newCapacity));
return this;
}
}
} else {
return this;
}
}
// Reallocation required.
chunk.
arena.
reallocate(this,
newCapacity, true);
return this;
}
@
Override
public final
ByteBufAllocator alloc() {
return
allocator;
}
@
Override
public final
ByteOrder order() {
return
ByteOrder.
BIG_ENDIAN;
}
@
Override
public final
ByteBuf unwrap() {
return null;
}
@
Override
public final
ByteBuf retainedDuplicate() {
return
PooledDuplicatedByteBuf.
newInstance(this, this,
readerIndex(),
writerIndex());
}
@
Override
public final
ByteBuf retainedSlice() {
final int
index =
readerIndex();
return
retainedSlice(
index,
writerIndex() -
index);
}
@
Override
public final
ByteBuf retainedSlice(int
index, int
length) {
return
PooledSlicedByteBuf.
newInstance(this, this,
index,
length);
}
protected final
ByteBuffer internalNioBuffer() {
ByteBuffer tmpNioBuf = this.
tmpNioBuf;
if (
tmpNioBuf == null) {
this.
tmpNioBuf =
tmpNioBuf =
newInternalNioBuffer(
memory);
}
return
tmpNioBuf;
}
protected abstract
ByteBuffer newInternalNioBuffer(T
memory);
@
Override
protected final void
deallocate() {
if (
handle >= 0) {
final long
handle = this.
handle;
this.
handle = -1;
memory = null;
tmpNioBuf = null;
chunk.
arena.
free(
chunk,
handle,
maxLength,
cache);
chunk = null;
recycle();
}
}
private void
recycle() {
recyclerHandle.
recycle(this);
}
protected final int
idx(int
index) {
return
offset +
index;
}
}