
zmq.io.coder.EncoderBase Maven / Gradle / Ivy
package zmq.io.coder;
import java.nio.ByteBuffer;
import zmq.Msg;
import zmq.util.Errno;
import zmq.util.ValueReference;
public abstract class EncoderBase implements IEncoder
{
// Where to get the data to write from.
private ByteBuffer writeBuf;
// Next step. If set to null, it means that associated data stream
// is dead.
private Runnable next;
// If true, first byte of the message is being written.
private boolean newMsgFlag;
// How much data to write before next step should be executed.
private int toWrite;
// The buffer for encoded data.
private final ByteBuffer buffer;
private final int bufferSize;
private boolean error;
protected Msg inProgress;
private final Errno errno;
protected EncoderBase(Errno errno, int bufferSize)
{
this.errno = errno;
this.bufferSize = bufferSize;
buffer = ByteBuffer.allocateDirect(bufferSize);
error = false;
}
// Load a new message into encoder.
@Override
public final void loadMsg(Msg msg)
{
assert (inProgress == null);
inProgress = msg;
next();
}
// The function returns a batch of binary data. The data
// are filled to a supplied buffer. If no buffer is supplied (data
// is NULL) encoder will provide buffer of its own.
@Override
public final int encode(ValueReference data, int size)
{
int bufferSize = size;
ByteBuffer buf = data.get();
if (buf == null) {
buf = this.buffer;
bufferSize = this.bufferSize;
buffer.clear();
}
if (inProgress == null) {
return 0;
}
int pos = 0;
buf.limit(buf.capacity());
while (pos < bufferSize) {
// If there are no more data to return, run the state machine.
// If there are still no data, return what we already have
// in the buffer.
if (toWrite == 0) {
if (newMsgFlag) {
inProgress = null;
break;
}
next();
}
// If there are no data in the buffer yet and we are able to
// fill whole buffer in a single go, let's use zero-copy.
// There's no disadvantage to it as we cannot stuck multiple
// messages into the buffer anyway. Note that subsequent
// write(s) are non-blocking, thus each single write writes
// at most SO_SNDBUF bytes at once not depending on how large
// is the chunk returned from here.
// As a consequence, large messages being sent won't block
// other engines running in the same I/O thread for excessive
// amounts of time.
if (pos == 0 && data.get() == null && toWrite >= bufferSize) {
writeBuf.limit(writeBuf.capacity());
data.set(writeBuf);
pos = toWrite;
writeBuf = null;
toWrite = 0;
return pos;
}
// Copy data to the buffer. If the buffer is full, return.
int toCopy = Math.min(toWrite, bufferSize - pos);
int limit = writeBuf.limit();
writeBuf.limit(Math.min(writeBuf.capacity(), writeBuf.position() + toCopy));
int current = buf.position();
buf.put(writeBuf);
toCopy = buf.position() - current;
writeBuf.limit(limit);
pos += toCopy;
toWrite -= toCopy;
}
data.set(buf);
return pos;
}
@Override
public void encoded()
{
buffer.flip();
}
protected void encodingError()
{
error = true;
}
public final boolean isError()
{
return error;
}
protected void next()
{
if (next != null) {
next.run();
}
}
protected void nextStep(Msg msg, Runnable state, boolean beginning)
{
if (msg == null) {
nextStep((byte[]) null, 0, state, beginning);
}
else {
nextStep(msg.buf(), state, beginning);
}
}
// This function should be called from derived class to write the data
// to the buffer and schedule next state machine action.
private void nextStep(byte[] buf, int toWrite, Runnable next, boolean newMsgFlag)
{
if (buf != null) {
writeBuf = ByteBuffer.wrap(buf);
writeBuf.limit(toWrite);
}
else {
writeBuf = null;
}
this.toWrite = toWrite;
this.next = next;
this.newMsgFlag = newMsgFlag;
}
protected void initStep(Runnable next, boolean newMsgFlag)
{
nextStep((byte[]) null, 0, next, newMsgFlag);
}
private void nextStep(ByteBuffer buf, Runnable next, boolean newMsgFlag)
{
nextStep(buf, buf.limit(), next, newMsgFlag);
}
protected void nextStep(ByteBuffer buf, int toWrite, Runnable next, boolean newMsgFlag)
{
buf.limit(toWrite);
buf.position(toWrite);
buf.flip();
writeBuf = buf;
this.toWrite = toWrite;
this.next = next;
this.newMsgFlag = newMsgFlag;
}
public int errno()
{
return errno.get();
}
public void errno(int err)
{
this.errno.set(err);
}
@Override
public void destroy()
{
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy