Created
July 12, 2012 15:32
-
-
Save pingw33n/3098886 to your computer and use it in GitHub Desktop.
CyclicByteBuffer
This file contains hidden or 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
import java.io.IOException; | |
import java.io.InputStream; | |
import java.nio.BufferOverflowException; | |
/** | |
* Cyclic byte array backed buffer that allows independent reads and writes. | |
*/ | |
public class CyclicByteBuffer | |
{ | |
public CyclicByteBuffer(int capacity) | |
{ | |
data = new byte[capacity]; | |
} | |
public InputStream getInputStream() | |
{ | |
if (inputStream == null) { | |
inputStream = new InputStream() | |
{ | |
@Override | |
public int read() throws IOException | |
{ | |
if (byteReadBuf == null) { | |
byteReadBuf = new byte[1]; | |
} | |
int r = read(byteReadBuf); | |
return r != -1 ? byteReadBuf[0] & 0xFF : -1; | |
} | |
@Override | |
public int read(byte[] b, int off, int len) throws IOException | |
{ | |
if (off + len > b.length || off < 0 || len < 0) { | |
throw new IllegalArgumentException(); | |
} | |
if (len == 0) { | |
return 0; | |
} | |
int lenAvailable = available(); | |
if (lenAvailable == 0) { | |
return -1; | |
} | |
len = Math.min(len, lenAvailable); | |
if (wrapBit == 0) { | |
assert end - start >= len; | |
System.arraycopy(data, start, b, off, len); | |
} else { | |
int leadingChunkLength = data.length - start; | |
assert leadingChunkLength + end >= len; | |
System.arraycopy(data, start, b, off, Math.min(leadingChunkLength, len)); | |
if (len > leadingChunkLength) { | |
System.arraycopy(data, 0, b, off + leadingChunkLength, len - leadingChunkLength); | |
} | |
} | |
free(len); | |
return len; | |
} | |
@Override | |
public long skip(long n) throws IOException | |
{ | |
if (n >= Integer.MAX_VALUE) { | |
n = Integer.MAX_VALUE; | |
} | |
n = Math.min(n, length()); | |
free((int) n); | |
return n; | |
} | |
@Override | |
public int available() throws IOException | |
{ | |
return length(); | |
} | |
private byte[] byteReadBuf; | |
}; | |
} | |
return inputStream; | |
} | |
public int length() | |
{ | |
int result = end - start + wrapBit * data.length; | |
assert result >= 0; | |
return result; | |
} | |
public void put(byte[] data, int offset, int length) throws BufferOverflowException | |
{ | |
if (length > capacityLeft()) { | |
throw new BufferOverflowException(); | |
} | |
int leadingChunkLength = Math.min(this.data.length - end, length); | |
System.arraycopy(data, offset, this.data, end, leadingChunkLength); | |
end += leadingChunkLength; | |
assert end <= this.data.length; | |
if (end == this.data.length) { | |
end = 0; | |
wrapBit = 1; | |
int trailingChunkLength = length - leadingChunkLength; | |
System.arraycopy(data, offset + leadingChunkLength, this.data, end, trailingChunkLength); | |
end += trailingChunkLength; | |
} | |
} | |
public void put(byte[] data) throws BufferOverflowException | |
{ | |
put(data, 0, data.length); | |
} | |
public void free(int count) | |
{ | |
if (count == 0) { | |
return; | |
} | |
if (count <= 0) { | |
throw new IllegalArgumentException("Negative value of count parameter"); | |
} | |
if (count > length()) { | |
throw new IllegalArgumentException("Too much data to free"); | |
} | |
start += count; | |
if (start >= data.length) { | |
start -= data.length; | |
wrapBit = 0; | |
} | |
} | |
public int capacity() | |
{ | |
return data.length; | |
} | |
public int capacityLeft() | |
{ | |
return data.length - length(); | |
} | |
private final byte[] data; | |
private int start; | |
private int end; | |
private int wrapBit; | |
private InputStream inputStream; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment