package com.sleepycat.util;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import de.ovgu.cide.jakutil.*;
/**
* A replacement for ByteArrayOutputStream that does not synchronize every
* byte read.
* <p>This class extends {@link OutputStream} and its <code>write()</code>
* methods allow it to be used as a standard output stream. In addition, it
* provides <code>writeFast()</code> methods that are not declared to throw
* <code>IOException</code>. <code>IOException</code> is never thrown by this
* class.</p>
* @author Mark Hayes
*/
public class FastOutputStream extends OutputStream {
/**
* The default initial size of the buffer if no initialSize parameter is
* specified. This constant is 100 bytes.
*/
public static final int DEFAULT_INIT_SIZE=100;
/**
* The default amount that the buffer is increased when it is full. This
* constant is zero, which means to double the current buffer size.
*/
public static final int DEFAULT_BUMP_SIZE=0;
private int len;
private int bumpLen;
private byte[] buf;
private static byte[] ZERO_LENGTH_BYTE_ARRAY=new byte[0];
/**
* Creates an output stream with default sizes.
*/
public FastOutputStream(){
initBuffer(DEFAULT_INIT_SIZE,DEFAULT_BUMP_SIZE);
}
/**
* Creates an output stream with a default bump size and a given initial
* size.
* @param initialSize the initial size of the buffer.
*/
public FastOutputStream( int initialSize){
initBuffer(initialSize,DEFAULT_BUMP_SIZE);
}
/**
* Creates an output stream with a given bump size and initial size.
* @param initialSize the initial size of the buffer.
* @param bumpSize the amount to increment the buffer.
*/
public FastOutputStream( int initialSize, int bumpSize){
initBuffer(initialSize,bumpSize);
}
/**
* Creates an output stream with a given initial buffer and a default
* bump size.
* @param buffer the initial buffer; will be owned by this object.
*/
public FastOutputStream( byte[] buffer){
buf=buffer;
bumpLen=DEFAULT_BUMP_SIZE;
}
/**
* Creates an output stream with a given initial buffer and a given
* bump size.
* @param buffer the initial buffer; will be owned by this object.
* @param bumpSize the amount to increment the buffer. If zero (the
* default), the current buffer size will be doubled when the buffer is
* full.
*/
public FastOutputStream( byte[] buffer, int bumpSize){
buf=buffer;
bumpLen=bumpSize;
}
private void initBuffer( int bufferSize, int bumpLen){
buf=new byte[bufferSize];
this.bumpLen=bumpLen;
}
public int size(){
return len;
}
public void reset(){
len=0;
}
public void write( int b) throws IOException {
writeFast(b);
}
public void write( byte[] fromBuf) throws IOException {
writeFast(fromBuf);
}
public void write( byte[] fromBuf, int offset, int length) throws IOException {
writeFast(fromBuf,offset,length);
}
public void writeTo( OutputStream out) throws IOException {
out.write(buf,0,len);
}
public String toString(){
return new String(buf,0,len);
}
public String toString( String encoding) throws UnsupportedEncodingException {
return new String(buf,0,len,encoding);
}
public byte[] toByteArray(){
if (len == 0) {
return ZERO_LENGTH_BYTE_ARRAY;
}
else {
byte[] toBuf=new byte[len];
System.arraycopy(buf,0,toBuf,0,len);
return toBuf;
}
}
/**
* Equivalent to <code>write(int)<code> but does not throw
* <code>IOException</code>.
* @see #write(int)
*/
public final void writeFast( int b){
if (len + 1 > buf.length) bump(1);
buf[len++]=(byte)b;
}
/**
* Equivalent to <code>write(byte[])<code> but does not throw
* <code>IOException</code>.
* @see #write(byte[])
*/
public final void writeFast( byte[] fromBuf){
int needed=len + fromBuf.length - buf.length;
if (needed > 0) bump(needed);
System.arraycopy(fromBuf,0,buf,len,fromBuf.length);
len+=fromBuf.length;
}
/**
* Equivalent to <code>write(byte[],int,int)<code> but does not throw
* <code>IOException</code>.
* @see #write(byte[],int,int)
*/
public final void writeFast( byte[] fromBuf, int offset, int length){
int needed=len + length - buf.length;
if (needed > 0) bump(needed);
System.arraycopy(fromBuf,offset,buf,len,length);
len+=length;
}
/**
* Returns the buffer owned by this object.
* @return the buffer.
*/
public byte[] getBufferBytes(){
return buf;
}
/**
* Returns the offset of the internal buffer.
* @return always zero currently.
*/
public int getBufferOffset(){
return 0;
}
/**
* Returns the length used in the internal buffer, i.e., the offset at
* which data will be written next.
* @return the buffer length.
*/
public int getBufferLength(){
return len;
}
/**
* Ensure that at least the given number of bytes are available in the
* internal buffer.
* @param sizeNeeded the number of bytes desired.
*/
public void makeSpace( int sizeNeeded){
int needed=len + sizeNeeded - buf.length;
if (needed > 0) bump(needed);
}
/**
* Skip the given number of bytes in the buffer.
* @param sizeAdded number of bytes to skip.
*/
public void addSize( int sizeAdded){
len+=sizeAdded;
}
private void bump( int needed){
int bump=(bumpLen > 0) ? bumpLen : buf.length;
byte[] toBuf=new byte[buf.length + needed + bump];
System.arraycopy(buf,0,toBuf,0,len);
buf=toBuf;
}
}