Skip to content

Instantly share code, notes, and snippets.

@ncruces
Last active July 2, 2021 17:54
Show Gist options
  • Save ncruces/5a1970c4fcfe5c91998046195a6dc70f to your computer and use it in GitHub Desktop.
Save ncruces/5a1970c4fcfe5c91998046195a6dc70f to your computer and use it in GitHub Desktop.
OutputStream that writes to a direct ByteBuffer
package io.github.ncruces.utils;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import static java.lang.Math.max;
public final class ByteBufferOutputStream extends OutputStream {
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private ByteBuffer buf;
public ByteBufferOutputStream() { buf = ByteBuffer.allocate(32); }
public ByteBufferOutputStream(int size) {
if (size < 0) throw new IllegalArgumentException("size < 0");
buf = ByteBuffer.allocateDirect(size);
}
public synchronized int size() { return buf.position(); }
public synchronized void reset() { buf.clear(); }
public synchronized ByteBuffer toByteBuffer() {
ByteBuffer result;
if (buf.isDirect()) {
result = buf.asReadOnlyBuffer();
} else {
result = ByteBuffer.allocateDirect(buf.flip().limit()).put(buf);
buf.limit(buf.capacity());
}
result.flip();
return result;
}
@Override
public synchronized void write(int b) {
if (buf.remaining() == 0) expand(1);
buf.put((byte)b);
}
@Override
public synchronized void write(byte[] b) {
if (b.length == 0) return;
if (b.length > buf.remaining()) expand(b.length);
buf.put(b);
}
@Override
public synchronized void write(byte[] b, int off, int len) {
if ((off | len | off + len | b.length - (off + len)) < 0) {
throw new IndexOutOfBoundsException();
}
if (len == 0) return;
if (len > buf.remaining()) expand(len);
buf.put(b, off, len);
}
@Override
public void close() {}
private void expand(int len) {
ByteBuffer old = buf;
int oldCapacity = old.capacity();
int minCapacity = old.position() + len;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0) {
if (minCapacity < 0) throw new OutOfMemoryError();
newCapacity = max(minCapacity, MAX_ARRAY_SIZE);
}
buf = ByteBuffer.allocate(newCapacity);
old.flip();
buf.put(old);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment