
com.tangosol.io.MultiBufferReadBuffer Maven / Gradle / Ivy
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
package com.tangosol.io;
import com.tangosol.io.nio.ByteBufferOutputStream;
import com.tangosol.util.Binary;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
/**
* The MultiBufferReadBuffer is a ReadBuffer implementation that presents a
* view across any number of underlying ReadBuffer objects, as if they were
* appended end-to-end into a single ReadBuffer.
*
* @author cp 2006.04.15
*/
public class MultiBufferReadBuffer
extends AbstractReadBuffer
{
// ----- constructors ---------------------------------------------------
/**
* Construct a MultiBufferReadBuffer from an array of underlying
* ReadBuffer objects.
*
* @param abuf an array of ReadBuffer objects from which to construct
* this MultiBufferReadBuffer
*/
public MultiBufferReadBuffer(ReadBuffer[] abuf)
{
abuf = abuf.clone();
int cBuffers = abuf.length;
int[] aof = new int[cBuffers];
int cb = 0;
for (int i = 0; i < cBuffers; ++i)
{
aof[i] = cb;
int cbBuf = abuf[i].length();
if (cb + cbBuf < cb)
{
// integer overflow
throw new IllegalArgumentException("cumulative buffer length exceeds 2GB");
}
cb += cbBuf;
}
m_abuf = abuf;
m_aofBuffer = aof;
m_ofStart = 0;
m_ofEnd = cb;
}
/**
* Construct a MultiBufferReadBuffer from its constituent members. This
* is a package-private constructor intended for use by the
* MultiBufferWriteBuffer and the MultiBufferReadBuffer itself. Note that
* this implementation holds onto the passed array references.
*
* @param abuf an array of underlying ReadBuffer objects containing
* the data that this MultiBufferReadBuffer represents
* @param aofBuffer the absolute offset of the first byte of each
* ReadBuffer passed in abuf
* @param ofStart the absolute offset into the virtual ReadBuffer that
* corresponds to the zero offset of this
* MultiBufferReadBuffer
* @param ofEnd the absolute offset into the virtual ReadBuffer that
* corresponds to the first byte beyond the bounds of
* this MultiBufferReadBuffer
*/
MultiBufferReadBuffer(ReadBuffer[] abuf, int[] aofBuffer, int ofStart, int ofEnd)
{
m_abuf = abuf;
m_aofBuffer = aofBuffer;
m_ofStart = ofStart;
m_ofEnd = ofEnd;
}
// ----- MultiBufferReadBuffer interface --------------------------------
/**
* Return a self-destructing BufferInput over this Buffer.
*
* As the BufferInput is advanced the individual buffer segments will be
* released allowing them to potentially be garbage collected.
*
* @return a destructed BufferInput
*/
public BufferInput getDestructiveBufferInput()
{
return instantiateBufferInput(/*fDestructive*/ true);
}
// ----- ReadBuffer interface -------------------------------------------
/**
* {@inheritDoc}
*/
public void writeTo(OutputStream out)
throws IOException
{
writeTo((DataOutput) new DataOutputStream(out));
}
/**
* {@inheritDoc}
*/
public void writeTo(OutputStream out, int of, int cb)
throws IOException
{
writeTo((DataOutput) new DataOutputStream(out), of, cb);
}
/**
* {@inheritDoc}
*/
public void writeTo(DataOutput out)
throws IOException
{
writeTo(out, 0, length());
}
/**
* {@inheritDoc}
*/
public void writeTo(DataOutput out, int of, int cb)
throws IOException
{
if (length() == 0 || cb == 0)
{
// nop
return;
}
int iBufFirst = getBufferIndexByOffset(of);
int iBufLast = getBufferIndexByOffset(of + cb);
for (int iBuf = iBufFirst; iBuf <= iBufLast; iBuf++)
{
ReadBuffer buf = getBuffer(iBuf);
int cbBuf = buf.length();
if (iBuf == iBufFirst)
{
int ofSrc = getBufferOffset(iBuf); // ofSrc <= of
buf = buf.getReadBuffer(of - ofSrc, cbBuf + ofSrc);
cbBuf += ofSrc;
}
else if (iBuf == iBufLast)
{
buf = buf.getReadBuffer(0, cb);
}
buf.writeTo(out);
cb -= cbBuf;
}
}
/**
* {@inheritDoc}
*/
public void writeTo(ByteBuffer buf)
{
try
{
writeTo(new ByteBufferOutputStream(buf));
}
catch (IOException e)
{
throw ensureRuntimeException(e);
}
}
/**
* {@inheritDoc}
*/
public void writeTo(ByteBuffer buf, int of, int cb)
throws IOException
{
writeTo(new ByteBufferOutputStream(buf), of, cb);
}
/**
* {@inheritDoc}
*/
public int length()
{
return m_ofEnd - m_ofStart;
}
/**
* {@inheritDoc}
*/
public byte byteAt(int of)
{
checkBounds(of, 1);
int iBuf = getBufferIndexByOffset(of);
return getBuffer(iBuf).byteAt(of - getBufferOffset(iBuf));
}
/**
* {@inheritDoc}
*/
public void copyBytes(int ofBegin, int ofEnd, byte abDest[], int ofDest)
{
int cbDest = ofEnd - ofBegin;
checkBounds(ofBegin, cbDest);
if (ofDest < 0 || ofDest + cbDest > abDest.length)
{
throw new IndexOutOfBoundsException("ofDest=" + ofDest
+ ", abDest.length=" + abDest.length
+ ", bytes requested=" + cbDest);
}
int iBuf = getBufferIndexByOffset(ofBegin);
ReadBuffer buf = getBuffer(iBuf);
int ofBuf = getBufferOffset(iBuf);
int ofSrc = ofBegin - ofBuf;
int cbSrc = Math.min(cbDest, buf.length() - ofSrc);
buf.copyBytes(ofSrc, ofSrc + cbSrc, abDest, ofDest);
ofDest += cbSrc;
cbDest -= cbSrc;
while (cbDest > 0)
{
buf = getBuffer(++iBuf);
cbSrc = Math.min(cbDest, buf.length());
buf.copyBytes(0, cbSrc, abDest, ofDest);
ofDest += cbSrc;
cbDest -= cbSrc;
}
}
/**
* {@inheritDoc}
*/
public byte[] toByteArray(int of, int cb)
{
checkBounds(of, cb);
if (cb == 0)
{
return NO_BYTES;
}
int iBuf = getBufferIndexByOffset(of);
return iBuf == getBufferIndexByOffset(of + cb - 1)
? getBuffer(iBuf).toByteArray(of - getBufferOffset(iBuf), cb)
: super.toByteArray(of, cb);
}
/**
* {@inheritDoc}
*/
public Binary toBinary(int of, int cb)
{
checkBounds(of, cb);
if (cb == 0)
{
return NO_BINARY;
}
int iBuf = getBufferIndexByOffset(of);
return iBuf == getBufferIndexByOffset(of + cb - 1)
? getBuffer(iBuf).toBinary(of - getBufferOffset(iBuf), cb)
: super.toBinary(of, cb);
}
/**
* {@inheritDoc}
*/
public ByteBuffer toByteBuffer()
{
return toByteBuffer(0, length());
}
/**
* {@inheritDoc}
*/
public ByteBuffer toByteBuffer(int of, int cb)
{
int iBuf = getBufferIndexByOffset(of);
if (iBuf == getBufferIndexByOffset(of + cb - 1))
{
return getBuffer(iBuf).toByteBuffer(of - getBufferOffset(iBuf), cb);
}
return ByteBuffer.wrap(toByteArray(of, cb)).asReadOnlyBuffer();
}
// ----- Object methods -------------------------------------------------
/**
* {@inheritDoc}
*/
public boolean equals(Object o)
{
if (o == this)
{
return true;
}
if (o instanceof ReadBuffer)
{
ReadBuffer bufThat = (ReadBuffer) o;
int cbThis = length();
int cbThat = bufThat.length();
if (cbThis != cbThat)
{
return false;
}
if (cbThat == 0)
{
return true;
}
int iBufFirst = getBufferIndexByOffset(0);
int iBufLast = getBufferIndexByOffset(cbThis);
int of = 0;
for (int iBuf = iBufFirst; iBuf <= iBufLast; iBuf++)
{
ReadBuffer buf = getBuffer(iBuf);
int cb = buf.length();
if (iBuf == iBufFirst)
{
int ofSrc = getBufferOffset(iBuf); // ofSrc <= 0
buf = buf.getReadBuffer(of - ofSrc, cb + ofSrc);
cb += ofSrc;
}
else if (iBuf == iBufLast)
{
buf = buf.getReadBuffer(0, cbThis - of);
cb = cbThis - of;
}
if (!buf.equals(bufThat.getReadBuffer(of, cb)))
{
return false;
}
of += cb;
}
return true;
}
return false;
}
// ----- factory methods ------------------------------------------------
/**
* {@inheritDoc}
*/
protected ReadBuffer instantiateReadBuffer(int of, int cb)
{
checkBounds(of, cb);
if (cb == 0)
{
return NO_BINARY;
}
// calculate which underlying buffers will compose the new
// MultiBufferReadBuffer
int iBufFirst = getBufferIndexByOffset(of);
int iBufLast = getBufferIndexByOffset(of + cb - 1);
// adjust offset to be relative to the first buffer that will compose
// the new MultiBufferReadBuffer
of -= getBufferOffset(iBufFirst);
// check if the new buffer could be created without the use of the
// MultiBufferReadBuffer implementation (i.e. it's a "single" buffer)
if (iBufFirst == iBufLast)
{
ReadBuffer buf = getBuffer(iBufFirst);
return cb == buf.length() ? buf : buf.getReadBuffer(of, cb);
}
// otherwise, build the list of underlying ReadBuffers that the new
// MultiBufferReadBuffer will be composed of
int cBuffers = iBufLast - iBufFirst + 1;
ReadBuffer[] abuf = new ReadBuffer[cBuffers];
int[] aof = new int[cBuffers];
int cbTotal = 0;
for (int i = 0; i < cBuffers; ++i)
{
ReadBuffer buf = getBuffer(iBufFirst + i);
abuf[i] = buf;
aof [i] = cbTotal;
cbTotal += buf.length();
}
return new MultiBufferReadBuffer(abuf, aof, of, of + cb);
}
/**
* {@inheritDoc}
*/
protected BufferInput instantiateBufferInput()
{
return instantiateBufferInput(/*fDestructive*/ false);
}
/**
* Factory method: Instantiate a BufferInput object to read data from the
* ReadBuffer.
*
* @param fDestructive true iff the BufferInput should self-destruct as it
* is advanced
*
* @return a new BufferInput reading from this ReadBuffer
*/
protected BufferInput instantiateBufferInput(boolean fDestructive)
{
return new MultiBufferInput(fDestructive);
}
// ----- inner class: MultiBufferInput ----------------------------------
/**
* An implementation of the BufferInput interface that is backed by a
* series of the underlying ReadBuffer BufferInput objects.
*/
public final class MultiBufferInput
extends AbstractBufferInput
{
// ----- constructors -------------------------------------------
/**
* Default constructor.
*/
public MultiBufferInput()
{
this(/*fDestructive*/ false);
}
/**
* Default constructor.
*
* @param fDestructive true iff the stream should self-destruct as it
* is advanced
*/
public MultiBufferInput(boolean fDestructive)
{
m_fDestructive = fDestructive;
// initialize the stream
sync();
}
// ----- InputStreaming methods ---------------------------------
/**
* {@inheritDoc}
*/
public int read()
throws IOException
{
int b;
BufferInput in = m_in;
if (in.available() >= 1)
{
b = in.read();
adjustOffsetInternal(1);
}
else
{
b = super.read();
sync();
}
return b;
}
/**
* {@inheritDoc}
*/
public int read(byte ab[], int of, int cb)
throws IOException
{
int cbActual;
BufferInput in = m_in;
if (in.available() >= cb)
{
cbActual = in.read(ab, of, cb);
assert cbActual == cb;
adjustOffsetInternal(cbActual);
}
else
{
cbActual = super.read(ab, of, cb);
sync();
}
return cbActual;
}
/**
* {@inheritDoc}
*/
public void reset()
throws IOException
{
int ofMark = getMarkInternal();
if (ofMark < 0)
{
throw new IOException("not marked");
}
// optimization: does the reset of the location occur within
// the current buffer?
BufferInput in = getIn();
int of = getOffset();
if (of > ofMark)
{
int cbRewind = of - ofMark;
int ofCurrent = in.getOffset();
if (cbRewind < ofCurrent)
{
in.setOffset(ofCurrent - cbRewind);
adjustOffsetInternal(-cbRewind);
return;
}
}
else if (of < ofMark)
{
int cbForward = ofMark - of;
if (cbForward < in.available())
{
in.skipBytes(cbForward);
adjustOffsetInternal(cbForward);
return;
}
}
else
{
return;
}
super.reset();
sync();
}
// ----- DataInput methods --------------------------------------
/**
* {@inheritDoc}
*/
public int skipBytes(int cb)
throws IOException
{
int cbActual;
BufferInput in = m_in;
if (in.available() >= cb)
{
cbActual = in.skipBytes(cb);
assert cbActual == cb;
adjustOffsetInternal(cbActual);
}
else
{
cbActual = super.skipBytes(cb);
sync();
}
return cbActual;
}
/**
* {@inheritDoc}
*/
public byte readByte()
throws IOException
{
byte b;
BufferInput in = m_in;
if (in.available() >= 1)
{
b = in.readByte();
adjustOffsetInternal(1);
}
else
{
b = super.readByte();
sync();
}
return b;
}
/**
* {@inheritDoc}
*/
public short readShort()
throws IOException
{
short n;
BufferInput in = m_in;
if (in.available() >= 2)
{
n = in.readShort();
adjustOffsetInternal(2);
}
else
{
n = super.readShort();
sync();
}
return n;
}
/**
* {@inheritDoc}
*/
public int readUnsignedShort()
throws IOException
{
int n;
BufferInput in = m_in;
if (in.available() >= 2)
{
n = in.readUnsignedShort();
adjustOffsetInternal(2);
}
else
{
n = super.readUnsignedShort();
sync();
}
return n;
}
/**
* {@inheritDoc}
*/
public char readChar()
throws IOException
{
char ch;
BufferInput in = m_in;
if (in.available() >= 2)
{
ch = in.readChar();
adjustOffsetInternal(2);
}
else
{
ch = super.readChar();
sync();
}
return ch;
}
/**
* {@inheritDoc}
*/
public int readInt()
throws IOException
{
int n;
BufferInput in = getIn();
if (in.available() >= 4)
{
n = in.readInt();
adjustOffsetInternal(4);
}
else
{
n = super.readInt();
sync();
}
return n;
}
/**
* {@inheritDoc}
*/
public long readLong()
throws IOException
{
long l;
BufferInput in = m_in;
if (in.available() >= 8)
{
l = in.readLong();
adjustOffsetInternal(8);
}
else
{
l = super.readLong();
sync();
}
return l;
}
/**
* {@inheritDoc}
*/
public float readFloat()
throws IOException
{
float fl;
BufferInput in = m_in;
if (in.available() >= 4)
{
fl = in.readFloat();
adjustOffsetInternal(4);
}
else
{
fl = super.readFloat();
sync();
}
return fl;
}
/**
* {@inheritDoc}
*/
public double readDouble()
throws IOException
{
double dfl;
BufferInput in = m_in;
if (in.available() >= 8)
{
dfl = in.readDouble();
adjustOffsetInternal(8);
}
else
{
dfl = super.readDouble();
sync();
}
return dfl;
}
/**
* {@inheritDoc}
*/
public String readUTF()
throws IOException
{
BufferInput in = m_in;
int cbAvail = in.available();
int cbChars;
if (cbAvail >= 2)
{
int ofBefore = in.getOffset();
cbChars = in.readUnsignedShort();
int cbTotal = 2 + cbChars;
if (cbAvail >= cbTotal)
{
in.setOffset(ofBefore);
String s = in.readUTF();
adjustOffsetInternal(cbTotal);
return s;
}
else
{
// not enough bytes left to read the String, so update
// the offset to reflect that we read the String length
adjustOffsetInternal(2);
}
}
else
{
cbChars = readUnsignedShort();
}
// do a virtual read of the String itself (i.e. across a buffer
// boundary)
String s = readUTF(cbChars);
sync();
return s;
}
// ----- BufferInput methods ------------------------------------
/**
* {@inheritDoc}
*/
public String readSafeUTF()
throws IOException
{
BufferInput in = m_in;
int cbAvail = in.available();
int cbChars;
if (cbAvail >= 5)
{
int ofBefore = in.getOffset();
cbChars = in.readPackedInt(); // WARNING: -1 == null String
int cbLength = in.getOffset() - ofBefore;
int cbTotal = cbLength + cbChars;
if (cbChars > 0 && cbAvail >= cbTotal)
{
in.setOffset(ofBefore);
String s = in.readSafeUTF();
adjustOffsetInternal(cbTotal);
return s;
}
else
{
// not enough bytes left to read the String, so update
// the offset to reflect that we read the String length
adjustOffsetInternal(cbLength);
}
}
else
{
cbChars = readPackedInt();
}
// do a virtual read of the String itself (i.e. across a buffer
// boundary)
String s = readUTF(cbChars);
if (cbChars > 0)
{
sync();
}
return s;
}
/**
* {@inheritDoc}
*/
public int readPackedInt()
throws IOException
{
int n;
BufferInput in = m_in;
if (in.available() >= 5)
{
int of = in.getOffset();
n = in.readPackedInt();
adjustOffsetInternal(in.getOffset() - of);
}
else
{
n = super.readPackedInt();
sync();
}
return n;
}
/**
* {@inheritDoc}
*/
public long readPackedLong()
throws IOException
{
long l;
BufferInput in = m_in;
if (in.available() >= 10)
{
int of = in.getOffset();
l = in.readPackedLong();
adjustOffsetInternal(in.getOffset() - of);
}
else
{
l = super.readPackedLong();
sync();
}
return l;
}
/**
* {@inheritDoc}
*/
public ReadBuffer readBuffer(int cb)
throws IOException
{
ReadBuffer buf;
BufferInput in = m_in;
if (in.available() >= cb)
{
buf = in.readBuffer(cb);
adjustOffsetInternal(cb);
}
else
{
buf = super.readBuffer(cb);
sync();
}
return buf;
}
/**
* {@inheritDoc}
*/
public void setOffset(int of)
{
// optimization: is the offset within the current buffer?
BufferInput in = getIn();
int ofCur = getOffset();
if (ofCur > of)
{
int cbRewind = ofCur - of;
int ofCurrent = in.getOffset();
if (cbRewind < ofCurrent)
{
in.setOffset(ofCurrent - cbRewind);
adjustOffsetInternal(-cbRewind);
return;
}
}
else if (ofCur < of)
{
int cbForward = of - ofCur;
try
{
if (cbForward < in.available())
{
in.skipBytes(cbForward);
adjustOffsetInternal(cbForward);
return;
}
}
catch (IOException e)
{
throw ensureRuntimeException(e);
}
}
else
{
return;
}
super.setOffset(of);
sync();
}
// ----- internal -----------------------------------------------
/**
* Obtain the underlying BufferOutput.
*
* @return the underlying BufferOutput
*/
protected BufferInput getIn()
{
return m_in;
}
/**
* After traversing an underlying WriteBuffer boundary, or otherwise
* changing the offset significantly, sync between this BufferOutput's
* absolute position and an underlying BufferOutput's relative
* position.
*/
protected void sync()
{
MultiBufferReadBuffer bufMulti = MultiBufferReadBuffer.this;
// absolute offset of this BufferInput
int of = getOffset();
// find the underlying WriteBuffer for that offset
int iBuf = bufMulti.getBufferIndexByOffset(of);
ReadBuffer buf = bufMulti.getBuffer(iBuf);
// convert the absolute offset to the underlying buffer's
// relative offset
of -= bufMulti.getBufferOffset(iBuf);
BufferInput inPrev = m_in;
if (inPrev != null && buf == inPrev.getBuffer())
{
// still inside the previous underlying ReadBuffer
inPrev.setOffset(of);
}
else
{
// traversed to the next (or some subsequent) underlying
// ReadBuffer; if this buffer supports destructive streaming,
// then release any previously streamed sub-buffers
if (m_fDestructive)
{
int ofMark = getMarkInternal();
if (ofMark >= 0)
{
// mark is in place; only allow destruction before
// the buffer containing the mark
iBuf = Math.min(iBuf,
bufMulti.getBufferIndexByOffset(ofMark) - 1);
}
// release previous buffers
while (--iBuf >= 0 && bufMulti.releaseBuffer(iBuf) != null)
{
}
}
// store the new underlying BufferInput and adjust the offset
BufferInput in = buf.getBufferInput();
m_in = in;
in.setOffset(of);
}
}
// ----- data members -------------------------------------------
/**
* The current underlying BufferInput object.
*/
private BufferInput m_in;
/**
* True if the BufferInput set to self-destruct.
*/
protected boolean m_fDestructive;
}
// ----- internal -------------------------------------------------------
/**
* Determine the number of ReadBuffer objects that contain the data
* presented by this MultiBufferReadBuffer.
*
* @return the count of underlying ReadBuffer objects
*/
protected int getBufferCount()
{
return m_abuf.length;
}
/**
* Determine the offset of the specified buffer. The offset of a buffer
* is the absolute offset of the first byte stored in the buffer.
*
* @param iBuffer an index 0 <= iBuffer < getBufferCount()
*
* @return the absolute offset of the first byte of the specified
* ReadBuffer
*/
protected int getBufferOffset(int iBuffer)
{
return m_aofBuffer[iBuffer] - m_ofStart;
}
/**
* Obtain the specified buffer.
*
* @param iBuffer an index 0 <= iBuffer < getBufferCount()
*
* @return the specified ReadBuffer
*/
protected ReadBuffer getBuffer(int iBuffer)
{
ReadBuffer buf = m_abuf[iBuffer];
if (buf == null)
{
throw new IndexOutOfBoundsException(
"the requested buffer '" + iBuffer + "' has been released");
}
return buf;
}
/**
* Release the specified buffer.
*
* Once released any operation requiring access to overall buffer segment
* maintained by said buffer will result in an error. This method allows
* for "destructive streaming", see #getDestructiveBufferInput()
*
* @param iBuffer an index 0 <= iBuffer < getBufferCount()
*
* @return the released buffer
*/
protected ReadBuffer releaseBuffer(int iBuffer)
{
ReadBuffer[] abuf = m_abuf;
ReadBuffer buf = m_abuf[iBuffer];
abuf[iBuffer] = null;
return buf;
}
/**
* Determine which underlying ReadBuffer contains the specified offset.
*
* @param of an offset into this MultiBufferReadBuffer
*
* @return the index of the ReadBuffer containing the specified offset
*/
protected int getBufferIndexByOffset(int of)
{
int[] aof = m_aofBuffer;
int cBuffers = aof.length;
if (cBuffers == 1)
{
// since there is only one buffer, the offset occurs within it
return 0;
}
// adjust offset to create an absolute offset into the virtual
// ReadBuffer composed of all the underlying ReadBuffer objects
of += m_ofStart;
// optimization: use previous "cached" result, and check both that
// buffer and the buffer after it (assuming there is buffer by
// buffer forward progress)
int iBuf = 0; // "closest" node from the binary search
int iLow = 0; // "left-most" node for the binary search
boolean fFound = false;
if (of >= m_ofLastOffset)
{
for (iBuf = m_iBufLastAnswer, iLow = iBuf + 2; iBuf < iLow; ++iBuf)
{
if (iBuf + 1 >= cBuffers || of < aof[iBuf+1])
{
fFound = true;
break;
}
}
}
if (!fFound)
{
// brute-force binary search through the array of offsets
int iHigh = cBuffers - 1;
while (iLow <= iHigh)
{
// pick a buffer to act as the root of the tree (or sub-tree)
// that is being searched
int iRoot = (iLow + iHigh) >> 1;
// absolute offset of the first byte of the buffer
int ofRoot = aof[iRoot];
if (of == ofRoot)
{
// exact hit
iBuf = iRoot;
while (iBuf < iHigh && ofRoot == aof[iBuf + 1])
{
// COH-5507 : skip over any empty buffers
iBuf += 1;
}
break;
}
else if (of < ofRoot)
{
iHigh = iRoot - 1;
}
else // if (of > ofRoot)
{
// go "right" in the binary tree ..
iLow = iRoot + 1;
// .. but remember this is the closest we've come so far ..
iBuf = iRoot;
}
}
}
// update "cache"
m_ofLastOffset = of;
m_iBufLastAnswer = iBuf;
return iBuf;
}
// ----- data members ---------------------------------------------------
/**
* The array of all ReadBuffer objects allocated to store the contents
* of this MultiBufferReadBuffer.
*/
private final ReadBuffer[] m_abuf;
/**
* An array of absolute offsets, each corresponding to the first byte
* stored in the corresponding ReadBuffer object.
*/
private final int[] m_aofBuffer;
/**
* The starting offset of this ReadBuffer. Basically, if there were a
* virtual ReadBuffer composed of all the contents of all the underlying
* ReadBuffers in {@link #m_abuf}, then this is the offset into that
* virtual ReadBuffer.
*/
private final int m_ofStart;
/**
* The ending offset of this ReadBuffer. Basically, if there were a
* virtual ReadBuffer composed of all the contents of all the underlying
* ReadBuffers in {@link #m_abuf}, then this is the offset into that
* ReadBuffer of the first byte that this MultiBufferReadBuffer does not
* permit access to; i.e. it is the "exclusive" ending offset.
*/
private final int m_ofEnd;
/**
* Cached "last offset looked up" value.
*/
private transient int m_ofLastOffset;
/**
* Cached "last buffer index answer" value.
*/
private transient int m_iBufLastAnswer;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy