com.pivotal.gemfirexd.internal.shared.common.io.DynamicByteArrayOutputStream Maven / Gradle / Ivy
/*
Derby - Class com.pivotal.gemfirexd.internal.shared.common.io.DynamicByteArrayOutputStream
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.pivotal.gemfirexd.internal.shared.common.io;
import com.pivotal.gemfirexd.internal.shared.common.sanity.SanityManager;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
A DynamicByteArrayOutputStream allows writing to a dynamically resizable
array of bytes. In addition to dynamic resizing, this extension allows
the user of this class to have more control over the position of the stream
and can get a direct reference of the array.
*/
public class DynamicByteArrayOutputStream extends OutputStream {
private static int INITIAL_SIZE = 4096;
private byte[] buf;
private int position;
private int used; // how many bytes are used
private int beginPosition;
public DynamicByteArrayOutputStream() {
this(INITIAL_SIZE);
}
public DynamicByteArrayOutputStream(int size) {
super();
buf = new byte[size];
}
public DynamicByteArrayOutputStream(byte[] data) {
super();
buf = data;
}
public DynamicByteArrayOutputStream(DynamicByteArrayOutputStream toBeCloned) {
byte[] cbuf = toBeCloned.getByteArray();
buf = new byte[cbuf.length];
write(cbuf, 0, cbuf.length);
position = toBeCloned.getPosition();
used = toBeCloned.getUsed();
beginPosition = toBeCloned.getBeginPosition();
}
/*
* OutputStream methods
*/
public final void write(int b)
{
if (position >= buf.length)
expandBuffer(INITIAL_SIZE);
buf[position++] = (byte) b;
if (position > used)
used = position;
}
public final void write(byte[] b, int off, int len)
{
if ((position+len) > buf.length)
expandBuffer(len);
System.arraycopy(b, off, buf, position, len);
position += len;
if (position > used)
used = position;
}
final void writeCompleteStream(InputStream dataIn, int len) throws IOException
{
if ((position+len) > buf.length)
expandBuffer(len);
InputStreamUtil.readFully(dataIn, buf, position, len);
position += len;
if (position > used)
used = position;
}
public final void close()
{
buf = null;
reset();
}
/*
* Specific methods
*/
/**
Reset the stream for reuse
*/
public final void reset()
{
position = 0;
beginPosition = 0;
used = 0;
}
/**
Get a reference to the byte array stored in the byte array output
stream. Note that the byte array may be longer that getPosition().
Bytes beyond and including the current poistion are invalid.
*/
public final byte[] getByteArray()
{
return buf;
}
/**
Get the number of bytes that was used.
*/
public final int getUsed()
{
return used;
}
/**
Get the current position in the stream
*/
public final int getPosition()
{
return position;
}
/**
Get the current position in the stream
*/
public final int getBeginPosition()
{
return beginPosition;
}
/**
Set the position of the stream pointer.
It is up to the caller to make sure the stream has no gap of garbage in
it or useful information is not left out at the end because the stream
does not remember anything about the previous position.
*/
public final void setPosition(int newPosition)
{
if (newPosition > position)
{
if (newPosition > buf.length)
expandBuffer(newPosition - buf.length);
}
position = newPosition;
if (position > used)
used = position;
return ;
}
/**
Set the begin position of the stream pointer.
If the newBeginPosition is larger than the stream itself,
then, the begin position is not set.
*/
public final void setBeginPosition(int newBeginPosition)
{
if (newBeginPosition > buf.length)
return;
beginPosition = newBeginPosition;
}
/**
Shrink the buffer left by the amount given. Ie.
bytes from 0 to amountToShrinkBy are thrown away
*/
public final void discardLeft(int amountToShrinkBy) {
System.arraycopy(buf, amountToShrinkBy, buf, 0,
used - amountToShrinkBy);
position -= amountToShrinkBy;
used -= amountToShrinkBy;
}
/**
Expand the buffer by at least the number of bytes requested in minExtension.
To optimize performance and reduce memory copies and allocation, we have a staged buffer
expansion.
- buf.length < 128k - increase by 4k
- buf.length < 1Mb - increase by 128k
- otherwise increase by 1Mb.
In all cases, if minExpansion is greater than the value about then the buffer will
be increased by minExtension.
*/
private void expandBuffer(int minExtension)
{
if (buf.length < (128 * 1024)) {
if (minExtension < INITIAL_SIZE)
minExtension = INITIAL_SIZE;
} else if (buf.length < (1024 * 1024)) {
if (minExtension < (128 * 1024))
minExtension = (128 * 1024);
} else {
if (minExtension < (1024 * 1024))
minExtension = 1024 * 1024;
}
int newsize = buf.length + minExtension;
byte[] newbuf = new byte[newsize];
System.arraycopy(buf, 0, newbuf, 0, buf.length);
buf = newbuf;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy