/*
* Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*
*/
package bench.serial;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
/**
* The StreamBuffer class provides a space that can be written to with an
* OutputStream and read from with an InputStream. It is similar to
* PipedInput/OutputStream except that it is unsynchronized and more
* lightweight. StreamBuffers are used inside of the serialization benchmarks
* in order to minimize the overhead incurred by reading and writing to/from the
* underlying stream (using ByteArrayInput/OutputStreams results in allocation
* of a new byte array with each cycle, while using PipedInput/OutputStreams
* involves threading and synchronization).
* <p>
* Writes/reads to and from a StreamBuffer must occur in distinct phases; reads
* from a StreamBuffer effectively close the StreamBuffer output stream. These
* semantics are necessary to avoid using wait/notify in
* StreamBufferInputStream.read().
*/
public class StreamBuffer {
/**
* Output stream for writing to stream buffer.
*/
private class StreamBufferOutputStream extends OutputStream {
private int pos;
public void write(int b) throws IOException {
if (mode != WRITE_MODE)
throw new IOException();
while (pos >= buf.length)
grow();
buf[pos++] = (byte) b;
}
public void write(byte[] b, int off, int len) throws IOException {
if (mode != WRITE_MODE)
throw new IOException();
while (pos + len > buf.length)
grow();
System.arraycopy(b, off, buf, pos, len);
pos += len;
}
public void close() throws IOException {
if (mode != WRITE_MODE)
throw new IOException();
mode = READ_MODE;
}
}
/**
* Input stream for reading from stream buffer.
*/
private class StreamBufferInputStream extends InputStream {
private int pos;
public int read() throws IOException {
if (mode == CLOSED_MODE)
throw new IOException();
mode = READ_MODE;
return (pos < out.pos) ? (buf[pos++] & 0xFF) : -1;
}
public int read(byte[] b, int off, int len) throws IOException {
if (mode == CLOSED_MODE)
throw new IOException();
mode = READ_MODE;
int avail = out.pos - pos;
int rlen = (avail < len) ? avail : len;
System.arraycopy(buf, pos, b, off, rlen);
pos += rlen;
return rlen;
}
public long skip(long len) throws IOException {
if (mode == CLOSED_MODE)
throw new IOException();
mode = READ_MODE;
int avail = out.pos - pos;
long slen = (avail < len) ? avail : len;
pos += slen;
return slen;
}
public int available() throws IOException {
if (mode == CLOSED_MODE)
throw new IOException();
mode = READ_MODE;
return out.pos - pos;
}
public void close() throws IOException {
if (mode == CLOSED_MODE)
throw new IOException();
mode = CLOSED_MODE;
}
}
private static final int START_BUFSIZE = 256;
private static final int GROW_FACTOR = 2;
private static final int CLOSED_MODE = 0;
private static final int WRITE_MODE = 1;
private static final int READ_MODE = 2;
private byte[] buf;
private StreamBufferOutputStream out = new StreamBufferOutputStream();
private StreamBufferInputStream in = new StreamBufferInputStream();
private int mode = WRITE_MODE;
public StreamBuffer() {
this(START_BUFSIZE);
}
public StreamBuffer(int size) {
buf = new byte[size];
}
public OutputStream getOutputStream() {
return out;
}
public InputStream getInputStream() {
return in;
}
public void reset() {
in.pos = out.pos = 0;
mode = WRITE_MODE;
}
private void grow() {
byte[] newbuf = new byte[buf.length * GROW_FACTOR];
System.arraycopy(buf, 0, newbuf, 0, buf.length);
buf = newbuf;
}
}