Last active
July 2, 2021 17:54
-
-
Save ncruces/5a1970c4fcfe5c91998046195a6dc70f to your computer and use it in GitHub Desktop.
OutputStream that writes to a direct ByteBuffer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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