/* $Id$ */
package ibis.ipl.impl.stacking.lrmc.io;
import ibis.io.Conversion;
import ibis.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* This is a complete implementation of <code>DataOutputStream</code>. It is
* built on top of an <code>OutputStream</code>. There is no need to put any
* buffering inbetween. This implementation does all the buffering needed.
*/
public final class BufferedArrayOutputStream extends DataOutputStream {
private static final int SIZEOF_CHAR = 2;
private static final int SIZEOF_SHORT = 2;
private static final int SIZEOF_INT = 4;
private static final int SIZEOF_LONG = 8;
private static final int SIZEOF_FLOAT = 4;
private static final int SIZEOF_DOUBLE = 8;
private static boolean DEBUG = false;
/** The underlying <code>OutputStream</code>. */
private LrmcOutputStream out;
/** The buffer in which output data is collected. */
private byte[] buffer;
/** Size of the buffer in which output data is collected. */
private int index = 0;
/** Number of bytes written so far to the underlying layer. */
private long bytes = 0;
/** Object used for conversion of primitive types to bytes. */
private Conversion conversion;
/** Size of the buffer in which output data is collected. */
private final int BUF_SIZE;
/**
* Constructor.
*
* @param out
* the underlying <code>OutputStream</code>
* @param bufsz
* the buffer size.
*/
public BufferedArrayOutputStream(LrmcOutputStream out, int bufsz) {
this.out = out;
this.buffer = out.getBuffer();
this.BUF_SIZE = bufsz;
conversion = Conversion.loadConversion(false);
}
public int bufferSize() {
return BUF_SIZE;
}
public long bytesWritten() {
return bytes + index;
}
public void resetBytesWritten() {
bytes = index;
}
/**
* Checks if there is space for <code>incr</code> more bytes and if not,
* the buffer is written to the underlying <code>OutputStream</code>.
*
* @param incr
* the space requested
* @param forced
* always flushes when set.
* @exception IOException
* in case of trouble.
*/
private void flush(int incr, boolean forced) throws IOException {
if (DEBUG) {
System.err.println("flush(" + incr + ") : " + " "
+ (index + incr >= BUF_SIZE) + " " + (index) + " " + forced
+ ")");
}
if (forced || index + incr > BUF_SIZE) {
bytes += index;
// The write will return a new buffer for us which is (at least)
// the same size as the old one.
buffer = out.write(0, index, forced);
// Assume we lost the buffer here
index = 0;
}
}
public void write(int b) throws IOException {
writeByte((byte) b);
}
public void writeBoolean(boolean value) throws IOException {
byte b = conversion.boolean2byte(value);
flush(1, false);
buffer[index++] = b;
}
public void writeByte(byte value) throws IOException {
flush(1, false);
buffer[index++] = value;
}
public void writeChar(char value) throws IOException {
flush(SIZEOF_CHAR, false);
conversion.char2byte(value, buffer, index);
index += SIZEOF_CHAR;
}
public void writeShort(short value) throws IOException {
flush(SIZEOF_SHORT, false);
conversion.short2byte(value, buffer, index);
index += SIZEOF_SHORT;
}
public void writeInt(int value) throws IOException {
flush(SIZEOF_INT, false);
conversion.int2byte(value, buffer, index);
index += SIZEOF_INT;
}
public void writeLong(long value) throws IOException {
flush(SIZEOF_LONG, false);
conversion.long2byte(value, buffer, index);
index += SIZEOF_LONG;
}
public void writeFloat(float value) throws IOException {
flush(SIZEOF_FLOAT, false);
conversion.float2byte(value, buffer, index);
index += SIZEOF_FLOAT;
}
public void writeDouble(double value) throws IOException {
flush(SIZEOF_DOUBLE, false);
conversion.double2byte(value, buffer, index);
index += SIZEOF_DOUBLE;
}
public void write(byte[] b) throws IOException {
writeArray(b);
}
public void write(byte[] b, int off, int len) throws IOException {
writeArray(b, off, len);
}
public void writeArray(boolean[] ref, int off, int len) throws IOException {
if (DEBUG) {
System.err.println("writeArray(boolean[" + off + " ... "
+ (off + len) + "])");
}
do {
flush(1, false);
int size = Math.min(BUF_SIZE - index, len);
conversion.boolean2byte(ref, off, size, buffer, index);
off += size;
index += size;
len -= size;
} while (len != 0);
}
public void writeArray(byte[] ref, int off, int len) throws IOException {
if (DEBUG) {
System.err.println("writeArray(byte[" + off + " ... " + (off + len)
+ "])");
}
while (len > (BUF_SIZE - index)) {
int space = BUF_SIZE - index;
// System.err.println(" ______ copying " + space + " bytes");
System.arraycopy(ref, off, buffer, index, space);
index += space;
len -= space;
off += space;
// force flush
flush(BUF_SIZE + 1, false);
}
if (len > 0) {
// System.err.println(" ______* copying " + len + " bytes");
System.arraycopy(ref, off, buffer, index, len);
index += len;
}
}
public void writeArray(char[] ref, int off, int len) throws IOException {
if (DEBUG) {
System.err.println("writeArray(char[" + off + " ... " + (off + len)
+ "])");
}
do {
flush(SIZEOF_CHAR, false);
int size = Math.min((BUF_SIZE - index) / SIZEOF_CHAR, len);
conversion.char2byte(ref, off, size, buffer, index);
off += size;
len -= size;
index += size * SIZEOF_CHAR;
} while (len != 0);
}
public void writeArray(short[] ref, int off, int len) throws IOException {
if (DEBUG) {
System.err.println("writeArray(short[" + off + " ... "
+ (off + len) + "])");
}
do {
flush(SIZEOF_SHORT, false);
int size = Math.min((BUF_SIZE - index) / SIZEOF_SHORT, len);
// System.err.println("Room to write " + size + " shorts");
conversion.short2byte(ref, off, size, buffer, index);
off += size;
len -= size;
index += size * SIZEOF_SHORT;
// System.err.println("Len = " + len + " index = " + index);
} while (len != 0);
}
public void writeArray(int[] ref, int off, int len) throws IOException {
if (DEBUG) {
System.err.println("writeArray(int[" + off + " ... " + (off + len)
+ "])");
}
do {
flush(SIZEOF_INT, false);
int size = Math.min((BUF_SIZE - index) / SIZEOF_INT, len);
// System.err.println("Room to write " + size + " ints");
conversion.int2byte(ref, off, size, buffer, index);
off += size;
len -= size;
index += size * SIZEOF_INT;
// System.err.println("Len = " + len + " index = " + index);
} while (len != 0);
}
public void writeArray(long[] ref, int off, int len) throws IOException {
if (DEBUG) {
System.err.println("writeArray(long[" + off + " ... " + (off + len)
+ "])");
}
do {
flush(SIZEOF_LONG, false);
int size = Math.min((BUF_SIZE - index) / SIZEOF_LONG, len);
conversion.long2byte(ref, off, size, buffer, index);
off += size;
len -= size;
index += size * SIZEOF_LONG;
} while (len != 0);
}
public void writeArray(float[] ref, int off, int len) throws IOException {
if (DEBUG) {
System.err.println("writeArray(float[" + off + " ... "
+ (off + len) + "])");
}
do {
flush(SIZEOF_FLOAT, false);
int size = Math.min((BUF_SIZE - index) / SIZEOF_FLOAT, len);
conversion.float2byte(ref, off, size, buffer, index);
off += size;
len -= size;
index += size * SIZEOF_FLOAT;
} while (len != 0);
}
public void writeArray(double[] ref, int off, int len) throws IOException {
if (DEBUG) {
System.err.println("writeArray(double[" + off + " ... "
+ (off + len) + "])");
}
do {
flush(SIZEOF_DOUBLE, false);
int size = Math.min((BUF_SIZE - index) / SIZEOF_DOUBLE, len);
conversion.double2byte(ref, off, size, buffer, index);
off += size;
len -= size;
index += size * SIZEOF_DOUBLE;
} while (len != 0);
}
public void flush() throws IOException {
// System.err.println("_____ ignoring flush() ");
}
public void forcedFlush() throws IOException {
// System.err.println(" ____ forced flush() ");
// new Exception().printStackTrace(System.err);
flush(BUF_SIZE + 1, true); /* Forces flush */
out.flush();
}
public void finish() {
// empty
}
public boolean finished() {
return true;
}
public void close() throws IOException {
flush();
out.close();
}
public void writeByteBuffer(ByteBuffer value) throws IOException {
int len = value.limit() - value.position();
while (len > (BUF_SIZE - index)) {
int space = BUF_SIZE - index;
// System.err.println(" ______ copying " + space + " bytes");
value.get(buffer, index, space);
index += space;
len -= space;
// force flush
flush(BUF_SIZE + 1, false);
}
if (len > 0) {
// System.err.println(" ______* copying " + len + " bytes");
value.get(buffer, index, len);
index += len;
}
}
}