blob: 418d0855bb51edf85b876faa605a30237209db5f [file] [log] [blame]
/*-
* Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle Berkeley
* DB Java Edition made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle Berkeley DB Java Edition for a copy of the
* license and additional information.
*/
package com.sleepycat.util;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
/**
* 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;
/*
* We can return the same byte[] for 0 length arrays.
*/
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 bumplength) {
buf = new byte[bufferSize];
this.bumpLen = bumplength;
}
// --- begin ByteArrayOutputStream compatible methods ---
public int size() {
return len;
}
public void reset() {
len = 0;
}
@Override
public void write(int b) {
writeFast(b);
}
@Override
public void write(byte[] fromBuf) {
writeFast(fromBuf);
}
@Override
public void write(byte[] fromBuf, int offset, int length) {
writeFast(fromBuf, offset, length);
}
public void writeTo(OutputStream out) throws IOException {
out.write(buf, 0, len);
}
@Override
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;
}
byte[] toBuf = new byte[len];
System.arraycopy(buf, 0, toBuf, 0, len);
return toBuf;
}
// --- end ByteArrayOutputStream compatible methods ---
/**
* Equivalent to <code>write(int)</code> but does not throw
* <code>IOException</code>.
*
* @param b the byte to write.
*
* @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>.
*
* @param fromBuf the buffer to write.
*
* @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>.
*
* @param fromBuf the buffer to write.
*
* @param offset the start offset in the buffer.
*
* @param length the number of bytes to write.
*
* @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) {
/* Double the buffer if the bumpLen is zero. */
int bump = (bumpLen > 0) ? bumpLen : buf.length;
byte[] toBuf = new byte[buf.length + needed + bump];
System.arraycopy(buf, 0, toBuf, 0, len);
buf = toBuf;
}
}