mirror of
https://github.com/collinsmith/riiablo.git
synced 2025-02-01 10:24:30 +07:00
Committing com.riiablo.io.nio experiment
Replaces com.riiablo.io if I decide to go this route
This commit is contained in:
parent
dd1444ad9a
commit
673b437c61
5
core/src/com/riiablo/io/nio/Aligned.java
Normal file
5
core/src/com/riiablo/io/nio/Aligned.java
Normal file
@ -0,0 +1,5 @@
|
||||
package com.riiablo.io.nio;
|
||||
|
||||
interface Aligned {
|
||||
boolean aligned();
|
||||
}
|
22
core/src/com/riiablo/io/nio/AlignedReader.java
Normal file
22
core/src/com/riiablo/io/nio/AlignedReader.java
Normal file
@ -0,0 +1,22 @@
|
||||
package com.riiablo.io.nio;
|
||||
|
||||
interface AlignedReader extends Aligned {
|
||||
int bytesRead();
|
||||
int bytesRemaining();
|
||||
int numBytes();
|
||||
|
||||
byte read8();
|
||||
short read16();
|
||||
int read32();
|
||||
long read64();
|
||||
|
||||
short read8u();
|
||||
int read16u();
|
||||
long read32u();
|
||||
|
||||
byte[] readBytes(int len);
|
||||
byte[] readBytes(byte[] dst);
|
||||
byte[] readBytes(byte[] dst, int dstOffset, int len);
|
||||
|
||||
String readString(int len);
|
||||
}
|
67
core/src/com/riiablo/io/nio/BitConstraints.java
Normal file
67
core/src/com/riiablo/io/nio/BitConstraints.java
Normal file
@ -0,0 +1,67 @@
|
||||
package com.riiablo.io.nio;
|
||||
|
||||
class BitConstraints {
|
||||
private BitConstraints() {}
|
||||
|
||||
private static int _validateSize(int min, int max, int bits) {
|
||||
assert min >= 0 : "min(" + min + ") < " + 0 + "!";
|
||||
assert max > 0 : "max(" + max + ") <= " + 0;
|
||||
assert min <= max : "min(" + min + ") > max(" + max + ")";
|
||||
if (bits < min) {
|
||||
throw new IllegalArgumentException("bits(" + bits + ") < " + min);
|
||||
}
|
||||
if (bits > max) {
|
||||
throw new IllegalArgumentException("bits(" + bits + ") > " + max);
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
private static int validateSizeU(int max, int bits) {
|
||||
return _validateSize(0, max - 1, bits);
|
||||
}
|
||||
|
||||
public static int validate7u(int bits) {
|
||||
return validateSizeU(Byte.SIZE, bits);
|
||||
}
|
||||
|
||||
public static int validate15u(int bits) {
|
||||
return validateSizeU(Short.SIZE, bits);
|
||||
}
|
||||
|
||||
public static int validate31u(int bits) {
|
||||
return validateSizeU(Integer.SIZE, bits);
|
||||
}
|
||||
|
||||
public static int validate63u(int bits) {
|
||||
return validateSizeU(Long.SIZE, bits);
|
||||
}
|
||||
|
||||
private static int validateSize(int max, int bits) {
|
||||
return _validateSize(0, max, bits);
|
||||
}
|
||||
|
||||
public static int validate8(int bits) {
|
||||
return validateSize(Byte.SIZE, bits);
|
||||
}
|
||||
|
||||
public static int validate16(int bits) {
|
||||
return validateSize(Short.SIZE, bits);
|
||||
}
|
||||
|
||||
public static int validate32(int bits) {
|
||||
return validateSize(Integer.SIZE, bits);
|
||||
}
|
||||
|
||||
public static int validate64(int bits) {
|
||||
return validateSize(Long.SIZE, bits);
|
||||
}
|
||||
|
||||
public static boolean isUnsigned(long value, int size) {
|
||||
assert 0 < size && size <= Long.SIZE;
|
||||
return (value & (1 << (size - 1))) == 0;
|
||||
}
|
||||
|
||||
public static int validateAscii(int bits) {
|
||||
return _validateSize(Byte.SIZE - 1, Byte.SIZE, bits);
|
||||
}
|
||||
}
|
400
core/src/com/riiablo/io/nio/BitInput.java
Normal file
400
core/src/com/riiablo/io/nio/BitInput.java
Normal file
@ -0,0 +1,400 @@
|
||||
package com.riiablo.io.nio;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class BitInput implements Aligned, AlignedReader, UnalignedReader {
|
||||
|
||||
private static final int MAX_SAFE_CACHED_BITS = Long.SIZE - Byte.SIZE;
|
||||
|
||||
private static final long[] MASKS = new long[Long.SIZE];
|
||||
static {
|
||||
for (int i = 1; i < Long.SIZE; i++) {
|
||||
MASKS[i] = (MASKS[i - 1] << 1) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
final ByteInput byteInput;
|
||||
// final ByteBuf buffer;
|
||||
final long numBits;
|
||||
long bitsRead;
|
||||
|
||||
private int bitsCached;
|
||||
private long cache;
|
||||
|
||||
BitInput(ByteInput byteInput, int bitsCached, long cache, long numBits) {
|
||||
this.byteInput = byteInput;
|
||||
// this.buffer = byteInput.buffer;
|
||||
this.bitsCached = bitsCached;
|
||||
this.cache = cache;
|
||||
this.numBits = numBits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bytesRead() {
|
||||
return byteInput.bytesRead();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bytesRemaining() {
|
||||
return byteInput.bytesRemaining();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int numBytes() {
|
||||
return byteInput.numBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bitsCached() {
|
||||
return bitsCached;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long cache() {
|
||||
return cache;
|
||||
}
|
||||
|
||||
void clearCache() {
|
||||
bitsCached = 0;
|
||||
cache = 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long bitsRead() {
|
||||
return bitsRead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long bitsRemaining() {
|
||||
assert (numBits - bitsRead) == (bitsCached + ((long) bytesRemaining() * Byte.SIZE))
|
||||
: "actual(" + (numBits - bitsRead) + ") != expected(" + (bitsCached + ((long) bytesRemaining() * Byte.SIZE)) + ")";
|
||||
return numBits - bitsRead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long numBits() {
|
||||
return numBits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean aligned() {
|
||||
assert bitsCached < Byte.SIZE : "bitsCached(" + bitsCached + ") > " + (Byte.SIZE - 1);
|
||||
return bitsCached == 0;
|
||||
}
|
||||
|
||||
public ByteInput align() {
|
||||
// consume cache if bits remaining
|
||||
assert bitsCached < Byte.SIZE : "bitsCached(" + bitsCached + ") > " + (Byte.SIZE - 1);
|
||||
if (bitsCached > 0) {
|
||||
bitsRead = Math.min(numBits, bitsRead + bitsCached);
|
||||
clearCache();
|
||||
}
|
||||
|
||||
assert bitsRead <= numBits : "bitsRead(" + bitsRead + ") > numBits(" + numBits + ")";
|
||||
return byteInput;
|
||||
}
|
||||
|
||||
public BitInput readSlice(long numBits) {
|
||||
// since this shouldn't go more than 1 level deep, can also generate a new
|
||||
// ByteInput with a new BitInput if allowing align
|
||||
if (numBits == 0) return ByteInput.emptyByteInput().unalign();
|
||||
if (numBits < 0) throw new IllegalArgumentException("numBits(" + numBits + ") < " + 0);
|
||||
if (bitsRead + numBits > this.numBits) {
|
||||
throw new IllegalArgumentException(
|
||||
"bitsRead(" + bitsRead + ") + sliceBits(" + numBits + ") > numBits(" + this.numBits + ")");
|
||||
}
|
||||
|
||||
|
||||
assert bitsCached < Byte.SIZE : "bitsCached(" + bitsCached + ") > " + (Byte.SIZE - 1);
|
||||
|
||||
// length should include the last byte that bits belong (round to ceil)
|
||||
final long numBytes = (numBits - bitsCached + Byte.SIZE - 1) / Byte.SIZE;
|
||||
return byteInput.readSlice(numBytes, bitsCached, cache, numBits).unalign();
|
||||
}
|
||||
|
||||
public BitInput discard(long bits) {
|
||||
if (bits < 0) throw new IllegalArgumentException("bits(" + bits + ") < " + 0);
|
||||
if (bits == 0) return this;
|
||||
|
||||
final long startingBitsRead = bitsRead;
|
||||
final long bytes = bits / Byte.SIZE;
|
||||
assert bytes <= Integer.MAX_VALUE : "bytes(" + bytes + ") > Integer.MAX_VALUE";
|
||||
if (bytes > 0) align().discard((int) bytes);
|
||||
|
||||
final long overflowBits = (startingBitsRead + bits) - bitsRead;
|
||||
// checks single byte, multi-byte and expected max value
|
||||
assert bytes != 0 || overflowBits < Byte.SIZE : "overflowBits(" + overflowBits + ") > " + (Byte.SIZE - 1);
|
||||
assert bytes == 0 || overflowBits < Short.SIZE : "overflowBits(" + overflowBits + ") > " + (Short.SIZE - 1);
|
||||
assert overflowBits < Short.SIZE : "overflowBits(" + overflowBits + ") > " + (Short.SIZE - 1);
|
||||
if (overflowBits > 0) _readRaw((int) overflowBits);
|
||||
return this;
|
||||
}
|
||||
|
||||
long incrementBitsRead(long bits) {
|
||||
if ((bitsRead += bits) > numBits) {
|
||||
bitsRead = numBits;
|
||||
throw new EndOfInput();
|
||||
}
|
||||
|
||||
return bitsRead;
|
||||
}
|
||||
|
||||
long decrementBitsRead(long bits) {
|
||||
if ((bitsRead -= bits) < 0) {
|
||||
assert false : "bitsRead(" + bitsRead + ") < " + 0;
|
||||
bitsRead = 0;
|
||||
}
|
||||
|
||||
return bitsRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to {@value #MAX_UNSIGNED_BITS} bits as unsigned and casts the
|
||||
* result into a {@code long}.
|
||||
* <p/>
|
||||
* <p>{@code bits} should be in [0, {@value #MAX_UNSIGNED_BITS}].
|
||||
* <p>Reading {@code 0} bits will always return {@code 0}.
|
||||
*/
|
||||
long readUnsigned(int bits) {
|
||||
assert bits >= 0 : "bits(" + bits + ") < " + 0;
|
||||
assert bits < Long.SIZE : "bits(" + bits + ") > " + (Long.SIZE - 1);
|
||||
if (bits <= 0) return 0;
|
||||
incrementBitsRead(bits);
|
||||
ensureCache(bits);
|
||||
return bitsCached < bits
|
||||
? readCacheSafe(bits)
|
||||
: readCacheUnsafe(bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures {@link #cache} contains at least <i>n</i> bits, up to
|
||||
* {@value #MAX_SAFE_CACHED_BITS} bits due to overflow.
|
||||
*/
|
||||
private int ensureCache(int bits) {
|
||||
assert bits > 0 : "bits(" + bits + ") < " + 1;
|
||||
assert bits < Long.SIZE : "bits(" + bits + ") > " + (Long.SIZE - 1);
|
||||
while (bitsCached < bits && bitsCached <= MAX_SAFE_CACHED_BITS) {
|
||||
final long nextByte = byteInput._read8u();
|
||||
cache |= (nextByte << bitsCached);
|
||||
bitsCached += Byte.SIZE;
|
||||
}
|
||||
|
||||
return bitsCached;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads <i>n</i> bits from {@link #cache}, consuming the next byte in the
|
||||
* underlying byte stream.
|
||||
* <p/>
|
||||
* This function asserts that {@link #cache} would have overflowed if
|
||||
* <i>n</i> bits were read from the underlying byte stream and thus reads
|
||||
* the next byte accounting for this case.
|
||||
*/
|
||||
private long readCacheSafe(int bits) {
|
||||
assert bits > 0 : "bits(" + bits + ") < " + 1;
|
||||
assert bits < Long.SIZE : "bits(" + bits + ") > " + (Long.SIZE - 1);
|
||||
final int bitsToAddCount = bits - bitsCached;
|
||||
final int overflowBits = Byte.SIZE - bitsToAddCount;
|
||||
final long nextByte = byteInput._read8u();
|
||||
long bitsToAdd = nextByte & MASKS[bitsToAddCount];
|
||||
cache |= (bitsToAdd << bitsCached);
|
||||
final long overflow = (nextByte >>> bitsToAddCount) & MASKS[overflowBits];
|
||||
final long bitsOut = bitsCached & MASKS[bits];
|
||||
cache = overflow;
|
||||
bitsCached = overflowBits;
|
||||
return bitsOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads <i>n</i> bits from {@link #cache}.
|
||||
* <p/>
|
||||
* This function asserts {@link #cache} contains at least <i>n</i> bits.
|
||||
*/
|
||||
private long readCacheUnsafe(int bits) {
|
||||
assert bits > 0 : "bits(" + bits + ") < " + 1;
|
||||
assert bits < Long.SIZE : "bits(" + bits + ") > " + (Long.SIZE - 1);
|
||||
final long bitsOut = cache & MASKS[bits];
|
||||
cache >>>= bits;
|
||||
bitsCached -= bits;
|
||||
return bitsOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to {@value Long#SIZE} bits and sign extending the result as a
|
||||
* {@code long}.
|
||||
* <p/>
|
||||
* <p>{@code bits} should be in [0, {@value Long#SIZE}].
|
||||
* <p>Reading {@code 0} bits will always return {@code 0}.
|
||||
*/
|
||||
long readSigned(int bits) {
|
||||
assert bits >= 0 : "bits(" + bits + ") < " + 0;
|
||||
assert bits <= Long.SIZE : "bits(" + bits + ") > " + Long.SIZE;
|
||||
if (bits <= 0) return 0;
|
||||
if (bits == Long.SIZE) return _readRaw(Long.SIZE);
|
||||
final int shift = Long.SIZE - bits;
|
||||
assert shift > 0;
|
||||
final long value = readUnsigned(bits);
|
||||
return value << shift >> shift;
|
||||
}
|
||||
|
||||
long _readRaw(int bits) {
|
||||
assert bits > 0 : "bits(" + bits + ") <= " + 0;
|
||||
assert bits <= Long.SIZE : "bits(" + bits + ") > " + Long.SIZE;
|
||||
long lo = readUnsigned(Math.min(Integer.SIZE, bits));
|
||||
long hi = readUnsigned(Math.max(bits - Integer.SIZE, 0));
|
||||
return (hi << Integer.SIZE) | lo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readRaw(int bits) {
|
||||
BitConstraints.validate64(bits);
|
||||
return _readRaw(bits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte read7u(int bits) {
|
||||
BitConstraints.validate7u(bits);
|
||||
final byte value = (byte) readUnsigned(bits);
|
||||
assert BitConstraints.isUnsigned(value, Byte.SIZE);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short read15u(int bits) {
|
||||
BitConstraints.validate15u(bits);
|
||||
final short value = (short) readUnsigned(bits);
|
||||
assert BitConstraints.isUnsigned(value, Short.SIZE);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read31u(int bits) {
|
||||
BitConstraints.validate31u(bits);
|
||||
final int value = (int) readUnsigned(bits);
|
||||
assert BitConstraints.isUnsigned(value, Integer.SIZE);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long read63u(int bits) {
|
||||
BitConstraints.validate63u(bits);
|
||||
final long value = (long) readUnsigned(bits);
|
||||
assert BitConstraints.isUnsigned(value, Long.SIZE);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readBoolean() {
|
||||
return read1() != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte read1() {
|
||||
final byte value = read7u(1);
|
||||
assert (value & ~1) == 0;
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte read8(int bits) {
|
||||
BitConstraints.validate8(bits);
|
||||
return (byte) readSigned(bits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short read16(int bits) {
|
||||
BitConstraints.validate16(bits);
|
||||
return (short) readSigned(bits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read32(int bits) {
|
||||
BitConstraints.validate32(bits);
|
||||
return (int) readSigned(bits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long read64(int bits) {
|
||||
BitConstraints.validate64(bits);
|
||||
return readSigned(bits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short read8u() {
|
||||
return read15u(Byte.SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read16u() {
|
||||
return read31u(Short.SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long read32u() {
|
||||
return read63u(Integer.SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte read8() {
|
||||
return read8(Byte.SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short read16() {
|
||||
return read16(Short.SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read32() {
|
||||
return read32(Integer.SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long read64() {
|
||||
return read64(Long.SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aligns bit stream and reads from {@link #align()}
|
||||
*/
|
||||
@Override
|
||||
public byte[] readBytes(int len) {
|
||||
return align().readBytes(len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aligns bit stream and reads from {@link #align()}
|
||||
*/
|
||||
@Override
|
||||
public byte[] readBytes(byte[] dst) {
|
||||
return align().readBytes(dst);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aligns bit stream and reads from {@link #align()}
|
||||
*/
|
||||
@Override
|
||||
public byte[] readBytes(byte[] dst, int dstOffset, int len) {
|
||||
return align().readBytes(dst, dstOffset, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readString(int len) {
|
||||
return readString(len, Byte.SIZE, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readString(int len, int bits, boolean nullTerminated) {
|
||||
if (len < 0) throw new IllegalArgumentException("len(" + len + ") < " + 0);
|
||||
BitConstraints.validateAscii(bits);
|
||||
|
||||
if (len == 0) return StringUtils.EMPTY;
|
||||
final byte[] dst = new byte[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
final byte b = dst[i] = (byte) readUnsigned(bits);
|
||||
if (nullTerminated && b == '\0') break;
|
||||
}
|
||||
|
||||
return new String(dst);
|
||||
}
|
||||
}
|
243
core/src/com/riiablo/io/nio/ByteInput.java
Normal file
243
core/src/com/riiablo/io/nio/ByteInput.java
Normal file
@ -0,0 +1,243 @@
|
||||
package com.riiablo.io.nio;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import com.riiablo.util.DebugUtils;
|
||||
|
||||
public class ByteInput implements Aligned, AlignedReader {
|
||||
private static final ByteInput EMPTY_BYTEINPUT = new ByteInput(Unpooled.EMPTY_BUFFER);
|
||||
public static ByteInput emptyByteInput() {
|
||||
return EMPTY_BYTEINPUT;
|
||||
}
|
||||
|
||||
public static ByteInput wrap(byte[] bytes) {
|
||||
return bytes == null ? emptyByteInput() : new ByteInput(Unpooled.wrappedBuffer(bytes));
|
||||
}
|
||||
|
||||
final BitInput bitInput;
|
||||
final ByteBuf buffer;
|
||||
|
||||
ByteInput(ByteBuf buffer) {
|
||||
this(buffer, 0, 0L, (long) buffer.readableBytes() * Byte.SIZE);
|
||||
}
|
||||
|
||||
ByteInput(ByteBuf buffer, int bitsCached, long cache, long numBits) {
|
||||
this.buffer = buffer;
|
||||
this.bitInput = new BitInput(this, bitsCached, cache, numBits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bytesRead() {
|
||||
return buffer.readerIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bytesRemaining() {
|
||||
return buffer.readableBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int numBytes() {
|
||||
return buffer.capacity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean aligned() {
|
||||
return bitInput.aligned();
|
||||
}
|
||||
|
||||
public BitInput unalign() {
|
||||
return bitInput;
|
||||
}
|
||||
|
||||
public ByteInput discard(int bytes) {
|
||||
buffer.skipBytes(bytes);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes bytes until the specified sequence of bytes are encountered.
|
||||
* After this method executes, position will be such that the next read
|
||||
* operation is at the first byte in the signature.
|
||||
* <p/>
|
||||
* <b>Precondition:</b> {@code signature.length == 2}.
|
||||
*
|
||||
* @see #discard(int)
|
||||
*/
|
||||
public ByteInput discardUntil(byte[] signature) {
|
||||
assert aligned() : "not aligned";
|
||||
if (signature.length != 2) {
|
||||
throw new IllegalArgumentException(
|
||||
"signature.length(" + signature.length + ") != " + 2 + ": " + DebugUtils.toByteArray(signature));
|
||||
}
|
||||
|
||||
final byte fb0 = signature[0];
|
||||
final byte fb1 = signature[1];
|
||||
byte b0, b1;
|
||||
b1 = read8();
|
||||
for (;;) {
|
||||
b0 = b1;
|
||||
b1 = read8();
|
||||
if (b0 == fb0 && b1 == fb1) {
|
||||
buffer.readerIndex(buffer.readerIndex() - signature.length);
|
||||
decrementBitsRead((long) signature.length * Byte.SIZE);
|
||||
assert bytesRemaining() >= signature.length
|
||||
: "bytesRemaining(" + bytesRemaining() + ") < signature.length(" + signature.length + ")";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: support dynamic signature lengths
|
||||
// create a byte[] of size signature.length
|
||||
// use as a circular buffer with each read byte incrementing index and then going back to
|
||||
// 0 when signature.length is reached. Comparisons will need to be index..length
|
||||
// and 0..index (and 0..length in case where index == 0)
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ByteInput readSlice(long numBytes) {
|
||||
return readSlice(numBytes, 0, 0L, numBytes * Byte.SIZE);
|
||||
}
|
||||
|
||||
public ByteInput readSlice(long numBytes, int bitsCached, long cache, long numBits) {
|
||||
assert numBytes <= Integer.MAX_VALUE : "ByteBuf only supports int length";
|
||||
final ByteBuf slice = buffer.readSlice((int) numBytes);
|
||||
return new ByteInput(slice, bitsCached, cache, numBits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next byte from the byte stream, ignoring alignment.
|
||||
*/
|
||||
short _read8u() {
|
||||
try {
|
||||
final short octet = buffer.readUnsignedByte();
|
||||
assert 0 <= octet && octet < (1 << Byte.SIZE);
|
||||
return octet;
|
||||
} catch (IndexOutOfBoundsException t) {
|
||||
throw new EndOfInput(t);
|
||||
}
|
||||
}
|
||||
|
||||
long incrementBitsRead(long bits) {
|
||||
assert (bits & (Byte.SIZE - 1)) == 0;
|
||||
return bitInput.incrementBitsRead(bits);
|
||||
}
|
||||
|
||||
long decrementBitsRead(long bits) {
|
||||
assert (bits & (Byte.SIZE - 1)) == 0;
|
||||
return bitInput.decrementBitsRead(bits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short read8u() {
|
||||
assert aligned() : "not aligned";
|
||||
try {
|
||||
incrementBitsRead(Byte.SIZE);
|
||||
return buffer.readUnsignedByte();
|
||||
} catch (IndexOutOfBoundsException t) {
|
||||
throw new EndOfInput(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read16u() {
|
||||
assert aligned() : "not aligned";
|
||||
try {
|
||||
incrementBitsRead(Short.SIZE);
|
||||
return buffer.readUnsignedShortLE();
|
||||
} catch (IndexOutOfBoundsException t) {
|
||||
throw new EndOfInput(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long read32u() {
|
||||
assert aligned() : "not aligned";
|
||||
try {
|
||||
incrementBitsRead(Integer.SIZE);
|
||||
return buffer.readUnsignedIntLE();
|
||||
} catch (IndexOutOfBoundsException t) {
|
||||
throw new EndOfInput(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte read8() {
|
||||
assert aligned() : "not aligned";
|
||||
try {
|
||||
incrementBitsRead(Byte.SIZE);
|
||||
return buffer.readByte();
|
||||
} catch (IndexOutOfBoundsException t) {
|
||||
throw new EndOfInput(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public short read16() {
|
||||
assert aligned() : "not aligned";
|
||||
try {
|
||||
incrementBitsRead(Short.SIZE);
|
||||
return buffer.readShortLE();
|
||||
} catch (IndexOutOfBoundsException t) {
|
||||
throw new EndOfInput(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read32() {
|
||||
assert aligned() : "not aligned";
|
||||
try {
|
||||
incrementBitsRead(Integer.SIZE);
|
||||
return buffer.readIntLE();
|
||||
} catch (IndexOutOfBoundsException t) {
|
||||
throw new EndOfInput(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long read64() {
|
||||
assert aligned() : "not aligned";
|
||||
try {
|
||||
incrementBitsRead(Long.SIZE);
|
||||
return buffer.readLongLE();
|
||||
} catch (IndexOutOfBoundsException t) {
|
||||
throw new EndOfInput(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] readBytes(int len) {
|
||||
return readBytes(new byte[len]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] readBytes(byte[] dst) {
|
||||
return readBytes(dst, 0, dst.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] readBytes(byte[] dst, int dstOffset, int len) {
|
||||
assert aligned() : "not aligned";
|
||||
try {
|
||||
incrementBitsRead((long) len * Byte.SIZE);
|
||||
buffer.readBytes(dst, dstOffset, len);
|
||||
return dst;
|
||||
} catch (IndexOutOfBoundsException t) {
|
||||
throw new EndOfInput(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readString(int len) {
|
||||
assert aligned() : "not aligned";
|
||||
try {
|
||||
incrementBitsRead((long) len * Byte.SIZE);
|
||||
return buffer.readCharSequence(len, CharsetUtil.US_ASCII).toString();
|
||||
} catch (IndexOutOfBoundsException t) {
|
||||
throw new EndOfInput(t);
|
||||
}
|
||||
}
|
||||
}
|
13
core/src/com/riiablo/io/nio/EndOfInput.java
Normal file
13
core/src/com/riiablo/io/nio/EndOfInput.java
Normal file
@ -0,0 +1,13 @@
|
||||
package com.riiablo.io.nio;
|
||||
|
||||
public class EndOfInput extends RuntimeException {
|
||||
private static final String DEFAULT_MESSAGE = "The end of the input has been reached!";
|
||||
|
||||
EndOfInput() {
|
||||
super(DEFAULT_MESSAGE);
|
||||
}
|
||||
|
||||
EndOfInput(Throwable cause) {
|
||||
super(DEFAULT_MESSAGE, cause);
|
||||
}
|
||||
}
|
88
core/src/com/riiablo/io/nio/UnalignedReader.java
Normal file
88
core/src/com/riiablo/io/nio/UnalignedReader.java
Normal file
@ -0,0 +1,88 @@
|
||||
package com.riiablo.io.nio;
|
||||
|
||||
interface UnalignedReader extends Aligned, AlignedReader {
|
||||
int MAX_ULONG_BITS = Long.SIZE - 1;
|
||||
int MAX_UINT_BITS = Integer.SIZE - 1;
|
||||
int MAX_USHORT_BITS = Short.SIZE - 1;
|
||||
int MAX_UBYTE_BITS = Byte.SIZE - 1;
|
||||
int MAX_UNSIGNED_BITS = MAX_ULONG_BITS;
|
||||
|
||||
int bitsCached();
|
||||
long cache();
|
||||
|
||||
long bitsRead();
|
||||
long bitsRemaining();
|
||||
long numBits();
|
||||
|
||||
/**
|
||||
* Reads up to {@value #MAX_UBYTE_BITS} bits as unsigned and casts the result
|
||||
* into a {@code byte}.
|
||||
*/
|
||||
byte read7u(int bits);
|
||||
|
||||
/**
|
||||
* Reads up to {@value #MAX_USHORT_BITS} bits as unsigned and casts the
|
||||
* result into a {@code short}.
|
||||
*/
|
||||
short read15u(int bits);
|
||||
|
||||
/**
|
||||
* Reads up to {@value #MAX_UINT_BITS} bits as unsigned and casts the result
|
||||
* into a {@code int}.
|
||||
*/
|
||||
int read31u(int bits);
|
||||
|
||||
/**
|
||||
* Reads up to {@value #MAX_ULONG_BITS} bits as unsigned and casts the result
|
||||
* into a {@code long}.
|
||||
*/
|
||||
long read63u(int bits);
|
||||
|
||||
/**
|
||||
* Reads {@code 1} bit as a {@code boolean}.
|
||||
*
|
||||
* @see #read1()
|
||||
*/
|
||||
boolean readBoolean();
|
||||
|
||||
/**
|
||||
* Reads {@code 1} bit as a {@code byte}.
|
||||
*/
|
||||
byte read1();
|
||||
|
||||
/**
|
||||
* Reads up to {@value Byte#SIZE} bits as a sign-extended {@code byte}.
|
||||
*/
|
||||
byte read8(int bits);
|
||||
|
||||
/**
|
||||
* Reads up to {@value Short#SIZE} bits as a sign-extended {@code short}.
|
||||
*/
|
||||
short read16(int bits);
|
||||
|
||||
/**
|
||||
* Reads up to {@value Integer#SIZE} bits as a sign-extended {@code int}.
|
||||
*/
|
||||
int read32(int bits);
|
||||
|
||||
/**
|
||||
* Reads up to {@value Long#SIZE} bits as a sign-extended {@code long}.
|
||||
*/
|
||||
long read64(int bits);
|
||||
|
||||
/**
|
||||
* Reads up to {@value Long#SIZE} bits as a {@code long}. This method is
|
||||
* intended to be used to read raw memory (i.e., flags).
|
||||
*/
|
||||
long readRaw(int bits);
|
||||
|
||||
/**
|
||||
* Reads <i>n</i> characters of size {@code bits} and constructs a string.
|
||||
*
|
||||
* @param len number of characters to read
|
||||
* @param bits size of each character ({@code 7} or {@code 8})
|
||||
* @param nullTerminated {@code true} to stop reading at {@code \0}, otherwise
|
||||
* {@code len} characters will be read (variable-width string)
|
||||
*/
|
||||
String readString(int len, int bits, boolean nullTerminated);
|
||||
}
|
Loading…
Reference in New Issue
Block a user