package pspnetparty.lib.socket;
import java.nio.ByteBuffer;
import java.util.LinkedList;
import pspnetparty.lib.Utility;
public class SendBufferQueue<T> {
public class Allotment {
private T attachment;
private ByteBuffer slice;
private ByteBuffer parent;
public T getAttachment() {
return attachment;
}
public ByteBuffer getBuffer() {
return slice;
}
@Override
public String toString() {
return slice.toString();
}
}
private static final boolean DEBUG = false;
private ByteBuffer queueingBuffer;
private LinkedList<Allotment> sliceBufferList = new LinkedList<Allotment>();
private int firstQueuePosition = -1;
private Allotment lastRetrievedAllotment;
public SendBufferQueue(int initialBufferSize) {
queueingBuffer = ByteBuffer.allocateDirect(initialBufferSize);
queueingBuffer.limit(0);
}
private void replaceNewBuffer(int lengthRequired) {
int bufferSize = Math.max(lengthRequired, queueingBuffer.capacity() * 2);
queueingBuffer = ByteBuffer.allocateDirect(bufferSize);
lastRetrievedAllotment = null;
firstQueuePosition = 0;
}
private ByteBuffer sliceBuffer(int length) {
int slicePosition = queueingBuffer.limit();
int sliceLimit = slicePosition + length;
if (DEBUG) {
System.out.println("Request: position=" + slicePosition + ", limit=" + sliceLimit + ", capacity=" + queueingBuffer.capacity());
System.out.println("firstQueuePosition=" + firstQueuePosition);
}
if (firstQueuePosition == 0) {
if (sliceLimit <= queueingBuffer.capacity()) {
queueingBuffer.position(slicePosition);
queueingBuffer.limit(sliceLimit);
} else {
replaceNewBuffer(length);
queueingBuffer.limit(length);
}
} else if (sliceLimit <= firstQueuePosition) {
queueingBuffer.position(slicePosition);
queueingBuffer.limit(sliceLimit);
} else if (slicePosition <= firstQueuePosition) {
replaceNewBuffer(length);
queueingBuffer.limit(length);
} else if (sliceLimit <= queueingBuffer.capacity()) {
queueingBuffer.position(slicePosition);
queueingBuffer.limit(sliceLimit);
} else if (firstQueuePosition >= length) {
queueingBuffer.position(0);
queueingBuffer.limit(length);
} else {
replaceNewBuffer(length);
queueingBuffer.limit(length);
}
if (DEBUG) {
System.out.println("Result: position=" + queueingBuffer.position() + ", limit=" + queueingBuffer.limit());
}
return queueingBuffer.slice();
}
public synchronized void queue(ByteBuffer buffer, boolean prependSizeHeader, T attachment) {
if (DEBUG) {
System.out.println("Queue: " + Utility.toHexString(buffer));
}
ByteBuffer slice;
if (prependSizeHeader) {
int length = buffer.remaining();
int totalLength = length + IProtocol.HEADER_BYTE_SIZE;
slice = sliceBuffer(totalLength);
slice.putInt(length);
slice.put(buffer);
} else {
int length = buffer.remaining();
slice = sliceBuffer(length);
slice.put(buffer);
}
slice.position(0);
Allotment allot = new Allotment();
allot.attachment = attachment;
allot.slice = slice;
allot.parent = queueingBuffer;
sliceBufferList.add(allot);
if (DEBUG) {
System.out.println(sliceBufferList);
}
}
public synchronized Allotment poll() {
Allotment allot = sliceBufferList.poll();
if (allot == null) {
queueingBuffer.limit(0);
firstQueuePosition = 0;
} else if (lastRetrievedAllotment != null && lastRetrievedAllotment.parent == queueingBuffer) {
int lastBufferLength = lastRetrievedAllotment.slice.capacity();
firstQueuePosition += lastBufferLength;
if (firstQueuePosition >= queueingBuffer.capacity())
firstQueuePosition = lastBufferLength;
}
if (DEBUG) {
if (allot != null)
System.out.println("Poll: " + Utility.toHexString(allot.slice));
}
lastRetrievedAllotment = allot;
return lastRetrievedAllotment;
}
public boolean isEmpty() {
return sliceBufferList.isEmpty();
}
}