Cleaned up ByteBuffer2 as self-growing bytearray structure. Fixed WINDOWS unbuffered input. Fixed UNSUPPORTED unbuffered input. Fixed POSIX unbuffered input

This commit is contained in:
nathan 2014-10-19 00:15:08 +02:00
parent 890d73e8aa
commit 227a0d9378
24 changed files with 3469 additions and 1789 deletions

View File

@ -373,8 +373,8 @@ public class Sys {
// NOTE: this saves the char array in UTF-16 format of bytes.
byte[] bytes = new byte[text.length*2];
for(int i=0; i<text.length; i++) {
bytes[2*i] = (byte) ((text[i] & 0xFF00)>>8);
bytes[2*i+1] = (byte) (text[i] & 0x00FF);
bytes[2*i] = (byte) (text[i] >> 8);
bytes[2*i+1] = (byte) text[i];
}
return bytes;
@ -754,7 +754,7 @@ public class Sys {
private static final void findModulesInJar(ClassLoader classLoader, String searchLocation,
Class<? extends Annotation> annotation, URL resource, List<Class<?>> annotatedClasses)
Class<? extends Annotation> annotation, URL resource, List<Class<?>> annotatedClasses)
throws IOException, ClassNotFoundException {
URLConnection connection = resource.openConnection();
@ -764,7 +764,6 @@ public class Sys {
JarURLConnection jarURLConnection = (JarURLConnection) connection;
JarFile jarFile = jarURLConnection.getJarFile();
String fileResource = jarURLConnection.getEntryName();
Enumeration<JarEntry> entries = jarFile.entries();
@ -773,8 +772,8 @@ public class Sys {
JarEntry jarEntry = entries.nextElement();
String name = jarEntry.getName();
if (name.startsWith(fileResource) && // make sure it's at least the correct package
isValid(name)) {
if (name.startsWith(searchLocation) && // make sure it's at least the correct package
isValid(name)) {
String classPath = name.replace(File.separatorChar, '.').substring(0, name.lastIndexOf("."));
@ -795,7 +794,9 @@ public class Sys {
// class files will not have an entry name, which is reserved for resources only
String name = hiveJarURLConnection.getResourceName();
if (isValid(name)) {
if (name.startsWith(searchLocation) && // make sure it's at least the correct package
isValid(name)) {
String classPath = name.substring(0, name.lastIndexOf('.'));
classPath = classPath.replace('/', '.');

View File

@ -1,120 +0,0 @@
package dorkbox.util.bytes;
import java.nio.ByteBuffer;
public class BigEndian {
// the following are ALL in Big-Endian (big is to the left, first byte is most significant, unsigned bytes)
/** SHORT to and from bytes */
public static class Short_ {
public static final short fromBytes(byte[] bytes) {
return fromBytes(bytes[0], bytes[1]);
}
public static final short fromBytes(byte b0, byte b1) {
return (short) ((b0 & 0xFF) << 8 |
(b1 & 0xFF) << 0);
}
public static final byte[] toBytes(short x) {
return new byte[] {(byte) (x >> 8),
(byte) (x >> 0)
};
}
public static final int fromBytes(ByteBuffer buff) {
return fromBytes(buff.get(), buff.get());
}
}
/** CHAR to and from bytes */
public static class Char_ {
public static final char fromBytes(byte[] bytes) {
return fromBytes(bytes[0], bytes[1]);
}
public static final char fromBytes(byte b0, byte b1) {
return (char) ((b0 & 0xFF) << 8 |
(b1 & 0xFF) << 0);
}
public static final byte[] toBytes(char x) {
return new byte[] {(byte) (x >> 8),
(byte) (x >> 0)
};
}
public static final int fromBytes(ByteBuffer buff) {
return fromBytes(buff.get(), buff.get());
}
}
/** INT to and from bytes */
public static class Int_ {
public static final int fromBytes(byte[] bytes) {
return fromBytes(bytes[0], bytes[1], bytes[2], bytes[3]);
}
public static final int fromBytes(byte b0, byte b1, byte b2, byte b3) {
return (b0 & 0xFF) << 24 |
(b1 & 0xFF) << 16 |
(b2 & 0xFF) << 8 |
(b3 & 0xFF) << 0;
}
public static int fromBytes(byte b0, byte b1) {
return (b0 & 0xFF) << 24 |
(b1 & 0xFF) << 16;
}
public static final byte[] toBytes(int x) {
return new byte[] {(byte) (x >> 24),
(byte) (x >> 16),
(byte) (x >> 8),
(byte) (x >> 0)
} ;
}
public static final int fromBytes(ByteBuffer buff) {
return fromBytes(buff.get(), buff.get(), buff.get(), buff.get());
}
}
/** LONG to and from bytes */
public static class Long_ {
public static final long fromBytes(byte[] bytes) {
return fromBytes(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]);
}
public static final long fromBytes(byte b0, byte b1, byte b2, byte b3, byte b4, byte b5, byte b6, byte b7) {
return (long) (b0 & 0xFF) << 56 |
(long) (b1 & 0xFF) << 48 |
(long) (b2 & 0xFF) << 40 |
(long) (b3 & 0xFF) << 32 |
(long) (b4 & 0xFF) << 24 |
(long) (b5 & 0xFF) << 16 |
(long) (b6 & 0xFF) << 8 |
(long) (b7 & 0xFF) << 0;
}
public static final byte[] toBytes (long x) {
return new byte[] {(byte) (x >> 56),
(byte) (x >> 48),
(byte) (x >> 40),
(byte) (x >> 32),
(byte) (x >> 24),
(byte) (x >> 16),
(byte) (x >> 8),
(byte) (x >> 0),
};
}
public static final long fromBytes(ByteBuffer buff) {
return fromBytes(buff.get(), buff.get(), buff.get(), buff.get(), buff.get(), buff.get(), buff.get(), buff.get());
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,338 +0,0 @@
package dorkbox.util.bytes;
import java.nio.BufferUnderflowException;
/**
* Cleanroom implementation of a self-growing bytebuffer. NOT SYNCHRONIZED!
*/
public class ByteBuffer2Fast {
private byte[] bytes;
private int position = 0;
private int mark = -1;
private int limit = 0;
public static ByteBuffer2Fast wrap(byte[] buffer) {
return new ByteBuffer2Fast(buffer);
}
public static ByteBuffer2Fast allocate(int capacity) {
ByteBuffer2Fast byteBuffer2 = new ByteBuffer2Fast(new byte[capacity]);
byteBuffer2.clear();
return byteBuffer2;
}
public ByteBuffer2Fast() {
this(0);
}
public ByteBuffer2Fast(int size) {
this(new byte[size]);
}
public ByteBuffer2Fast(byte[] bytes) {
this.bytes = bytes;
clear();
this.position = bytes.length;
}
public byte getByte() {
if (this.position > this.limit) {
throw new BufferUnderflowException();
}
return this.bytes[this.position++];
}
public byte getByte(int i) {
if (i > this.limit) {
throw new BufferUnderflowException();
}
return this.bytes[i];
}
public void getBytes(byte[] buffer) {
getBytes(buffer, 0, buffer.length);
}
public void getBytes(byte[] buffer, int length) {
getBytes(buffer, 0, length);
}
public void getBytes(byte[] buffer, int offset, int length) {
if (this.position + length - offset > this.limit) {
throw new BufferUnderflowException();
}
System.arraycopy(this.bytes, this.position, buffer, 0, length-offset);
this.position += length-offset;
}
/**
* MUST call checkBuffer before calling this!
*
* NOT PROTECTED
*/
private final void _put(byte b) {
this.bytes[this.position++] = b;
}
/** NOT PROTECTED! */
private final void checkBuffer(int threshold) {
if (this.bytes.length < threshold) {
byte[] t = new byte[threshold];
// grow at back of array
System.arraycopy(this.bytes, 0, t, 0, this.bytes.length);
this.limit = t.length;
this.bytes = t;
}
}
public final void put(ByteBuffer2Fast buffer) {
putBytes(buffer.array(), buffer.position, buffer.limit);
buffer.position = buffer.limit;
}
public final ByteBuffer2Fast putBytes(byte[] src) {
return putBytes(src, 0, src.length);
}
public final ByteBuffer2Fast putBytes(byte[] src, int offset, int length) {
checkBuffer(this.position + length - offset);
System.arraycopy(src, offset, this.bytes, this.position, length);
this.position += length;
return this;
}
public final ByteBuffer2Fast putByte(byte b) {
checkBuffer(this.position + 1);
_put(b);
return this;
}
public final void putByte(int position, byte b) {
this.position = position;
putByte(b);
}
public final void putChar(char c) {
checkBuffer(this.position + 2);
putBytes(BigEndian.Char_.toBytes(c));
}
public final char getChar() {
return BigEndian.Char_.fromBytes(getByte(), getByte());
}
public final char getChar(int i) {
return BigEndian.Char_.fromBytes(getByte(i++), getByte(i));
}
public void getChars(int srcStart, int srcLength, char[] dest, int destStart) {
for (int i=srcStart;i<srcLength;i+=2) {
char c = BigEndian.Char_.fromBytes(getByte(i), getByte(i+1));
dest[destStart++] = c;
}
}
public final ByteBuffer2Fast putShort(short x) {
checkBuffer(this.position + 2);
putBytes(BigEndian.Short_.toBytes(x));
return this;
}
public final short getShort() {
return BigEndian.Short_.fromBytes(getByte(), getByte());
}
public final short getShort(int i) {
return BigEndian.Short_.fromBytes(getByte(i++), getByte(i));
}
public final void putInt(int x) {
checkBuffer(this.position + 4);
putBytes(BigEndian.Int_.toBytes(x));
}
public final int getInt() {
return BigEndian.Int_.fromBytes(getByte(), getByte(), getByte(), getByte());
}
public final int getInt(int i) {
return BigEndian.Int_.fromBytes(getByte(i++), getByte(i++), getByte(i++), getByte(i++));
}
public final void putLong(long x) {
checkBuffer(this.position + 8);
putBytes(BigEndian.Long_.toBytes(x));
}
public final long getLong() {
return BigEndian.Long_.fromBytes(getByte(), getByte(), getByte(), getByte(), getByte(), getByte(), getByte(), getByte());
}
public final long getLong(int i) {
return BigEndian.Long_.fromBytes(getByte(i++), getByte(i++), getByte(i++), getByte(i++), getByte(i++), getByte(i++), getByte(i++), getByte(i++));
}
/**
* Returns the backing array of this buffer
*/
public byte[] array() {
return this.bytes;
}
/**
* Returns a copy of the backing array of this buffer
*/
public final byte[] arrayCopy() {
int length = this.bytes.length - this.position;
byte[] b = new byte[length];
System.arraycopy(this.bytes, this.position, b, 0, length);
return b;
}
/**
* Returns this buffer's position.
*/
public int position() {
return this.position;
}
/**
* Sets this buffer's position.
*/
public final ByteBuffer2Fast position(int position) {
if (position > this.bytes.length || position < 0) {
throw new IllegalArgumentException();
}
this.position = position;
if (this.mark > position) {
this.mark = -1;
}
return this;
}
/**
* Returns the number of elements between the current position and the
* limit.
*/
public final int remaining() {
return this.limit - this.position;
}
/**
* Tells whether there are any elements between the current position and
* the limit.
*/
public final boolean hasRemaining() {
return this.position < this.limit;
}
/**
* Sets this buffer's limit.
*/
public final void limit(int limit) {
this.limit = limit;
if (this.position > limit) {
this.position = limit;
}
if (this.mark > limit) {
this.mark = -1;
}
}
/**
* Returns this buffer's limit.
*/
public int limit() {
return this.limit;
}
/**
* Returns this buffer's capacity.
*/
public int capacity() {
return this.bytes.length;
}
/**
* The bytes between the buffer's current position and its limit, if any, are copied to the beginning of the buffer.
* That is, the byte at index p = position() is copied to index zero, the byte at index p + 1 is copied to index one,
* and so forth until the byte at index limit() - 1 is copied to index n = limit() - 1 - p. The buffer's position is
* then set to n+1 and its limit is set to its capacity. The mark, if defined, is discarded.
*
* The buffer's position is set to the number of bytes copied, rather than to zero, so that an invocation of this method
* can be followed immediately by an invocation of another relative put method.
*/
public final void compact() {
this.mark = -1;
System.arraycopy(this.bytes, this.position, this.bytes, 0, remaining());
position(remaining());
limit(capacity());
}
/**
* Readies the buffer for reading.
*
* Flips this buffer. The limit is set to the current position and then
* the position is set to zero. If the mark is defined then it is
* discarded.
*/
public final void flip() {
this.limit = this.position;
this.position = 0;
this.mark = -1;
}
/**
* Clears this buffer. The position is set to zero, the limit is set to
* the capacity, and the mark is discarded.
*/
public final void clear() {
this.position = 0;
this.limit = capacity();
this.mark = -1;
}
/**
* Rewinds this buffer. The position is set to zero and the mark is
* discarded.
*/
public final void rewind() {
this.position = 0;
this.mark = -1;
}
/**
* Sets this buffer's mark at its position.
*/
public final void mark() {
this.mark = this.position;
}
/**
* Resets this buffer's position to the previously-marked position.
*
* <p> Invoking this method neither changes nor discards the mark's
* value. </p>
*/
public void reset() {
this.position = this.mark;
}
}

View File

@ -0,0 +1,20 @@
package dorkbox.util.bytes;
import dorkbox.util.objectPool.PoolableObject;
public class ByteBuffer2Poolable implements PoolableObject<ByteBuffer2> {
@Override
public ByteBuffer2 create() {
return new ByteBuffer2(8, -1);
}
@Override
public void activate(ByteBuffer2 object) {
object.clear();
}
@Override
public void passivate(ByteBuffer2 object) {
}
}

View File

@ -2,6 +2,11 @@ package dorkbox.util.bytes;
import java.nio.ByteBuffer;
/**
* This is intel/amd/arm arch!
*
* arm is technically bi-endian
*/
public class LittleEndian {
// the following are ALL in Little-Endian (big is to the right, first byte is least significant, unsigned bytes)
@ -24,10 +29,9 @@ public class LittleEndian {
(b0 & 0xFF) << 0);
}
public static final byte[] toBytes(char x) {
return new byte[] {(byte) (x >> 8),
(byte) (x >> 0)
return new byte[] {(byte) (x >> 0),
(byte) (x >> 8)
};
}

View File

@ -1,541 +0,0 @@
package dorkbox.util.bytes;
public class OptimizeUtils {
private static final OptimizeUtils instance = new OptimizeUtils();
public static OptimizeUtils get() {
return instance;
}
// int
/**
* FROM KRYO
*
* Returns the number of bytes that would be written with {@link #writeInt(int, boolean)}.
*
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
*/
public final int intLength (int value, boolean optimizePositive) {
if (!optimizePositive) {
value = value << 1 ^ value >> 31;
}
if (value >>> 7 == 0) {
return 1;
}
if (value >>> 14 == 0) {
return 2;
}
if (value >>> 21 == 0) {
return 3;
}
if (value >>> 28 == 0) {
return 4;
}
return 5;
}
/**
* FROM KRYO
*
* look at buffer, and see if we can read the length of the int off of it. (from the reader index)
*/
public final boolean canReadInt (ByteBuffer2 buffer) {
int position = buffer.position();
try {
int remaining = buffer.remaining();
for (int offset = 0; offset < 32 && remaining > 0; offset += 7, remaining--) {
int b = buffer.getByte();
if ((b & 0x80) == 0) {
return true;
}
}
return false;
} finally {
buffer.position(position);
}
}
/**
* FROM KRYO
*
* look at buffer, and see if we can read the length of the int off of it. (from the reader index)
*
* @return 0 if we could not read anything, >0 for the number of bytes for the int on the buffer
*/
public boolean canReadInt (byte[] buffer) {
int length = buffer.length;
if (length >= 5) {
return true;
}
int p = 0;
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == length) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == length) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == length) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == length) {
return false;
}
return true;
}
/**
* FROM KRYO
*
* Reads an int from the buffer that was optimized.
*/
public final int readInt (ByteBuffer2 buffer, boolean optimizePositive) {
int b = buffer.getByte();
int result = b & 0x7F;
if ((b & 0x80) != 0) {
b = buffer.getByte();
result |= (b & 0x7F) << 7;
if ((b & 0x80) != 0) {
b = buffer.getByte();
result |= (b & 0x7F) << 14;
if ((b & 0x80) != 0) {
b = buffer.getByte();
result |= (b & 0x7F) << 21;
if ((b & 0x80) != 0) {
b = buffer.getByte();
result |= (b & 0x7F) << 28;
}
}
}
}
return optimizePositive ? result : result >>> 1 ^ -(result & 1);
}
/**
* FROM KRYO
*
* Reads an int from the buffer that was optimized.
*/
public int readInt (byte[] buffer, boolean optimizePositive) {
int position = 0;
int b = buffer[position++];
int result = b & 0x7F;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 7;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 14;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 21;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 28;
}
}
}
}
return optimizePositive ? result : result >>> 1 ^ -(result & 1);
}
/**
* FROM KRYO
*
* Writes the specified int to the buffer using 1 to 5 bytes, depending on the size of the number.
*
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
* @return the number of bytes written.
*/
public final int writeInt (ByteBuffer2 buffer, int value, boolean optimizePositive) {
if (!optimizePositive) {
value = value << 1 ^ value >> 31;
}
if (value >>> 7 == 0) {
buffer.putByte((byte)value);
return 1;
}
if (value >>> 14 == 0) {
buffer.putByte((byte)(value & 0x7F | 0x80));
buffer.putByte((byte)(value >>> 7));
return 2;
}
if (value >>> 21 == 0) {
buffer.putByte((byte)(value & 0x7F | 0x80));
buffer.putByte((byte)(value >>> 7 | 0x80));
buffer.putByte((byte)(value >>> 14));
return 3;
}
if (value >>> 28 == 0) {
buffer.putByte((byte)(value & 0x7F | 0x80));
buffer.putByte((byte)(value >>> 7 | 0x80));
buffer.putByte((byte)(value >>> 14 | 0x80));
buffer.putByte((byte)(value >>> 21));
return 4;
}
buffer.putByte((byte)(value & 0x7F | 0x80));
buffer.putByte((byte)(value >>> 7 | 0x80));
buffer.putByte((byte)(value >>> 14 | 0x80));
buffer.putByte((byte)(value >>> 21 | 0x80));
buffer.putByte((byte)(value >>> 28));
return 5;
}
/**
* FROM KRYO
*
* Writes the specified int to the buffer using 1 to 5 bytes, depending on the size of the number.
*
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
* @return the number of bytes written.
*/
public int writeInt (byte[] buffer, int value, boolean optimizePositive) {
int position = 0;
if (!optimizePositive) {
value = value << 1 ^ value >> 31;
}
if (value >>> 7 == 0) {
buffer[position++] = (byte)value;
return 1;
}
if (value >>> 14 == 0) {
buffer[position++] = (byte)(value & 0x7F | 0x80);
buffer[position++] = (byte)(value >>> 7);
return 2;
}
if (value >>> 21 == 0) {
buffer[position++] = (byte)(value & 0x7F | 0x80);
buffer[position++] = (byte)(value >>> 7 | 0x80);
buffer[position++] = (byte)(value >>> 14);
return 3;
}
if (value >>> 28 == 0) {
buffer[position++] = (byte)(value & 0x7F | 0x80);
buffer[position++] = (byte)(value >>> 7 | 0x80);
buffer[position++] = (byte)(value >>> 14 | 0x80);
buffer[position++] = (byte)(value >>> 21);
return 4;
}
buffer[position++] = (byte)(value & 0x7F | 0x80);
buffer[position++] = (byte)(value >>> 7 | 0x80);
buffer[position++] = (byte)(value >>> 14 | 0x80);
buffer[position++] = (byte)(value >>> 21 | 0x80);
buffer[position++] = (byte)(value >>> 28);
return 5;
}
// long
/**
* Returns the number of bytes that would be written with {@link #writeLong(long, boolean)}.
*
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
*/
public final int longLength (long value, boolean optimizePositive) {
if (!optimizePositive) {
value = value << 1 ^ value >> 63;
}
if (value >>> 7 == 0) {
return 1;
}
if (value >>> 14 == 0) {
return 2;
}
if (value >>> 21 == 0) {
return 3;
}
if (value >>> 28 == 0) {
return 4;
}
if (value >>> 35 == 0) {
return 5;
}
if (value >>> 42 == 0) {
return 6;
}
if (value >>> 49 == 0) {
return 7;
}
if (value >>> 56 == 0) {
return 8;
}
return 9;
}
/**
* FROM KRYO
*
* Reads a 1-9 byte long.
*
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
*/
public final long readLong (ByteBuffer2 buffer, boolean optimizePositive) {
int b = buffer.getByte();
long result = b & 0x7F;
if ((b & 0x80) != 0) {
b = buffer.getByte();
result |= (b & 0x7F) << 7;
if ((b & 0x80) != 0) {
b = buffer.getByte();
result |= (b & 0x7F) << 14;
if ((b & 0x80) != 0) {
b = buffer.getByte();
result |= (b & 0x7F) << 21;
if ((b & 0x80) != 0) {
b = buffer.getByte();
result |= (long)(b & 0x7F) << 28;
if ((b & 0x80) != 0) {
b = buffer.getByte();
result |= (long)(b & 0x7F) << 35;
if ((b & 0x80) != 0) {
b = buffer.getByte();
result |= (long)(b & 0x7F) << 42;
if ((b & 0x80) != 0) {
b = buffer.getByte();
result |= (long)(b & 0x7F) << 49;
if ((b & 0x80) != 0) {
b = buffer.getByte();
result |= (long)b << 56;
}
}
}
}
}
}
}
}
if (!optimizePositive) {
result = result >>> 1 ^ -(result & 1);
}
return result;
}
/**
* FROM KRYO
*
* Reads a 1-9 byte long.
*
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
*/
public long readLong (byte[] buffer, boolean optimizePositive) {
int position = 0;
int b = buffer[position++];
long result = b & 0x7F;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 7;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 14;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 21;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (long)(b & 0x7F) << 28;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (long)(b & 0x7F) << 35;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (long)(b & 0x7F) << 42;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (long)(b & 0x7F) << 49;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (long)b << 56;
}
}
}
}
}
}
}
}
if (!optimizePositive) {
result = result >>> 1 ^ -(result & 1);
}
return result;
}
/**
* FROM KRYO
*
* Writes a 1-9 byte long.
*
* @param optimizePositive If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be
* inefficient (9 bytes).
* @return the number of bytes written.
*/
public final int writeLong (ByteBuffer2 buffer, long value, boolean optimizePositive) {
if (!optimizePositive) {
value = value << 1 ^ value >> 63;
}
if (value >>> 7 == 0) {
buffer.putByte((byte)value);
return 1;
}
if (value >>> 14 == 0) {
buffer.putByte((byte)(value & 0x7F | 0x80));
buffer.putByte((byte)(value >>> 7));
return 2;
}
if (value >>> 21 == 0) {
buffer.putByte((byte)(value & 0x7F | 0x80));
buffer.putByte((byte)(value >>> 7 | 0x80));
buffer.putByte((byte)(value >>> 14));
return 3;
}
if (value >>> 28 == 0) {
buffer.putByte((byte)(value & 0x7F | 0x80));
buffer.putByte((byte)(value >>> 7 | 0x80));
buffer.putByte((byte)(value >>> 14 | 0x80));
buffer.putByte((byte)(value >>> 21));
return 4;
}
if (value >>> 35 == 0) {
buffer.putByte((byte)(value & 0x7F | 0x80));
buffer.putByte((byte)(value >>> 7 | 0x80));
buffer.putByte((byte)(value >>> 14 | 0x80));
buffer.putByte((byte)(value >>> 21 | 0x80));
buffer.putByte((byte)(value >>> 28));
return 5;
}
if (value >>> 42 == 0) {
buffer.putByte((byte)(value & 0x7F | 0x80));
buffer.putByte((byte)(value >>> 7 | 0x80));
buffer.putByte((byte)(value >>> 14 | 0x80));
buffer.putByte((byte)(value >>> 21 | 0x80));
buffer.putByte((byte)(value >>> 28 | 0x80));
buffer.putByte((byte)(value >>> 35));
return 6;
}
if (value >>> 49 == 0) {
buffer.putByte((byte)(value & 0x7F | 0x80));
buffer.putByte((byte)(value >>> 7 | 0x80));
buffer.putByte((byte)(value >>> 14 | 0x80));
buffer.putByte((byte)(value >>> 21 | 0x80));
buffer.putByte((byte)(value >>> 28 | 0x80));
buffer.putByte((byte)(value >>> 35 | 0x80));
buffer.putByte((byte)(value >>> 42));
return 7;
}
if (value >>> 56 == 0) {
buffer.putByte((byte)(value & 0x7F | 0x80));
buffer.putByte((byte)(value >>> 7 | 0x80));
buffer.putByte((byte)(value >>> 14 | 0x80));
buffer.putByte((byte)(value >>> 21 | 0x80));
buffer.putByte((byte)(value >>> 28 | 0x80));
buffer.putByte((byte)(value >>> 35 | 0x80));
buffer.putByte((byte)(value >>> 42 | 0x80));
buffer.putByte((byte)(value >>> 49));
return 8;
}
buffer.putByte((byte)(value & 0x7F | 0x80));
buffer.putByte((byte)(value >>> 7 | 0x80));
buffer.putByte((byte)(value >>> 14 | 0x80));
buffer.putByte((byte)(value >>> 21 | 0x80));
buffer.putByte((byte)(value >>> 28 | 0x80));
buffer.putByte((byte)(value >>> 35 | 0x80));
buffer.putByte((byte)(value >>> 42 | 0x80));
buffer.putByte((byte)(value >>> 49 | 0x80));
buffer.putByte((byte)(value >>> 56));
return 9;
}
/**
* FROM KRYO
*
* look at buffer, and see if we can read the length of the long off of it (from the reader index).
*/
public final boolean canReadLong (ByteBuffer2 buffer) {
int position = buffer.position();
try {
int remaining = buffer.remaining();
for (int offset = 0; offset < 64 && remaining > 0; offset += 7, remaining--) {
int b = buffer.getByte();
if ((b & 0x80) == 0) {
return true;
}
}
return false;
} finally {
buffer.position(position);
}
}
public boolean canReadLong (byte[] buffer) {
int limit = buffer.length;
if (limit >= 9) {
return true;
}
int p = 0;
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == limit) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == limit) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == limit) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == limit) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == limit) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == limit) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == limit) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == limit) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,284 @@
package dorkbox.util.bytes;
public class OptimizeUtilsByteArray {
private static final OptimizeUtilsByteArray instance = new OptimizeUtilsByteArray();
public static OptimizeUtilsByteArray get() {
return instance;
}
private OptimizeUtilsByteArray() {
}
// int
/**
* FROM KRYO
*
* Returns the number of bytes that would be written with {@link #writeInt(int, boolean)}.
*
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
*/
public final int intLength (int value, boolean optimizePositive) {
return ByteBuffer2.intLength(value, optimizePositive);
}
/**
* FROM KRYO
*
* look at buffer, and see if we can read the length of the int off of it. (from the reader index)
*
* @return 0 if we could not read anything, >0 for the number of bytes for the int on the buffer
*/
public boolean canReadInt(byte[] buffer) {
int length = buffer.length;
if (length >= 5) {
return true;
}
int p = 0;
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == length) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == length) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == length) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == length) {
return false;
}
return true;
}
/**
* FROM KRYO
*
* Reads an int from the buffer that was optimized.
*/
public int readInt (byte[] buffer, boolean optimizePositive) {
int position = 0;
int b = buffer[position++];
int result = b & 0x7F;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 7;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 14;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 21;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 28;
}
}
}
}
return optimizePositive ? result : result >>> 1 ^ -(result & 1);
}
/**
* FROM KRYO
*
* Writes the specified int to the buffer using 1 to 5 bytes, depending on the size of the number.
*
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
* @return the number of bytes written.
*/
public int writeInt (byte[] buffer, int value, boolean optimizePositive) {
int position = 0;
if (!optimizePositive) {
value = value << 1 ^ value >> 31;
}
if (value >>> 7 == 0) {
buffer[position++] = (byte)value;
return 1;
}
if (value >>> 14 == 0) {
buffer[position++] = (byte)(value & 0x7F | 0x80);
buffer[position++] = (byte)(value >>> 7);
return 2;
}
if (value >>> 21 == 0) {
buffer[position++] = (byte)(value & 0x7F | 0x80);
buffer[position++] = (byte)(value >>> 7 | 0x80);
buffer[position++] = (byte)(value >>> 14);
return 3;
}
if (value >>> 28 == 0) {
buffer[position++] = (byte)(value & 0x7F | 0x80);
buffer[position++] = (byte)(value >>> 7 | 0x80);
buffer[position++] = (byte)(value >>> 14 | 0x80);
buffer[position++] = (byte)(value >>> 21);
return 4;
}
buffer[position++] = (byte)(value & 0x7F | 0x80);
buffer[position++] = (byte)(value >>> 7 | 0x80);
buffer[position++] = (byte)(value >>> 14 | 0x80);
buffer[position++] = (byte)(value >>> 21 | 0x80);
buffer[position++] = (byte)(value >>> 28);
return 5;
}
// long
/**
* Returns the number of bytes that would be written with {@link #writeLong(long, boolean)}.
*
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
*/
public final int longLength (long value, boolean optimizePositive) {
if (!optimizePositive) {
value = value << 1 ^ value >> 63;
}
if (value >>> 7 == 0) {
return 1;
}
if (value >>> 14 == 0) {
return 2;
}
if (value >>> 21 == 0) {
return 3;
}
if (value >>> 28 == 0) {
return 4;
}
if (value >>> 35 == 0) {
return 5;
}
if (value >>> 42 == 0) {
return 6;
}
if (value >>> 49 == 0) {
return 7;
}
if (value >>> 56 == 0) {
return 8;
}
return 9;
}
/**
* FROM KRYO
*
* Reads a 1-9 byte long.
*
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
*/
public long readLong (byte[] buffer, boolean optimizePositive) {
int position = 0;
int b = buffer[position++];
long result = b & 0x7F;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 7;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 14;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 21;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (long)(b & 0x7F) << 28;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (long)(b & 0x7F) << 35;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (long)(b & 0x7F) << 42;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (long)(b & 0x7F) << 49;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (long)b << 56;
}
}
}
}
}
}
}
}
if (!optimizePositive) {
result = result >>> 1 ^ -(result & 1);
}
return result;
}
public boolean canReadLong (byte[] buffer) {
int limit = buffer.length;
if (limit >= 9) {
return true;
}
int p = 0;
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == limit) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == limit) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == limit) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == limit) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == limit) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == limit) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == limit) {
return false;
}
if ((buffer[p++] & 0x80) == 0) {
return true;
}
if (p == limit) {
return false;
}
return true;
}
}

View File

@ -17,14 +17,25 @@ public class OptimizeUtilsByteBuf {
*
* Returns the number of bytes that would be written with {@link #writeInt(int, boolean)}.
*
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
* @param optimizePositive
* true if you want to optimize the number of bytes needed to write the length value
*/
public final int intLength (int value, boolean optimizePositive) {
if (!optimizePositive) value = (value << 1) ^ (value >> 31);
if (value >>> 7 == 0) return 1;
if (value >>> 14 == 0) return 2;
if (value >>> 21 == 0) return 3;
if (value >>> 28 == 0) return 4;
public final int intLength(int value, boolean optimizePositive) {
if (!optimizePositive) {
value = value << 1 ^ value >> 31;
}
if (value >>> 7 == 0) {
return 1;
}
if (value >>> 14 == 0) {
return 2;
}
if (value >>> 21 == 0) {
return 3;
}
if (value >>> 28 == 0) {
return 4;
}
return 5;
}
@ -35,7 +46,7 @@ public class OptimizeUtilsByteBuf {
*
* @return 0 if we could not read anything, >0 for the number of bytes for the int on the buffer
*/
public final int canReadInt (ByteBuf buffer) {
public final int canReadInt(ByteBuf buffer) {
int startIndex = buffer.readerIndex();
try {
int remaining = buffer.readableBytes();
@ -56,7 +67,7 @@ public class OptimizeUtilsByteBuf {
*
* Reads an int from the buffer that was optimized.
*/
public final int readInt (ByteBuf buffer, boolean optimizePositive) {
public final int readInt(ByteBuf buffer, boolean optimizePositive) {
int b = buffer.readByte();
int result = b & 0x7F;
if ((b & 0x80) != 0) {
@ -75,70 +86,88 @@ public class OptimizeUtilsByteBuf {
}
}
}
return optimizePositive ? result : ((result >>> 1) ^ -(result & 1));
return optimizePositive ? result : result >>> 1 ^ -(result & 1);
}
/**
* FROM KRYO
*
* Writes the specified int to the buffer using 1 to 5 bytes, depending on the size of the number.
*
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
* @param optimizePositive
* true if you want to optimize the number of bytes needed to write the length value
* @return the number of bytes written.
*/
public final int writeInt (ByteBuf buffer, int value, boolean optimizePositive) {
if (!optimizePositive) value = (value << 1) ^ (value >> 31);
public final int writeInt(ByteBuf buffer, int value, boolean optimizePositive) {
if (!optimizePositive) {
value = value << 1 ^ value >> 31;
}
if (value >>> 7 == 0) {
buffer.writeByte((byte)value);
buffer.writeByte((byte) value);
return 1;
}
if (value >>> 14 == 0) {
buffer.writeByte((byte)((value & 0x7F) | 0x80));
buffer.writeByte((byte)(value >>> 7));
buffer.writeByte((byte) (value & 0x7F | 0x80));
buffer.writeByte((byte) (value >>> 7));
return 2;
}
if (value >>> 21 == 0) {
buffer.writeByte((byte)((value & 0x7F) | 0x80));
buffer.writeByte((byte)(value >>> 7 | 0x80));
buffer.writeByte((byte)(value >>> 14));
buffer.writeByte((byte) (value & 0x7F | 0x80));
buffer.writeByte((byte) (value >>> 7 | 0x80));
buffer.writeByte((byte) (value >>> 14));
return 3;
}
if (value >>> 28 == 0) {
buffer.writeByte((byte)((value & 0x7F) | 0x80));
buffer.writeByte((byte)(value >>> 7 | 0x80));
buffer.writeByte((byte)(value >>> 14 | 0x80));
buffer.writeByte((byte)(value >>> 21));
buffer.writeByte((byte) (value & 0x7F | 0x80));
buffer.writeByte((byte) (value >>> 7 | 0x80));
buffer.writeByte((byte) (value >>> 14 | 0x80));
buffer.writeByte((byte) (value >>> 21));
return 4;
}
buffer.writeByte((byte)((value & 0x7F) | 0x80));
buffer.writeByte((byte)(value >>> 7 | 0x80));
buffer.writeByte((byte)(value >>> 14 | 0x80));
buffer.writeByte((byte)(value >>> 21 | 0x80));
buffer.writeByte((byte)(value >>> 28));
buffer.writeByte((byte) (value & 0x7F | 0x80));
buffer.writeByte((byte) (value >>> 7 | 0x80));
buffer.writeByte((byte) (value >>> 14 | 0x80));
buffer.writeByte((byte) (value >>> 21 | 0x80));
buffer.writeByte((byte) (value >>> 28));
return 5;
}
// long
/**
* Returns the number of bytes that would be written with {@link #writeLong(long, boolean)}.
*
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
* @param optimizePositive
* true if you want to optimize the number of bytes needed to write the length value
*/
public final int longLength (long value, boolean optimizePositive) {
if (!optimizePositive) value = (value << 1) ^ (value >> 63);
if (value >>> 7 == 0) return 1;
if (value >>> 14 == 0) return 2;
if (value >>> 21 == 0) return 3;
if (value >>> 28 == 0) return 4;
if (value >>> 35 == 0) return 5;
if (value >>> 42 == 0) return 6;
if (value >>> 49 == 0) return 7;
if (value >>> 56 == 0) return 8;
public final int longLength(long value, boolean optimizePositive) {
if (!optimizePositive) {
value = value << 1 ^ value >> 63;
}
if (value >>> 7 == 0) {
return 1;
}
if (value >>> 14 == 0) {
return 2;
}
if (value >>> 21 == 0) {
return 3;
}
if (value >>> 28 == 0) {
return 4;
}
if (value >>> 35 == 0) {
return 5;
}
if (value >>> 42 == 0) {
return 6;
}
if (value >>> 49 == 0) {
return 7;
}
if (value >>> 56 == 0) {
return 8;
}
return 9;
}
@ -147,9 +176,10 @@ public class OptimizeUtilsByteBuf {
*
* Reads a 1-9 byte long.
*
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
* @param optimizePositive
* true if you want to optimize the number of bytes needed to write the length value
*/
public final long readLong (ByteBuf buffer, boolean optimizePositive) {
public final long readLong(ByteBuf buffer, boolean optimizePositive) {
int b = buffer.readByte();
long result = b & 0x7F;
if ((b & 0x80) != 0) {
@ -163,19 +193,19 @@ public class OptimizeUtilsByteBuf {
result |= (b & 0x7F) << 21;
if ((b & 0x80) != 0) {
b = buffer.readByte();
result |= (long)(b & 0x7F) << 28;
result |= (long) (b & 0x7F) << 28;
if ((b & 0x80) != 0) {
b = buffer.readByte();
result |= (long)(b & 0x7F) << 35;
result |= (long) (b & 0x7F) << 35;
if ((b & 0x80) != 0) {
b = buffer.readByte();
result |= (long)(b & 0x7F) << 42;
result |= (long) (b & 0x7F) << 42;
if ((b & 0x80) != 0) {
b = buffer.readByte();
result |= (long)(b & 0x7F) << 49;
result |= (long) (b & 0x7F) << 49;
if ((b & 0x80) != 0) {
b = buffer.readByte();
result |= (long)b << 56;
result |= (long) b << 56;
}
}
}
@ -184,91 +214,95 @@ public class OptimizeUtilsByteBuf {
}
}
}
if (!optimizePositive) result = (result >>> 1) ^ -(result & 1);
if (!optimizePositive) {
result = result >>> 1 ^ -(result & 1);
}
return result;
}
/**
* FROM KRYO
*
* Writes a 1-9 byte long.
*
* @param optimizePositive If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be
* inefficient (9 bytes).
* @param optimizePositive
* If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be
* inefficient (9 bytes).
* @return the number of bytes written.
*/
public final int writeLong (ByteBuf buffer, long value, boolean optimizePositive) {
if (!optimizePositive) value = (value << 1) ^ (value >> 63);
public final int writeLong(ByteBuf buffer, long value, boolean optimizePositive) {
if (!optimizePositive) {
value = value << 1 ^ value >> 63;
}
if (value >>> 7 == 0) {
buffer.writeByte((byte)value);
buffer.writeByte((byte) value);
return 1;
}
if (value >>> 14 == 0) {
buffer.writeByte((byte)((value & 0x7F) | 0x80));
buffer.writeByte((byte)(value >>> 7));
buffer.writeByte((byte) (value & 0x7F | 0x80));
buffer.writeByte((byte) (value >>> 7));
return 2;
}
if (value >>> 21 == 0) {
buffer.writeByte((byte)((value & 0x7F) | 0x80));
buffer.writeByte((byte)(value >>> 7 | 0x80));
buffer.writeByte((byte)(value >>> 14));
buffer.writeByte((byte) (value & 0x7F | 0x80));
buffer.writeByte((byte) (value >>> 7 | 0x80));
buffer.writeByte((byte) (value >>> 14));
return 3;
}
if (value >>> 28 == 0) {
buffer.writeByte((byte)((value & 0x7F) | 0x80));
buffer.writeByte((byte)(value >>> 7 | 0x80));
buffer.writeByte((byte)(value >>> 14 | 0x80));
buffer.writeByte((byte)(value >>> 21));
buffer.writeByte((byte) (value & 0x7F | 0x80));
buffer.writeByte((byte) (value >>> 7 | 0x80));
buffer.writeByte((byte) (value >>> 14 | 0x80));
buffer.writeByte((byte) (value >>> 21));
return 4;
}
if (value >>> 35 == 0) {
buffer.writeByte((byte)((value & 0x7F) | 0x80));
buffer.writeByte((byte)(value >>> 7 | 0x80));
buffer.writeByte((byte)(value >>> 14 | 0x80));
buffer.writeByte((byte)(value >>> 21 | 0x80));
buffer.writeByte((byte)(value >>> 28));
buffer.writeByte((byte) (value & 0x7F | 0x80));
buffer.writeByte((byte) (value >>> 7 | 0x80));
buffer.writeByte((byte) (value >>> 14 | 0x80));
buffer.writeByte((byte) (value >>> 21 | 0x80));
buffer.writeByte((byte) (value >>> 28));
return 5;
}
if (value >>> 42 == 0) {
buffer.writeByte((byte)((value & 0x7F) | 0x80));
buffer.writeByte((byte)(value >>> 7 | 0x80));
buffer.writeByte((byte)(value >>> 14 | 0x80));
buffer.writeByte((byte)(value >>> 21 | 0x80));
buffer.writeByte((byte)(value >>> 28 | 0x80));
buffer.writeByte((byte)(value >>> 35));
buffer.writeByte((byte) (value & 0x7F | 0x80));
buffer.writeByte((byte) (value >>> 7 | 0x80));
buffer.writeByte((byte) (value >>> 14 | 0x80));
buffer.writeByte((byte) (value >>> 21 | 0x80));
buffer.writeByte((byte) (value >>> 28 | 0x80));
buffer.writeByte((byte) (value >>> 35));
return 6;
}
if (value >>> 49 == 0) {
buffer.writeByte((byte)((value & 0x7F) | 0x80));
buffer.writeByte((byte)(value >>> 7 | 0x80));
buffer.writeByte((byte)(value >>> 14 | 0x80));
buffer.writeByte((byte)(value >>> 21 | 0x80));
buffer.writeByte((byte)(value >>> 28 | 0x80));
buffer.writeByte((byte)(value >>> 35 | 0x80));
buffer.writeByte((byte)(value >>> 42));
buffer.writeByte((byte) (value & 0x7F | 0x80));
buffer.writeByte((byte) (value >>> 7 | 0x80));
buffer.writeByte((byte) (value >>> 14 | 0x80));
buffer.writeByte((byte) (value >>> 21 | 0x80));
buffer.writeByte((byte) (value >>> 28 | 0x80));
buffer.writeByte((byte) (value >>> 35 | 0x80));
buffer.writeByte((byte) (value >>> 42));
return 7;
}
if (value >>> 56 == 0) {
buffer.writeByte((byte)((value & 0x7F) | 0x80));
buffer.writeByte((byte)(value >>> 7 | 0x80));
buffer.writeByte((byte)(value >>> 14 | 0x80));
buffer.writeByte((byte)(value >>> 21 | 0x80));
buffer.writeByte((byte)(value >>> 28 | 0x80));
buffer.writeByte((byte)(value >>> 35 | 0x80));
buffer.writeByte((byte)(value >>> 42 | 0x80));
buffer.writeByte((byte)(value >>> 49));
buffer.writeByte((byte) (value & 0x7F | 0x80));
buffer.writeByte((byte) (value >>> 7 | 0x80));
buffer.writeByte((byte) (value >>> 14 | 0x80));
buffer.writeByte((byte) (value >>> 21 | 0x80));
buffer.writeByte((byte) (value >>> 28 | 0x80));
buffer.writeByte((byte) (value >>> 35 | 0x80));
buffer.writeByte((byte) (value >>> 42 | 0x80));
buffer.writeByte((byte) (value >>> 49));
return 8;
}
buffer.writeByte((byte)((value & 0x7F) | 0x80));
buffer.writeByte((byte)(value >>> 7 | 0x80));
buffer.writeByte((byte)(value >>> 14 | 0x80));
buffer.writeByte((byte)(value >>> 21 | 0x80));
buffer.writeByte((byte)(value >>> 28 | 0x80));
buffer.writeByte((byte)(value >>> 35 | 0x80));
buffer.writeByte((byte)(value >>> 42 | 0x80));
buffer.writeByte((byte)(value >>> 49 | 0x80));
buffer.writeByte((byte)(value >>> 56));
buffer.writeByte((byte) (value & 0x7F | 0x80));
buffer.writeByte((byte) (value >>> 7 | 0x80));
buffer.writeByte((byte) (value >>> 14 | 0x80));
buffer.writeByte((byte) (value >>> 21 | 0x80));
buffer.writeByte((byte) (value >>> 28 | 0x80));
buffer.writeByte((byte) (value >>> 35 | 0x80));
buffer.writeByte((byte) (value >>> 42 | 0x80));
buffer.writeByte((byte) (value >>> 49 | 0x80));
buffer.writeByte((byte) (value >>> 56));
return 9;
}
@ -279,7 +313,7 @@ public class OptimizeUtilsByteBuf {
*
* @return 0 if we could not read anything, >0 for the number of bytes for the long on the buffer
*/
public final int canReadLong (ByteBuf buffer) {
public final int canReadLong(ByteBuf buffer) {
int position = buffer.readerIndex();
try {
int remaining = buffer.readableBytes();

View File

@ -0,0 +1,38 @@
package dorkbox.util.input;
import java.nio.charset.Charset;
public class Encoding {
/**
* Get the default encoding. Will first look at the LC_CTYPE environment variable, then the input.encoding
* system property, then the default charset according to the JVM.
*
* @return The default encoding to use when none is specified.
*/
public static String get() {
// LC_CTYPE is usually in the form en_US.UTF-8
String envEncoding = extractEncodingFromCtype(System.getenv("LC_CTYPE"));
if (envEncoding != null) {
return envEncoding;
}
return System.getProperty("input.encoding", Charset.defaultCharset().name());
}
/**
* Parses the LC_CTYPE value to extract the encoding according to the POSIX standard, which says that the LC_CTYPE
* environment variable may be of the format <code>[language[_territory][.codeset][@modifier]]</code>
*
* @param ctype The ctype to parse, may be null
* @return The encoding, if one was present, otherwise null
*/
private static String extractEncodingFromCtype(String ctype) {
if (ctype != null && ctype.indexOf('.') > 0) {
String encodingAndModifier = ctype.substring(ctype.indexOf('.') + 1);
if (encodingAndModifier.indexOf('@') > 0) {
return encodingAndModifier.substring(0, encodingAndModifier.indexOf('@'));
}
return encodingAndModifier;
}
return null;
}
}

View File

@ -1,14 +1,11 @@
package dorkbox.util.input;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.concurrent.CopyOnWriteArrayList;
@ -18,11 +15,14 @@ import org.fusesource.jansi.AnsiConsole;
import org.slf4j.Logger;
import dorkbox.util.OS;
import dorkbox.util.Sys;
import dorkbox.util.bytes.ByteBuffer2Fast;
import dorkbox.util.bytes.ByteBuffer2;
import dorkbox.util.bytes.ByteBuffer2Poolable;
import dorkbox.util.input.posix.UnixTerminal;
import dorkbox.util.input.unsupported.UnsupportedTerminal;
import dorkbox.util.input.windows.WindowsTerminal;
import dorkbox.util.objectPool.ObjectPool;
import dorkbox.util.objectPool.ObjectPoolFactory;
import dorkbox.util.objectPool.ObjectPoolHolder;
public class InputConsole {
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(InputConsole.class);
@ -108,30 +108,15 @@ public class InputConsole {
private final Object inputLockSingle = new Object();
private final Object inputLockLine = new Object();
private ThreadLocal<ByteBuffer2Fast> threadBufferForRead = new ThreadLocal<ByteBuffer2Fast>();
private CopyOnWriteArrayList<ByteBuffer2Fast> threadBuffersForRead = new CopyOnWriteArrayList<ByteBuffer2Fast>();
ThreadLocal<Integer> indexOfStringForReadChar = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return -1;
}
};
private final ObjectPool<ByteBuffer2> pool = ObjectPoolFactory.create(new ByteBuffer2Poolable());
private ThreadLocal<ObjectPoolHolder<ByteBuffer2>> threadBufferForRead = new ThreadLocal<ObjectPoolHolder<ByteBuffer2>>();
private CopyOnWriteArrayList<ObjectPoolHolder<ByteBuffer2>> threadBuffersForRead = new CopyOnWriteArrayList<ObjectPoolHolder<ByteBuffer2>>();
private volatile int readChar = -1;
private final boolean unsupported;
private final Terminal terminal;
private Reader reader;
private final String encoding;
private InputConsole() {
Logger logger = InputConsole.logger;
boolean unsupported = false;
String type = System.getProperty(TerminalType.TYPE, TerminalType.AUTO).toLowerCase();
if ("dumb".equals(System.getenv("TERM"))) {
@ -141,48 +126,42 @@ public class InputConsole {
logger.debug("Creating terminal; type={}", type);
Terminal t;
String encoding = Encoding.get();
Terminal t;
try {
if (type.equals(TerminalType.UNIX)) {
t = new UnixTerminal();
t = new UnixTerminal(encoding);
}
else if (type.equals(TerminalType.WIN) || type.equals(TerminalType.WINDOWS)) {
t = new WindowsTerminal();
}
else if (type.equals(TerminalType.NONE) || type.equals(TerminalType.OFF) || type.equals(TerminalType.FALSE)) {
t = new UnsupportedTerminal();
unsupported = true;
t = new UnsupportedTerminal(encoding);
} else {
if (isIDEAutoDetect()) {
logger.debug("Terminal is in UNSUPPORTED (best guess). Unable to support single key input. Only line input available.");
t = new UnsupportedTerminal();
unsupported = true;
t = new UnsupportedTerminal(encoding);
} else {
if (OS.isWindows()) {
t = new WindowsTerminal();
} else {
t = new UnixTerminal();
t = new UnixTerminal(encoding);
}
}
}
}
catch (Exception e) {
logger.error("Failed to construct terminal, falling back to unsupported");
t = new UnsupportedTerminal();
unsupported = true;
t = new UnsupportedTerminal(encoding);
}
InputStream in;
try {
t.init();
in = t.wrapInIfNeeded(System.in);
}
catch (Throwable e) {
logger.error("Terminal initialization failed, falling back to unsupported");
t = new UnsupportedTerminal();
unsupported = true;
in = System.in;
t = new UnsupportedTerminal(encoding);
try {
t.init();
@ -191,17 +170,10 @@ public class InputConsole {
}
}
this.encoding = this.encoding != null ? this.encoding : getEncoding();
this.reader = new InputStreamReader(in, this.encoding);
t.setEchoEnabled(true);
if (unsupported) {
this.reader = new BufferedReader(this.reader);
}
this.unsupported = unsupported;
this.terminal = t;
logger.debug("Created Terminal: {}", this.terminal);
logger.debug("Created Terminal: {} ({}x{})", this.terminal.getClass().getSimpleName(), t.getWidth(), t.getHeight());
}
// called when the JVM is shutting down.
@ -237,9 +209,9 @@ public class InputConsole {
/** return null if no data */
private final char[] readLine0() {
if (this.threadBufferForRead.get() == null) {
ByteBuffer2Fast buffer = ByteBuffer2Fast.allocate(0);
this.threadBufferForRead.set(buffer);
this.threadBuffersForRead.add(buffer);
ObjectPoolHolder<ByteBuffer2> holder = this.pool.take();
this.threadBufferForRead.set(holder);
this.threadBuffersForRead.add(holder);
}
synchronized (this.inputLockLine) {
@ -250,33 +222,28 @@ public class InputConsole {
}
}
ByteBuffer2Fast stringBuffer = this.threadBufferForRead.get();
int len = stringBuffer.position();
ObjectPoolHolder<ByteBuffer2> objectPoolHolder = this.threadBufferForRead.get();
ByteBuffer2 buffer = objectPoolHolder.getValue();
int len = buffer.position();
if (len == 0) {
return emptyLine;
}
char[] chars = new char[len/2]; // because 2 chars is 1 bytes
stringBuffer.getChars(0, len, chars, 0);
buffer.rewind();
char[] readChars = buffer.readChars(len/2); // java always stores chars in 2 bytes
// dump the chars in the buffer (safer for passwords, etc)
stringBuffer.clear();
stringBuffer.putBytes(new byte[0]);
buffer.clearSecure();
this.threadBuffersForRead.remove(objectPoolHolder);
this.pool.release(objectPoolHolder);
this.threadBufferForRead.set(null);
this.threadBuffersForRead.remove(stringBuffer); // TODO: use object pool!
return chars;
return readChars;
}
/** return null if no data */
private final char[] readLinePassword0() {
if (this.threadBufferForRead.get() == null) {
ByteBuffer2Fast buffer = ByteBuffer2Fast.allocate(0);
this.threadBufferForRead.set(buffer);
this.threadBuffersForRead.add(buffer);
}
// don't bother in an IDE. it won't work.
boolean echoEnabled = this.terminal.isEchoEnabled();
this.terminal.setEchoEnabled(false);
@ -288,51 +255,15 @@ public class InputConsole {
/** return -1 if no data */
private final int read0() {
// if we are reading data (because we are in IDE mode), we want to return ALL
// the chars of the line!
// so, readChar is REALLY the index at which we return letters (until the whole string is returned
if (this.unsupported) {
int readerCount = this.indexOfStringForReadChar.get();
if (readerCount == -1) {
// we have to wait for more data.
synchronized (this.inputLockLine) {
try {
this.inputLockLine.wait();
} catch (InterruptedException e) {
return -1;
}
readerCount = 0;
this.indexOfStringForReadChar.set(0);
}
synchronized (this.inputLockSingle) {
try {
this.inputLockSingle.wait();
} catch (InterruptedException e) {
return -1;
}
// EACH thread will have it's own count!
ByteBuffer2Fast stringBuffer = this.threadBufferForRead.get();
if (readerCount == stringBuffer.position()) {
this.indexOfStringForReadChar.set(-1);
return '\n';
} else {
this.indexOfStringForReadChar.set(readerCount+1);
}
char c = stringBuffer.getChar(readerCount);
return c;
}
else {
// we can read like normal.
synchronized (this.inputLockSingle) {
try {
this.inputLockSingle.wait();
} catch (InterruptedException e) {
return -1;
}
}
return this.readChar;
}
return this.readChar;
}
/**
@ -351,163 +282,98 @@ public class InputConsole {
private final void run() {
Logger logger2 = logger;
// if we are eclipse/etc, we MUST do this per line! (per character DOESN'T work.)
// char readers will get looped for the WHOLE string, so reading by char will work,
// it just waits until \n until it triggers
if (this.unsupported) {
BufferedReader reader = (BufferedReader) this.reader;
String line = null;
char[] readLine = null;
final boolean ansiEnabled = Ansi.isEnabled();
Ansi ansi = Ansi.ansi();
PrintStream out = AnsiConsole.out;
try {
while ((line = reader.readLine()) != null) {
readLine = line.toCharArray();
int typedChar;
char asChar;
// notify everyone waiting for a line of text.
synchronized (this.inputLockSingle) {
if (readLine.length > 0) {
this.readChar = readLine[0];
} else {
this.readChar = -1;
}
this.inputLockSingle.notifyAll();
}
synchronized (this.inputLockLine) {
byte[] charToBytes = Sys.charToBytes(readLine);
// don't type ; in a bash shell, it quits everything
// \n is replaced by \r in unix terminal?
while ((typedChar = this.terminal.read()) != -1) {
asChar = (char) typedChar;
for (ByteBuffer2Fast buffer : this.threadBuffersForRead) {
buffer.clear();
buffer.putBytes(charToBytes);
}
this.inputLockLine.notifyAll();
}
}
} catch (Exception ignored) {
ignored.printStackTrace();
if (logger2.isTraceEnabled()) {
logger2.trace("READ: {} ({})", asChar, typedChar);
}
}
else {
// from a 'regular' console
try {
final boolean ansiEnabled = Ansi.isEnabled();
Ansi ansi = Ansi.ansi();
PrintStream out = AnsiConsole.out;
int typedChar;
// notify everyone waiting for a character.
synchronized (this.inputLockSingle) {
if (this.terminal.wasSequence() && typedChar == '\n') {
// don't want to forward \n if it was a part of a sequence in the unsupported terminal
// the JIT will short-cut this out if we are not the unsupported terminal
} else {
this.readChar = typedChar;
this.inputLockSingle.notifyAll();
}
}
// don't type ; in a bash shell, it quits everything
// \n is replaced by \r in unix terminal?
while ((typedChar = this.reader.read()) != -1) {
char asChar = (char) typedChar;
// if we type a backspace key, swallow it + previous in READLINE. READCHAR will have it passed.
if (typedChar == '\b') {
int position = 0;
if (logger2.isTraceEnabled()) {
logger2.trace("READ: {} ({})", asChar, typedChar);
}
// clear ourself + one extra.
if (ansiEnabled) {
for (ObjectPoolHolder<ByteBuffer2> objectPoolHolder : this.threadBuffersForRead) {
ByteBuffer2 buffer = objectPoolHolder.getValue();
// size of the buffer BEFORE our backspace was typed
int length = buffer.position();
int amtToOverwrite = 2 * 2; // backspace is always 2 chars (^?) * 2 because it's bytes
// notify everyone waiting for a character.
synchronized (this.inputLockSingle) {
this.readChar = typedChar;
this.inputLockSingle.notifyAll();
}
if (length > 1) {
char charAt = buffer.readChar(length-2);
amtToOverwrite += getPrintableCharacters(charAt);
// if we type a backspace key, swallow it + previous in READLINE. READCHAR will have it passed.
if (typedChar == 127) {
int position = 0;
// delete last item in our buffer
length -= 2;
buffer.setPosition(length);
// clear ourself + one extra.
if (ansiEnabled) {
for (ByteBuffer2Fast buffer : this.threadBuffersForRead) {
// size of the buffer BEFORE our backspace was typed
int length = buffer.position();
int amtToOverwrite = 2 * 2; // backspace is always 2 chars (^?) * 2 because it's bytes
if (length > 1) {
char charAt = buffer.getChar(length-2);
amtToOverwrite += getPrintableCharacters(charAt);
// delete last item in our buffer
length -= 2;
buffer.position(length);
// now figure out where the cursor is really at.
// this is more memory friendly than buf.toString.length
for (int i=0;i<length;i+=2) {
charAt = buffer.getChar(i);
position += getPrintableCharacters(charAt);
}
position++;
}
char[] overwrite = new char[amtToOverwrite];
char c = ' ';
for (int i=0;i<amtToOverwrite;i++) {
overwrite[i] = c;
}
// move back however many, over write, then go back again
out.print(ansi.cursorToColumn(position));
out.print(overwrite);
out.print(ansi.cursorToColumn(position));
out.flush();
// now figure out where the cursor is really at.
// this is more memory friendly than buf.toString.length
for (int i=0;i<length;i+=2) {
charAt = buffer.readChar(i);
position += getPrintableCharacters(charAt);
}
position++;
}
// read-line will ignore backspace
continue;
}
char[] overwrite = new char[amtToOverwrite];
char c = ' ';
for (int i=0;i<amtToOverwrite;i++) {
overwrite[i] = c;
}
// ignoring \r, because \n is ALWAYS the last character in a new line sequence. (even for windows)
if (asChar == '\n') {
synchronized (this.inputLockLine) {
this.inputLockLine.notifyAll();
}
} else if (asChar != '\r') {
// only append if we are not a new line.
for (ByteBuffer2Fast buffer : this.threadBuffersForRead) {
buffer.putChar(asChar);
}
// move back however many, over write, then go back again
out.print(ansi.cursorToColumn(position));
out.print(overwrite);
out.print(ansi.cursorToColumn(position));
out.flush();
}
}
} catch (IOException ignored) {
// read-line will ignore backspace
continue;
}
// ignoring \r, because \n is ALWAYS the last character in a new line sequence. (even for windows)
if (asChar == '\n') {
synchronized (this.inputLockLine) {
this.inputLockLine.notifyAll();
}
} else {
// our windows console PREVENTS us from returning '\r' (it truncates '\r\n', and returns just '\n')
// only append if we are not a new line.
for (ObjectPoolHolder<ByteBuffer2> objectPoolHolder : this.threadBuffersForRead) {
ByteBuffer2 buffer = objectPoolHolder.getValue();
buffer.writeChar(asChar);
}
}
}
}
/**
* Get the default encoding. Will first look at the LC_CTYPE environment variable, then the input.encoding
* system property, then the default charset according to the JVM.
*
* @return The default encoding to use when none is specified.
*/
public static String getEncoding() {
// LC_CTYPE is usually in the form en_US.UTF-8
String envEncoding = extractEncodingFromCtype(System.getenv("LC_CTYPE"));
if (envEncoding != null) {
return envEncoding;
}
return System.getProperty("input.encoding", Charset.defaultCharset().name());
}
/**
* Parses the LC_CTYPE value to extract the encoding according to the POSIX standard, which says that the LC_CTYPE
* environment variable may be of the format <code>[language[_territory][.codeset][@modifier]]</code>
*
* @param ctype The ctype to parse, may be null
* @return The encoding, if one was present, otherwise null
*/
static String extractEncodingFromCtype(String ctype) {
if (ctype != null && ctype.indexOf('.') > 0) {
String encodingAndModifier = ctype.substring(ctype.indexOf('.') + 1);
if (encodingAndModifier.indexOf('@') > 0) {
return encodingAndModifier.substring(0, encodingAndModifier.indexOf('@'));
}
return encodingAndModifier;
}
return null;
}
/**
* try to guess if we are running inside an IDE
*/

View File

@ -1,7 +1,6 @@
package dorkbox.util.input;
import java.io.IOException;
import java.io.InputStream;
public abstract class Terminal {
protected final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());
@ -60,7 +59,15 @@ public abstract class Terminal {
public abstract int getWidth();
public abstract int getHeight();
public InputStream wrapInIfNeeded(InputStream in) throws IOException {
return in;
/**
* @return a character from whatever underlying input method the terminal has available.
*/
public abstract int read();
/**
* Only needed for unsupported character input.
*/
public boolean wasSequence() {
return false;
}
}

View File

@ -6,7 +6,7 @@
*
* http://www.opensource.org/licenses/bsd-license.php
*/
package dorkbox.util.input;
package dorkbox.util.input.posix;
import java.io.IOException;
import java.io.InputStream;

View File

@ -1,6 +1,7 @@
package dorkbox.util.input.posix;
import java.io.IOException;
import java.io.Reader;
import java.nio.ByteBuffer;
import com.sun.jna.Native;
@ -18,10 +19,15 @@ public class UnixTerminal extends Terminal {
private volatile TermiosStruct termInfoDefault = new TermiosStruct();
private volatile TermiosStruct termInfo = new TermiosStruct();
private Reader reader;
private PosixTerminalControl term;
private ByteBuffer windowSizeBuffer = ByteBuffer.allocate(8);
public UnixTerminal() throws Exception {
public UnixTerminal(String encoding) throws Exception {
this.reader = new InputStreamReader(System.in, encoding);
this.term = (PosixTerminalControl) Native.loadLibrary("c", PosixTerminalControl.class);
// save off the defaults
@ -54,7 +60,6 @@ public class UnixTerminal extends Terminal {
// t->c_cc[VMIN] = 1;
// t->c_cc[VTIME] = 0;
if (this.term.tcgetattr(0, this.termInfo) !=0) {
throw new IOException("Failed to get terminal info");
}
@ -86,7 +91,7 @@ public class UnixTerminal extends Terminal {
* used after calling this method.
*/
@Override
public void restore() throws IOException {
public final void restore() throws IOException {
if (this.term.tcsetattr(0, PosixTerminalControl.TCSANOW, this.termInfoDefault) != 0) {
throw new IOException("Can not reset terminal to defaults");
}
@ -96,7 +101,7 @@ public class UnixTerminal extends Terminal {
* Returns number of columns in the terminal.
*/
@Override
public int getWidth() {
public final int getWidth() {
if (this.term.ioctl(0, PosixTerminalControl.TIOCGWINSZ, this.windowSizeBuffer) != 0) {
return DEFAULT_WIDTH;
}
@ -109,7 +114,7 @@ public class UnixTerminal extends Terminal {
* Returns number of rows in the terminal.
*/
@Override
public int getHeight() {
public final int getHeight() {
if (this.term.ioctl(0, PosixTerminalControl.TIOCGWINSZ, this.windowSizeBuffer) != 0) {
return DEFAULT_HEIGHT;
}
@ -119,7 +124,7 @@ public class UnixTerminal extends Terminal {
}
@Override
public synchronized void setEchoEnabled(final boolean enabled) {
public final synchronized void setEchoEnabled(final boolean enabled) {
// have to reget them, since flags change everything
if (this.term.tcgetattr(0, this.termInfo) !=0) {
this.logger.error("Failed to get terminal info");
@ -139,29 +144,38 @@ public class UnixTerminal extends Terminal {
super.setEchoEnabled(enabled);
}
public void disableInterruptCharacter() {
// have to re-get them, since flags change everything
if (this.term.tcgetattr(0, this.termInfo) !=0) {
this.logger.error("Failed to get terminal info");
}
// public final void disableInterruptCharacter() {
// // have to re-get them, since flags change everything
// if (this.term.tcgetattr(0, this.termInfo) !=0) {
// this.logger.error("Failed to get terminal info");
// }
//
// this.termInfo.c_cc[PosixTerminalControl.VINTR] = 0; // interrupt disabled
//
// if (this.term.tcsetattr(0, PosixTerminalControl.TCSANOW, this.termInfo) != 0) {
// this.logger.error("Can not set terminal flags");
// }
// }
//
// public final void enableInterruptCharacter() {
// // have to re-get them, since flags change everything
// if (this.term.tcgetattr(0, this.termInfo) !=0) {
// this.logger.error("Failed to get terminal info");
// }
//
// this.termInfo.c_cc[PosixTerminalControl.VINTR] = 3; // interrupt is ctrl-c
//
// if (this.term.tcsetattr(0, PosixTerminalControl.TCSANOW, this.termInfo) != 0) {
// this.logger.error("Can not set terminal flags");
// }
// }
this.termInfo.c_cc[PosixTerminalControl.VINTR] = 0; // interrupt disabled
if (this.term.tcsetattr(0, PosixTerminalControl.TCSANOW, this.termInfo) != 0) {
this.logger.error("Can not set terminal flags");
}
}
public void enableInterruptCharacter() {
// have to re-get them, since flags change everything
if (this.term.tcgetattr(0, this.termInfo) !=0) {
this.logger.error("Failed to get terminal info");
}
this.termInfo.c_cc[PosixTerminalControl.VINTR] = 3; // interrupt is ctrl-c
if (this.term.tcsetattr(0, PosixTerminalControl.TCSANOW, this.termInfo) != 0) {
this.logger.error("Can not set terminal flags");
@Override
public final int read() {
try {
return this.reader.read();
} catch (IOException ignored) {
return -1;
}
}
}

View File

@ -1,30 +1,91 @@
package dorkbox.util.input.unsupported;
import java.io.BufferedReader;
import java.io.IOException;
import dorkbox.util.bytes.ByteBuffer2;
import dorkbox.util.input.Terminal;
import dorkbox.util.input.posix.InputStreamReader;
public class UnsupportedTerminal extends Terminal {
public UnsupportedTerminal() {
// setAnsiSupported(false);
setEchoEnabled(true);
private final ByteBuffer2 buffer = new ByteBuffer2(8, -1);
private BufferedReader reader;
private String readLine = null;
private char[] line;
private ThreadLocal<Integer> indexOfStringForReadChar = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return -1;
}
};
public UnsupportedTerminal(String encoding) {
this.reader = new BufferedReader(new InputStreamReader(System.in, encoding));
}
@Override
public void init() throws IOException {
public final void init() throws IOException {
}
@Override
public void restore() {
public final void restore() {
}
@Override
public int getWidth() {
public final int getWidth() {
return 0;
}
@Override
public int getHeight() {
public final int getHeight() {
return 0;
}
@Override
public final int read() {
// if we are reading data (because we are in IDE mode), we want to return ALL
// the chars of the line!
// so, readChar is REALLY the index at which we return letters (until the whole string is returned)
int readerCount = this.indexOfStringForReadChar.get();
if (readerCount == -1) {
// we have to wait for more data.
try {
this.readLine = this.reader.readLine();
} catch (IOException e) {
return -1;
}
this.line = this.readLine.toCharArray();
this.buffer.clear();
for (char c : this.line) {
this.buffer.writeChar(c);
}
readerCount = 0;
this.indexOfStringForReadChar.set(0);
}
// EACH thread will have it's own count!
if (readerCount == this.buffer.position()) {
this.indexOfStringForReadChar.set(-1);
return '\n';
} else {
this.indexOfStringForReadChar.set(readerCount+2); // because 2 bytes per char in java
}
char c = this.buffer.readChar(readerCount);
return c;
}
@Override
public final boolean wasSequence() {
return this.line.length > 0;
}
}

View File

@ -46,22 +46,8 @@ public enum ConsoleMode {
* discarded by ReadFile or ReadConsole, even when this mode is enabled.
*/
ENABLE_MOUSE_INPUT(16),
;
/**
* When enabled, text entered in a console window will be inserted at the
* current cursor location and all text following that location will not be
* overwritten. When disabled, all following text will be overwritten. An OR
* operation must be performed with this flag and the ENABLE_EXTENDED_FLAGS
* flag to enable this functionality.
*/
ENABLE_PROCESSED_OUTPUT(1),
/**
* This flag enables the user to use the mouse to select and edit text. To
* enable this option, use the OR to combine this flag with
* ENABLE_EXTENDED_FLAGS.
*/
ENABLE_WRAP_AT_EOL_OUTPUT(2),;
public final int code;

View File

@ -8,11 +8,11 @@
*/
package dorkbox.util.input.windows;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import org.fusesource.jansi.internal.Kernel32.INPUT_RECORD;
import org.fusesource.jansi.internal.Kernel32.KEY_EVENT_RECORD;
import org.fusesource.jansi.internal.WindowsSupport;
import dorkbox.util.input.Terminal;
@ -26,34 +26,26 @@ import dorkbox.util.input.Terminal;
* url=/library/en-us/dllproc/base/getconsolemode.asp">GetConsoleMode</a> to
* disable character echoing.
* <p/>
* <p>
* By default, the {@link #wrapInIfNeeded(java.io.InputStream)} method will attempt
* to test to see if the specified {@link InputStream} is {@link System#in} or a wrapper
* around {@link FileDescriptor#in}, and if so, will bypass the character reading to
* directly invoke the readc() method in the JNI library. This is so the class
* can read special keys (like arrow keys) which are otherwise inaccessible via
* the {@link System#in} stream. Using JNI reading can be bypassed by setting
* the <code>jline.WindowsTerminal.directConsole</code> system property
* to <code>false</code>.
* </p>
*
* @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.0
* @since 2.0 (customized)
*/
public class WindowsTerminal extends Terminal
{
public static final String DIRECT_CONSOLE = WindowsTerminal.class.getName() + ".directConsole";
private int originalMode;
public class WindowsTerminal extends Terminal {
private volatile int originalMode;
private final PrintStream out;
public WindowsTerminal() {
this.out = System.out;
}
@Override
public void init() throws IOException {
public final void init() throws IOException {
this.originalMode = WindowsSupport.getConsoleMode();
WindowsSupport.setConsoleMode(this.originalMode & ~ConsoleMode.ENABLE_ECHO_INPUT.code);
// Must set these four modes at the same time to make it work fine.
WindowsSupport.setConsoleMode(this.originalMode |
ConsoleMode.ENABLE_LINE_INPUT.code |
ConsoleMode.ENABLE_ECHO_INPUT.code |
ConsoleMode.ENABLE_PROCESSED_INPUT.code |
ConsoleMode.ENABLE_WINDOW_INPUT.code);
}
/**
@ -62,69 +54,71 @@ public class WindowsTerminal extends Terminal
* used after calling this method.
*/
@Override
public void restore() throws IOException {
public final void restore() throws IOException {
// restore the old console mode
WindowsSupport.setConsoleMode(this.originalMode);
}
@Override
public int getWidth() {
public final int getWidth() {
int w = WindowsSupport.getWindowsTerminalWidth();
return w < 1 ? DEFAULT_WIDTH : w;
}
@Override
public int getHeight() {
public final int getHeight() {
int h = WindowsSupport.getWindowsTerminalHeight();
return h < 1 ? DEFAULT_HEIGHT : h;
}
@Override
public void setEchoEnabled(final boolean enabled) {
// Must set these four modes at the same time to make it work fine.
if (enabled) {
WindowsSupport.setConsoleMode(WindowsSupport.getConsoleMode() |
ConsoleMode.ENABLE_ECHO_INPUT.code |
ConsoleMode.ENABLE_LINE_INPUT.code |
ConsoleMode.ENABLE_PROCESSED_INPUT.code |
ConsoleMode.ENABLE_WINDOW_INPUT.code);
public final int read() {
int input = readInput();
if (isEchoEnabled()) {
char asChar = (char) input;
if (asChar == '\n') {
this.out.println();
} else {
this.out.print(asChar);
}
// have to flush, otherwise we'll never see the chars on screen
this.out.flush();
}
else {
WindowsSupport.setConsoleMode(WindowsSupport.getConsoleMode() &
~(ConsoleMode.ENABLE_LINE_INPUT.code |
ConsoleMode.ENABLE_ECHO_INPUT.code |
ConsoleMode.ENABLE_PROCESSED_INPUT.code |
ConsoleMode.ENABLE_WINDOW_INPUT.code));
}
super.setEchoEnabled(enabled);
return input;
}
private final int readInput() {
// this HOOKS the input event, and prevents it from going to the console "proper"
try {
INPUT_RECORD[] events = null;
while (true) {
// we ALWAYS read until we have an event we care about!
events = WindowsSupport.readConsoleInput(1);
@Override
public InputStream wrapInIfNeeded(InputStream in) throws IOException {
if (isSystemIn(in)) {
return new InputStream() {
@Override
public int read() throws IOException {
return WindowsSupport.readByte();
if (events != null) {
for (int i = 0; i < events.length; i++ ) {
KEY_EVENT_RECORD keyEvent = events[i].keyEvent;
//Log.trace(keyEvent.keyDown? "KEY_DOWN" : "KEY_UP", "key code:", keyEvent.keyCode, "char:", (long)keyEvent.uchar);
if (keyEvent.keyDown) {
if (keyEvent.uchar > 0) {
char uchar = keyEvent.uchar;
if (uchar == '\r') {
// we purposefully swallow input after \r, and substitute it with \n
return '\n';
}
return uchar;
}
}
}
}
};
} else {
return in;
}
}
private boolean isSystemIn(final InputStream in) throws IOException {
if (in == null) {
return false;
}
else if (in == System.in) {
return true;
}
else if (in instanceof FileInputStream && ((FileInputStream) in).getFD() == FileDescriptor.in) {
return true;
}
} catch (IOException e) {
this.logger.error("Windows console input error: ", e);
}
return false;
return -1;
}
}

View File

@ -104,10 +104,10 @@ class FastObjectPool<T> implements ObjectPool<T> {
}
@Override
public void release(ObjectPoolHolder<T> object) throws InterruptedException {
this.lock.lockInterruptibly();
public void release(ObjectPoolHolder<T> object) {
try {
this.lock.lockInterruptibly();
int localValue = this.releasePointer;
//long index = ((localValue & mask) * INDEXSCALE ) + BASE;
long index = ((localValue & this.mask)<<this.ASHIFT ) + this.BASE;
@ -120,6 +120,7 @@ class FastObjectPool<T> implements ObjectPool<T> {
else {
throw new IllegalArgumentException("Invalid reference passed");
}
} catch (InterruptedException e) {
}
finally {
this.lock.unlock();

View File

@ -9,5 +9,5 @@ public interface ObjectPool<T> {
/**
* Return object to the pool
*/
public void release(ObjectPoolHolder<T> object) throws InterruptedException;
public void release(ObjectPoolHolder<T> object);
}

View File

@ -2,11 +2,22 @@ package dorkbox.util.objectPool;
import dorkbox.util.Sys;
public class ObjectPoolFactory<T> {
public class ObjectPoolFactory {
private ObjectPoolFactory() {
}
/**
* Creates a pool with the max number of available processors as the pool size (padded by 2x as many).
*/
public static <T> ObjectPool<T> create(PoolableObject<T> poolableObject) {
return create(poolableObject, Runtime.getRuntime().availableProcessors() * 2);
}
/**
* Creates a pool of the specified size
*/
public static <T> ObjectPool<T> create(PoolableObject<T> poolableObject, int size) {
if (Sys.isAndroid) {
// unfortunately, unsafe is not available in android

View File

@ -10,10 +10,10 @@ public interface PoolableObject<T> {
/**
* invoked on every instance that is borrowed from the pool
*/
public void activate(T t);
public void activate(T object);
/**
* invoked on every instance that is returned to the pool
*/
public void passivate(T t);
public void passivate(T object);
}

View File

@ -76,7 +76,7 @@ class SlowObjectPool<T> implements ObjectPool<T> {
}
@Override
public void release(ObjectPoolHolder<T> object) throws InterruptedException {
public void release(ObjectPoolHolder<T> object) {
if (object.state.compareAndSet(USED, FREE)) {
this.queue.offer(object);
this.poolableObject.passivate(object.getValue());

View File

@ -21,10 +21,6 @@ import dorkbox.util.OS;
*/
public class ShellProcessBuilder {
// TODO: see http://mark.koli.ch/2009/12/uac-prompt-from-java-createprocess-error740-the-requested-operation-requires-elevation.html
// for more information on copying files in windows with UAC protections.
// maybe we want to hook into our launcher executor so that we can "auto elevate" commands?
private String workingDirectory = null;
private String executableName = null;
private String executableDirectory = null;
@ -56,9 +52,9 @@ public class ShellProcessBuilder {
}
public ShellProcessBuilder(InputStream in, PrintStream out, PrintStream err) {
outputStream = out;
errorStream = err;
inputStream = in;
this.outputStream = out;
this.errorStream = err;
this.inputStream = in;
}
/**
@ -71,19 +67,19 @@ public class ShellProcessBuilder {
}
public final ShellProcessBuilder addArgument(String argument) {
arguments.add(argument);
this.arguments.add(argument);
return this;
}
public final ShellProcessBuilder addArguments(String... paths) {
for (String path : paths) {
arguments.add(path);
this.arguments.add(path);
}
return this;
}
public final ShellProcessBuilder addArguments(List<String> paths) {
arguments.addAll(paths);
this.arguments.addAll(paths);
return this;
}
@ -106,39 +102,39 @@ public class ShellProcessBuilder {
public void start() {
// if no executable, then use the command shell
if (executableName == null) {
if (this.executableName == null) {
if (OS.isWindows()) {
// windows
executableName = "cmd";
arguments.add(0, "/c");
this.executableName = "cmd";
this.arguments.add(0, "/c");
} else {
// *nix
executableName = "/bin/bash";
File file = new File(executableName);
this.executableName = "/bin/bash";
File file = new File(this.executableName);
if (!file.canExecute()) {
executableName = "/bin/sh";
this.executableName = "/bin/sh";
}
arguments.add(0, "-c");
this.arguments.add(0, "-c");
}
} else if (workingDirectory != null) {
if (!workingDirectory.endsWith("/") && !workingDirectory.endsWith("\\")) {
workingDirectory += File.separator;
} else if (this.workingDirectory != null) {
if (!this.workingDirectory.endsWith("/") && !this.workingDirectory.endsWith("\\")) {
this.workingDirectory += File.separator;
}
}
if (executableDirectory != null) {
if (!executableDirectory.endsWith("/") && !executableDirectory.endsWith("\\")) {
executableDirectory += File.separator;
if (this.executableDirectory != null) {
if (!this.executableDirectory.endsWith("/") && !this.executableDirectory.endsWith("\\")) {
this.executableDirectory += File.separator;
}
executableName = executableDirectory + executableName;
this.executableName = this.executableDirectory + this.executableName;
}
List<String> argumentsList = new ArrayList<String>();
argumentsList.add(executableName);
argumentsList.add(this.executableName);
for (String arg : arguments) {
for (String arg : this.arguments) {
if (arg.contains(" ")) {
// individual arguments MUST be in their own element in order to
// be processed properly (this is how it works on the command line!)
@ -154,7 +150,7 @@ public class ShellProcessBuilder {
// if we don't want output... TODO: i think we want to "exec" (this calls exec -c, which calls our program)
// this code as well, since calling it directly won't work
boolean pipeToNull = errorStream == null || outputStream == null;
boolean pipeToNull = this.errorStream == null || this.outputStream == null;
if (pipeToNull) {
if (OS.isWindows()) {
// >NUL on windows
@ -165,22 +161,22 @@ public class ShellProcessBuilder {
}
}
if (debugInfo) {
errorStream.print("Executing: ");
if (this.debugInfo) {
this.errorStream.print("Executing: ");
Iterator<String> iterator = argumentsList.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
errorStream.print(s);
this.errorStream.print(s);
if (iterator.hasNext()) {
errorStream.print(" ");
this.errorStream.print(" ");
}
}
errorStream.print(OS.LINE_SEPARATOR);
this.errorStream.print(OS.LINE_SEPARATOR);
}
ProcessBuilder processBuilder = new ProcessBuilder(argumentsList);
if (workingDirectory != null) {
processBuilder.directory(new File(workingDirectory));
if (this.workingDirectory != null) {
processBuilder.directory(new File(this.workingDirectory));
}
// combine these so output is properly piped to null.
@ -189,23 +185,23 @@ public class ShellProcessBuilder {
}
try {
process = processBuilder.start();
this.process = processBuilder.start();
} catch (Exception ex) {
errorStream.println("There was a problem executing the program. Details:\n");
ex.printStackTrace(errorStream);
this.errorStream.println("There was a problem executing the program. Details:\n");
ex.printStackTrace(this.errorStream);
if (process != null) {
if (this.process != null) {
try {
process.destroy();
process = null;
this.process.destroy();
this.process = null;
} catch (Exception e) {
errorStream.println("Error destroying process: \n");
e.printStackTrace(errorStream);
this.errorStream.println("Error destroying process: \n");
e.printStackTrace(this.errorStream);
}
}
}
if (process != null) {
if (this.process != null) {
ProcessProxy writeToProcess_input;
ProcessProxy readFromProcess_output;
ProcessProxy readFromProcess_error;
@ -218,7 +214,7 @@ public class ShellProcessBuilder {
// readers (read process -> write console)
// have to keep the output buffers from filling in the target process.
readFromProcess_output = new ProcessProxy("Process Reader: " + executableName, process.getInputStream(), nullOutputStream);
readFromProcess_output = new ProcessProxy("Process Reader: " + this.executableName, this.process.getInputStream(), nullOutputStream);
readFromProcess_error = null;
}
// we want to pipe our input/output from process to ourselves
@ -228,21 +224,21 @@ public class ShellProcessBuilder {
* to the user's window. This is important or the spawned process could block.
*/
// readers (read process -> write console)
readFromProcess_output = new ProcessProxy("Process Reader: " + executableName, process.getInputStream(), outputStream);
if (errorStream != outputStream) {
readFromProcess_error = new ProcessProxy("Process Reader: " + executableName, process.getErrorStream(), errorStream);
readFromProcess_output = new ProcessProxy("Process Reader: " + this.executableName, this.process.getInputStream(), this.outputStream);
if (this.errorStream != this.outputStream) {
readFromProcess_error = new ProcessProxy("Process Reader: " + this.executableName, this.process.getErrorStream(), this.errorStream);
} else {
processBuilder.redirectErrorStream(true);
readFromProcess_error = null;
}
}
if (inputStream != null) {
if (this.inputStream != null) {
/**
* Proxy System.in from the user's window to the spawned process
*/
// writer (read console -> write process)
writeToProcess_input = new ProcessProxy("Process Writer: " + executableName, inputStream, process.getOutputStream());
writeToProcess_input = new ProcessProxy("Process Writer: " + this.executableName, this.inputStream, this.process.getOutputStream());
} else {
writeToProcess_input = null;
}
@ -254,10 +250,10 @@ public class ShellProcessBuilder {
Thread hook = new Thread(new Runnable() {
@Override
public void run() {
if (debugInfo) {
errorStream.println("Terminating process: " + executableName);
if (ShellProcessBuilder.this.debugInfo) {
ShellProcessBuilder.this.errorStream.println("Terminating process: " + ShellProcessBuilder.this.executableName);
}
process.destroy();
ShellProcessBuilder.this.process.destroy();
}
}
);
@ -273,10 +269,10 @@ public class ShellProcessBuilder {
}
try {
process.waitFor();
this.process.waitFor();
@SuppressWarnings("unused")
int exitValue = process.exitValue();
int exitValue = this.process.exitValue();
// wait for the READER threads to die (meaning their streams have closed/EOF'd)
if (writeToProcess_input != null) {
@ -294,7 +290,7 @@ public class ShellProcessBuilder {
// forcibly terminate the process when it's streams have closed.
// this is for cleanup ONLY, not to actually do anything.
process.destroy();
this.process.destroy();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}

View File

@ -0,0 +1,766 @@
package dorkbox.util;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Random;
import org.junit.Assert;
import org.junit.Test;
import dorkbox.util.bytes.ByteBuffer2;
public class ByteBuffer2Test {
static public void assertArrayEquals(Object object1, Object object2) {
Assert.assertEquals(arrayToList(object1), arrayToList(object2));
}
static public Object arrayToList(Object array) {
if (array == null || !array.getClass().isArray()) {
return array;
}
ArrayList<Object> list = new ArrayList<Object>(Array.getLength(array));
for (int i = 0, n = Array.getLength(array); i < n; i++) {
list.add(arrayToList(Array.get(array, i)));
}
return list;
}
@Test
public void testWriteBytes() {
ByteBuffer2 buffer = new ByteBuffer2(512);
buffer.writeBytes(new byte[] {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26});
buffer.writeBytes(new byte[] {31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46});
buffer.writeByte(51);
buffer.writeBytes(new byte[] {52,53,54,55,56,57,58});
buffer.writeByte(61);
buffer.writeByte(62);
buffer.writeByte(63);
buffer.writeByte(64);
buffer.writeByte(65);
assertArrayEquals(new byte[] {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,31,32,33,34,35,36,37,38,39,40,41,42,
43,44,45,46,51,52,53,54,55,56,57,58,61,62,63,64,65}, buffer.toBytes());
}
@Test
public void testStrings() {
runStringTest(new ByteBuffer2(4096));
runStringTest(new ByteBuffer2(897));
ByteBuffer2 write = new ByteBuffer2(21);
String value = "abcdef\u00E1\u00E9\u00ED\u00F3\u00FA\u1234";
write.writeString(value);
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
assertArrayEquals(value, read.readString());
runStringTest(127);
runStringTest(256);
runStringTest(1024 * 1023);
runStringTest(1024 * 1024);
runStringTest(1024 * 1025);
runStringTest(1024 * 1026);
runStringTest(1024 * 1024 * 2);
}
public void runStringTest(ByteBuffer2 write) {
String value1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\rabcdefghijklmnopqrstuvwxyz\n1234567890\t\"!`?'.,;:()[]{}<>|/@\\^$-%+=#_&~*";
String value2 = "abcdef\u00E1\u00E9\u00ED\u00F3\u00FA\u1234";
write.writeString("");
write.writeString("1");
write.writeString("22");
write.writeString("uno");
write.writeString("dos");
write.writeString("tres");
write.writeString(null);
write.writeString(value1);
write.writeString(value2);
for (int i = 0; i < 127; i++) {
write.writeString(String.valueOf((char) i));
}
for (int i = 0; i < 127; i++) {
write.writeString(String.valueOf((char) i) + "abc");
}
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
Assert.assertEquals("", read.readString());
Assert.assertEquals("1", read.readString());
Assert.assertEquals("22", read.readString());
Assert.assertEquals("uno", read.readString());
Assert.assertEquals("dos", read.readString());
Assert.assertEquals("tres", read.readString());
Assert.assertEquals(null, read.readString());
Assert.assertEquals(value1, read.readString());
Assert.assertEquals(value2, read.readString());
for (int i = 0; i < 127; i++) {
Assert.assertEquals(String.valueOf((char) i), read.readString());
}
for (int i = 0; i < 127; i++) {
Assert.assertEquals(String.valueOf((char) i) + "abc", read.readString());
}
read.rewind();
Assert.assertEquals("", read.readStringBuilder().toString());
Assert.assertEquals("1", read.readStringBuilder().toString());
Assert.assertEquals("22", read.readStringBuilder().toString());
Assert.assertEquals("uno", read.readStringBuilder().toString());
Assert.assertEquals("dos", read.readStringBuilder().toString());
Assert.assertEquals("tres", read.readStringBuilder().toString());
Assert.assertEquals(null, read.readStringBuilder());
Assert.assertEquals(value1, read.readStringBuilder().toString());
Assert.assertEquals(value2, read.readStringBuilder().toString());
for (int i = 0; i < 127; i++) {
Assert.assertEquals(String.valueOf((char) i), read.readStringBuilder().toString());
}
for (int i = 0; i < 127; i++) {
Assert.assertEquals(String.valueOf((char) i) + "abc", read.readStringBuilder().toString());
}
}
public void runStringTest(int length) {
ByteBuffer2 write = new ByteBuffer2(1024, -1);
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < length; i++) {
buffer.append((char) i);
}
String value = buffer.toString();
write.writeString(value);
write.writeString(value);
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
Assert.assertEquals(value, read.readString());
Assert.assertEquals(value, read.readStringBuilder().toString());
write.clear();
write.writeString(buffer);
write.writeString(buffer);
read = new ByteBuffer2(write.toBytes());
Assert.assertEquals(value, read.readStringBuilder().toString());
Assert.assertEquals(value, read.readString());
if (length <= 127) {
write.clear();
write.writeAscii(value);
write.writeAscii(value);
read = new ByteBuffer2(write.toBytes());
Assert.assertEquals(value, read.readStringBuilder().toString());
Assert.assertEquals(value, read.readString());
}
}
@Test
public void testCanReadInt() {
ByteBuffer2 write = new ByteBuffer2();
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
Assert.assertEquals(false, read.canReadInt());
write = new ByteBuffer2(4);
write.writeInt(400, true);
read = new ByteBuffer2(write.toBytes());
Assert.assertEquals(true, read.canReadInt());
read.setPosition(read.capacity());
Assert.assertEquals(false, read.canReadInt());
}
@Test
public void testInts() {
runIntTest(new ByteBuffer2(4096));
}
private void runIntTest(ByteBuffer2 write) {
write.writeInt(0);
write.writeInt(63);
write.writeInt(64);
write.writeInt(127);
write.writeInt(128);
write.writeInt(8192);
write.writeInt(16384);
write.writeInt(2097151);
write.writeInt(1048575);
write.writeInt(134217727);
write.writeInt(268435455);
write.writeInt(134217728);
write.writeInt(268435456);
write.writeInt(-2097151);
write.writeInt(-1048575);
write.writeInt(-134217727);
write.writeInt(-268435455);
write.writeInt(-134217728);
write.writeInt(-268435456);
Assert.assertEquals(1, write.writeInt(0, true));
Assert.assertEquals(1, write.writeInt(0, false));
Assert.assertEquals(1, write.writeInt(63, true));
Assert.assertEquals(1, write.writeInt(63, false));
Assert.assertEquals(1, write.writeInt(64, true));
Assert.assertEquals(2, write.writeInt(64, false));
Assert.assertEquals(1, write.writeInt(127, true));
Assert.assertEquals(2, write.writeInt(127, false));
Assert.assertEquals(2, write.writeInt(128, true));
Assert.assertEquals(2, write.writeInt(128, false));
Assert.assertEquals(2, write.writeInt(8191, true));
Assert.assertEquals(2, write.writeInt(8191, false));
Assert.assertEquals(2, write.writeInt(8192, true));
Assert.assertEquals(3, write.writeInt(8192, false));
Assert.assertEquals(2, write.writeInt(16383, true));
Assert.assertEquals(3, write.writeInt(16383, false));
Assert.assertEquals(3, write.writeInt(16384, true));
Assert.assertEquals(3, write.writeInt(16384, false));
Assert.assertEquals(3, write.writeInt(2097151, true));
Assert.assertEquals(4, write.writeInt(2097151, false));
Assert.assertEquals(3, write.writeInt(1048575, true));
Assert.assertEquals(3, write.writeInt(1048575, false));
Assert.assertEquals(4, write.writeInt(134217727, true));
Assert.assertEquals(4, write.writeInt(134217727, false));
Assert.assertEquals(4, write.writeInt(268435455, true));
Assert.assertEquals(5, write.writeInt(268435455, false));
Assert.assertEquals(4, write.writeInt(134217728, true));
Assert.assertEquals(5, write.writeInt(134217728, false));
Assert.assertEquals(5, write.writeInt(268435456, true));
Assert.assertEquals(5, write.writeInt(268435456, false));
Assert.assertEquals(1, write.writeInt(-64, false));
Assert.assertEquals(5, write.writeInt(-64, true));
Assert.assertEquals(2, write.writeInt(-65, false));
Assert.assertEquals(5, write.writeInt(-65, true));
Assert.assertEquals(2, write.writeInt(-8192, false));
Assert.assertEquals(5, write.writeInt(-8192, true));
Assert.assertEquals(3, write.writeInt(-1048576, false));
Assert.assertEquals(5, write.writeInt(-1048576, true));
Assert.assertEquals(4, write.writeInt(-134217728, false));
Assert.assertEquals(5, write.writeInt(-134217728, true));
Assert.assertEquals(5, write.writeInt(-134217729, false));
Assert.assertEquals(5, write.writeInt(-134217729, true));
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
Assert.assertEquals(0, read.readInt());
Assert.assertEquals(63, read.readInt());
Assert.assertEquals(64, read.readInt());
Assert.assertEquals(127, read.readInt());
Assert.assertEquals(128, read.readInt());
Assert.assertEquals(8192, read.readInt());
Assert.assertEquals(16384, read.readInt());
Assert.assertEquals(2097151, read.readInt());
Assert.assertEquals(1048575, read.readInt());
Assert.assertEquals(134217727, read.readInt());
Assert.assertEquals(268435455, read.readInt());
Assert.assertEquals(134217728, read.readInt());
Assert.assertEquals(268435456, read.readInt());
Assert.assertEquals(-2097151, read.readInt());
Assert.assertEquals(-1048575, read.readInt());
Assert.assertEquals(-134217727, read.readInt());
Assert.assertEquals(-268435455, read.readInt());
Assert.assertEquals(-134217728, read.readInt());
Assert.assertEquals(-268435456, read.readInt());
Assert.assertEquals(true, read.canReadInt());
Assert.assertEquals(true, read.canReadInt());
Assert.assertEquals(true, read.canReadInt());
Assert.assertEquals(0, read.readInt(true));
Assert.assertEquals(0, read.readInt(false));
Assert.assertEquals(63, read.readInt(true));
Assert.assertEquals(63, read.readInt(false));
Assert.assertEquals(64, read.readInt(true));
Assert.assertEquals(64, read.readInt(false));
Assert.assertEquals(127, read.readInt(true));
Assert.assertEquals(127, read.readInt(false));
Assert.assertEquals(128, read.readInt(true));
Assert.assertEquals(128, read.readInt(false));
Assert.assertEquals(8191, read.readInt(true));
Assert.assertEquals(8191, read.readInt(false));
Assert.assertEquals(8192, read.readInt(true));
Assert.assertEquals(8192, read.readInt(false));
Assert.assertEquals(16383, read.readInt(true));
Assert.assertEquals(16383, read.readInt(false));
Assert.assertEquals(16384, read.readInt(true));
Assert.assertEquals(16384, read.readInt(false));
Assert.assertEquals(2097151, read.readInt(true));
Assert.assertEquals(2097151, read.readInt(false));
Assert.assertEquals(1048575, read.readInt(true));
Assert.assertEquals(1048575, read.readInt(false));
Assert.assertEquals(134217727, read.readInt(true));
Assert.assertEquals(134217727, read.readInt(false));
Assert.assertEquals(268435455, read.readInt(true));
Assert.assertEquals(268435455, read.readInt(false));
Assert.assertEquals(134217728, read.readInt(true));
Assert.assertEquals(134217728, read.readInt(false));
Assert.assertEquals(268435456, read.readInt(true));
Assert.assertEquals(268435456, read.readInt(false));
Assert.assertEquals(-64, read.readInt(false));
Assert.assertEquals(-64, read.readInt(true));
Assert.assertEquals(-65, read.readInt(false));
Assert.assertEquals(-65, read.readInt(true));
Assert.assertEquals(-8192, read.readInt(false));
Assert.assertEquals(-8192, read.readInt(true));
Assert.assertEquals(-1048576, read.readInt(false));
Assert.assertEquals(-1048576, read.readInt(true));
Assert.assertEquals(-134217728, read.readInt(false));
Assert.assertEquals(-134217728, read.readInt(true));
Assert.assertEquals(-134217729, read.readInt(false));
Assert.assertEquals(-134217729, read.readInt(true));
Assert.assertEquals(false, read.canReadInt());
Random random = new Random();
for (int i = 0; i < 10000; i++) {
int value = random.nextInt();
write.clear();
write.writeInt(value);
write.writeInt(value, true);
write.writeInt(value, false);
read.setBuffer(write.toBytes());
Assert.assertEquals(value, read.readInt());
Assert.assertEquals(value, read.readInt(true));
Assert.assertEquals(value, read.readInt(false));
}
}
@Test
public void testLongs() {
runLongTest(new ByteBuffer2(4096));
}
private void runLongTest(ByteBuffer2 write) {
write.writeLong(0);
write.writeLong(63);
write.writeLong(64);
write.writeLong(127);
write.writeLong(128);
write.writeLong(8192);
write.writeLong(16384);
write.writeLong(2097151);
write.writeLong(1048575);
write.writeLong(134217727);
write.writeLong(268435455);
write.writeLong(134217728);
write.writeLong(268435456);
write.writeLong(-2097151);
write.writeLong(-1048575);
write.writeLong(-134217727);
write.writeLong(-268435455);
write.writeLong(-134217728);
write.writeLong(-268435456);
Assert.assertEquals(1, write.writeLong(0, true));
Assert.assertEquals(1, write.writeLong(0, false));
Assert.assertEquals(1, write.writeLong(63, true));
Assert.assertEquals(1, write.writeLong(63, false));
Assert.assertEquals(1, write.writeLong(64, true));
Assert.assertEquals(2, write.writeLong(64, false));
Assert.assertEquals(1, write.writeLong(127, true));
Assert.assertEquals(2, write.writeLong(127, false));
Assert.assertEquals(2, write.writeLong(128, true));
Assert.assertEquals(2, write.writeLong(128, false));
Assert.assertEquals(2, write.writeLong(8191, true));
Assert.assertEquals(2, write.writeLong(8191, false));
Assert.assertEquals(2, write.writeLong(8192, true));
Assert.assertEquals(3, write.writeLong(8192, false));
Assert.assertEquals(2, write.writeLong(16383, true));
Assert.assertEquals(3, write.writeLong(16383, false));
Assert.assertEquals(3, write.writeLong(16384, true));
Assert.assertEquals(3, write.writeLong(16384, false));
Assert.assertEquals(3, write.writeLong(2097151, true));
Assert.assertEquals(4, write.writeLong(2097151, false));
Assert.assertEquals(3, write.writeLong(1048575, true));
Assert.assertEquals(3, write.writeLong(1048575, false));
Assert.assertEquals(4, write.writeLong(134217727, true));
Assert.assertEquals(4, write.writeLong(134217727, false));
Assert.assertEquals(4, write.writeLong(268435455l, true));
Assert.assertEquals(5, write.writeLong(268435455l, false));
Assert.assertEquals(4, write.writeLong(134217728l, true));
Assert.assertEquals(5, write.writeLong(134217728l, false));
Assert.assertEquals(5, write.writeLong(268435456l, true));
Assert.assertEquals(5, write.writeLong(268435456l, false));
Assert.assertEquals(1, write.writeLong(-64, false));
Assert.assertEquals(9, write.writeLong(-64, true));
Assert.assertEquals(2, write.writeLong(-65, false));
Assert.assertEquals(9, write.writeLong(-65, true));
Assert.assertEquals(2, write.writeLong(-8192, false));
Assert.assertEquals(9, write.writeLong(-8192, true));
Assert.assertEquals(3, write.writeLong(-1048576, false));
Assert.assertEquals(9, write.writeLong(-1048576, true));
Assert.assertEquals(4, write.writeLong(-134217728, false));
Assert.assertEquals(9, write.writeLong(-134217728, true));
Assert.assertEquals(5, write.writeLong(-134217729, false));
Assert.assertEquals(9, write.writeLong(-134217729, true));
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
Assert.assertEquals(0, read.readLong());
Assert.assertEquals(63, read.readLong());
Assert.assertEquals(64, read.readLong());
Assert.assertEquals(127, read.readLong());
Assert.assertEquals(128, read.readLong());
Assert.assertEquals(8192, read.readLong());
Assert.assertEquals(16384, read.readLong());
Assert.assertEquals(2097151, read.readLong());
Assert.assertEquals(1048575, read.readLong());
Assert.assertEquals(134217727, read.readLong());
Assert.assertEquals(268435455, read.readLong());
Assert.assertEquals(134217728, read.readLong());
Assert.assertEquals(268435456, read.readLong());
Assert.assertEquals(-2097151, read.readLong());
Assert.assertEquals(-1048575, read.readLong());
Assert.assertEquals(-134217727, read.readLong());
Assert.assertEquals(-268435455, read.readLong());
Assert.assertEquals(-134217728, read.readLong());
Assert.assertEquals(-268435456, read.readLong());
Assert.assertEquals(0, read.readLong(true));
Assert.assertEquals(0, read.readLong(false));
Assert.assertEquals(63, read.readLong(true));
Assert.assertEquals(63, read.readLong(false));
Assert.assertEquals(64, read.readLong(true));
Assert.assertEquals(64, read.readLong(false));
Assert.assertEquals(127, read.readLong(true));
Assert.assertEquals(127, read.readLong(false));
Assert.assertEquals(128, read.readLong(true));
Assert.assertEquals(128, read.readLong(false));
Assert.assertEquals(8191, read.readLong(true));
Assert.assertEquals(8191, read.readLong(false));
Assert.assertEquals(8192, read.readLong(true));
Assert.assertEquals(8192, read.readLong(false));
Assert.assertEquals(16383, read.readLong(true));
Assert.assertEquals(16383, read.readLong(false));
Assert.assertEquals(16384, read.readLong(true));
Assert.assertEquals(16384, read.readLong(false));
Assert.assertEquals(2097151, read.readLong(true));
Assert.assertEquals(2097151, read.readLong(false));
Assert.assertEquals(1048575, read.readLong(true));
Assert.assertEquals(1048575, read.readLong(false));
Assert.assertEquals(134217727, read.readLong(true));
Assert.assertEquals(134217727, read.readLong(false));
Assert.assertEquals(268435455, read.readLong(true));
Assert.assertEquals(268435455, read.readLong(false));
Assert.assertEquals(134217728, read.readLong(true));
Assert.assertEquals(134217728, read.readLong(false));
Assert.assertEquals(268435456, read.readLong(true));
Assert.assertEquals(268435456, read.readLong(false));
Assert.assertEquals(-64, read.readLong(false));
Assert.assertEquals(-64, read.readLong(true));
Assert.assertEquals(-65, read.readLong(false));
Assert.assertEquals(-65, read.readLong(true));
Assert.assertEquals(-8192, read.readLong(false));
Assert.assertEquals(-8192, read.readLong(true));
Assert.assertEquals(-1048576, read.readLong(false));
Assert.assertEquals(-1048576, read.readLong(true));
Assert.assertEquals(-134217728, read.readLong(false));
Assert.assertEquals(-134217728, read.readLong(true));
Assert.assertEquals(-134217729, read.readLong(false));
Assert.assertEquals(-134217729, read.readLong(true));
Random random = new Random();
for (int i = 0; i < 10000; i++) {
long value = random.nextLong();
write.clear();
write.writeLong(value);
write.writeLong(value, true);
write.writeLong(value, false);
read.setBuffer(write.toBytes());
Assert.assertEquals(value, read.readLong());
Assert.assertEquals(value, read.readLong(true));
Assert.assertEquals(value, read.readLong(false));
}
}
@Test
public void testShorts() {
runShortTest(new ByteBuffer2(4096));
}
private void runShortTest(ByteBuffer2 write) {
write.writeShort(0);
write.writeShort(63);
write.writeShort(64);
write.writeShort(127);
write.writeShort(128);
write.writeShort(8192);
write.writeShort(16384);
write.writeShort(32767);
write.writeShort(-63);
write.writeShort(-64);
write.writeShort(-127);
write.writeShort(-128);
write.writeShort(-8192);
write.writeShort(-16384);
write.writeShort(-32768);
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
Assert.assertEquals(0, read.readShort());
Assert.assertEquals(63, read.readShort());
Assert.assertEquals(64, read.readShort());
Assert.assertEquals(127, read.readShort());
Assert.assertEquals(128, read.readShort());
Assert.assertEquals(8192, read.readShort());
Assert.assertEquals(16384, read.readShort());
Assert.assertEquals(32767, read.readShort());
Assert.assertEquals(-63, read.readShort());
Assert.assertEquals(-64, read.readShort());
Assert.assertEquals(-127, read.readShort());
Assert.assertEquals(-128, read.readShort());
Assert.assertEquals(-8192, read.readShort());
Assert.assertEquals(-16384, read.readShort());
Assert.assertEquals(-32768, read.readShort());
}
@Test
public void testFloats() {
runFloatTest(new ByteBuffer2(4096));
}
private void runFloatTest(ByteBuffer2 write) {
write.writeFloat(0);
write.writeFloat(63);
write.writeFloat(64);
write.writeFloat(127);
write.writeFloat(128);
write.writeFloat(8192);
write.writeFloat(16384);
write.writeFloat(32767);
write.writeFloat(-63);
write.writeFloat(-64);
write.writeFloat(-127);
write.writeFloat(-128);
write.writeFloat(-8192);
write.writeFloat(-16384);
write.writeFloat(-32768);
Assert.assertEquals(1, write.writeFloat(0, 1000, true));
Assert.assertEquals(1, write.writeFloat(0, 1000, false));
Assert.assertEquals(3, write.writeFloat(63, 1000, true));
Assert.assertEquals(3, write.writeFloat(63, 1000, false));
Assert.assertEquals(3, write.writeFloat(64, 1000, true));
Assert.assertEquals(3, write.writeFloat(64, 1000, false));
Assert.assertEquals(3, write.writeFloat(127, 1000, true));
Assert.assertEquals(3, write.writeFloat(127, 1000, false));
Assert.assertEquals(3, write.writeFloat(128, 1000, true));
Assert.assertEquals(3, write.writeFloat(128, 1000, false));
Assert.assertEquals(4, write.writeFloat(8191, 1000, true));
Assert.assertEquals(4, write.writeFloat(8191, 1000, false));
Assert.assertEquals(4, write.writeFloat(8192, 1000, true));
Assert.assertEquals(4, write.writeFloat(8192, 1000, false));
Assert.assertEquals(4, write.writeFloat(16383, 1000, true));
Assert.assertEquals(4, write.writeFloat(16383, 1000, false));
Assert.assertEquals(4, write.writeFloat(16384, 1000, true));
Assert.assertEquals(4, write.writeFloat(16384, 1000, false));
Assert.assertEquals(4, write.writeFloat(32767, 1000, true));
Assert.assertEquals(4, write.writeFloat(32767, 1000, false));
Assert.assertEquals(3, write.writeFloat(-64, 1000, false));
Assert.assertEquals(5, write.writeFloat(-64, 1000, true));
Assert.assertEquals(3, write.writeFloat(-65, 1000, false));
Assert.assertEquals(5, write.writeFloat(-65, 1000, true));
Assert.assertEquals(4, write.writeFloat(-8192, 1000, false));
Assert.assertEquals(5, write.writeFloat(-8192, 1000, true));
float delta = 0.00000001f;
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
Assert.assertEquals(read.readFloat(), 0f, delta);
Assert.assertEquals(read.readFloat(), 63f, delta);
Assert.assertEquals(read.readFloat(), 64f, delta);
Assert.assertEquals(read.readFloat(), 127f, delta);
Assert.assertEquals(read.readFloat(), 128f, delta);
Assert.assertEquals(read.readFloat(), 8192f, delta);
Assert.assertEquals(read.readFloat(), 16384f, delta);
Assert.assertEquals(read.readFloat(), 32767f, delta);
Assert.assertEquals(read.readFloat(), -63f, delta);
Assert.assertEquals(read.readFloat(), -64f, delta);
Assert.assertEquals(read.readFloat(), -127f, delta);
Assert.assertEquals(read.readFloat(), -128f, delta);
Assert.assertEquals(read.readFloat(), -8192f, delta);
Assert.assertEquals(read.readFloat(), -16384f, delta);
Assert.assertEquals(read.readFloat(), -32768f, delta);
Assert.assertEquals(read.readFloat(1000, true), 0f, delta);
Assert.assertEquals(read.readFloat(1000, false), 0f, delta);
Assert.assertEquals(read.readFloat(1000, true), 63f, delta);
Assert.assertEquals(read.readFloat(1000, false), 63f, delta);
Assert.assertEquals(read.readFloat(1000, true), 64f, delta);
Assert.assertEquals(read.readFloat(1000, false), 64f, delta);
Assert.assertEquals(read.readFloat(1000, true), 127f, delta);
Assert.assertEquals(read.readFloat(1000, false), 127f, delta);
Assert.assertEquals(read.readFloat(1000, true), 128f, delta);
Assert.assertEquals(read.readFloat(1000, false), 128f, delta);
Assert.assertEquals(read.readFloat(1000, true), 8191f, delta);
Assert.assertEquals(read.readFloat(1000, false), 8191f, delta);
Assert.assertEquals(read.readFloat(1000, true), 8192f, delta);
Assert.assertEquals(read.readFloat(1000, false), 8192f, delta);
Assert.assertEquals(read.readFloat(1000, true), 16383f, delta);
Assert.assertEquals(read.readFloat(1000, false), 16383f, delta);
Assert.assertEquals(read.readFloat(1000, true), 16384f, delta);
Assert.assertEquals(read.readFloat(1000, false), 16384f, delta);
Assert.assertEquals(read.readFloat(1000, true), 32767f, delta);
Assert.assertEquals(read.readFloat(1000, false), 32767f, delta);
Assert.assertEquals(read.readFloat(1000, false), -64f, delta);
Assert.assertEquals(read.readFloat(1000, true), -64f, delta);
Assert.assertEquals(read.readFloat(1000, false), -65f, delta);
Assert.assertEquals(read.readFloat(1000, true), -65f, delta);
Assert.assertEquals(read.readFloat(1000, false), -8192f, delta);
Assert.assertEquals(read.readFloat(1000, true), -8192f, delta);
}
@Test
public void testDoubles() {
runDoubleTest(new ByteBuffer2(4096));
}
private void runDoubleTest(ByteBuffer2 write) {
write.writeDouble(0);
write.writeDouble(63);
write.writeDouble(64);
write.writeDouble(127);
write.writeDouble(128);
write.writeDouble(8192);
write.writeDouble(16384);
write.writeDouble(32767);
write.writeDouble(-63);
write.writeDouble(-64);
write.writeDouble(-127);
write.writeDouble(-128);
write.writeDouble(-8192);
write.writeDouble(-16384);
write.writeDouble(-32768);
Assert.assertEquals(1, write.writeDouble(0, 1000, true));
Assert.assertEquals(1, write.writeDouble(0, 1000, false));
Assert.assertEquals(3, write.writeDouble(63, 1000, true));
Assert.assertEquals(3, write.writeDouble(63, 1000, false));
Assert.assertEquals(3, write.writeDouble(64, 1000, true));
Assert.assertEquals(3, write.writeDouble(64, 1000, false));
Assert.assertEquals(3, write.writeDouble(127, 1000, true));
Assert.assertEquals(3, write.writeDouble(127, 1000, false));
Assert.assertEquals(3, write.writeDouble(128, 1000, true));
Assert.assertEquals(3, write.writeDouble(128, 1000, false));
Assert.assertEquals(4, write.writeDouble(8191, 1000, true));
Assert.assertEquals(4, write.writeDouble(8191, 1000, false));
Assert.assertEquals(4, write.writeDouble(8192, 1000, true));
Assert.assertEquals(4, write.writeDouble(8192, 1000, false));
Assert.assertEquals(4, write.writeDouble(16383, 1000, true));
Assert.assertEquals(4, write.writeDouble(16383, 1000, false));
Assert.assertEquals(4, write.writeDouble(16384, 1000, true));
Assert.assertEquals(4, write.writeDouble(16384, 1000, false));
Assert.assertEquals(4, write.writeDouble(32767, 1000, true));
Assert.assertEquals(4, write.writeDouble(32767, 1000, false));
Assert.assertEquals(3, write.writeDouble(-64, 1000, false));
Assert.assertEquals(9, write.writeDouble(-64, 1000, true));
Assert.assertEquals(3, write.writeDouble(-65, 1000, false));
Assert.assertEquals(9, write.writeDouble(-65, 1000, true));
Assert.assertEquals(4, write.writeDouble(-8192, 1000, false));
Assert.assertEquals(9, write.writeDouble(-8192, 1000, true));
write.writeDouble(1.23456d);
double delta = 0.00000001D;
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
Assert.assertEquals(read.readDouble(), 0d, delta);
Assert.assertEquals(read.readDouble(), 63d, delta);
Assert.assertEquals(read.readDouble(), 64d, delta);
Assert.assertEquals(read.readDouble(), 127d, delta);
Assert.assertEquals(read.readDouble(), 128d, delta);
Assert.assertEquals(read.readDouble(), 8192d, delta);
Assert.assertEquals(read.readDouble(), 16384d, delta);
Assert.assertEquals(read.readDouble(), 32767d, delta);
Assert.assertEquals(read.readDouble(), -63d, delta);
Assert.assertEquals(read.readDouble(), -64d, delta);
Assert.assertEquals(read.readDouble(), -127d, delta);
Assert.assertEquals(read.readDouble(), -128d, delta);
Assert.assertEquals(read.readDouble(), -8192d, delta);
Assert.assertEquals(read.readDouble(), -16384d, delta);
Assert.assertEquals(read.readDouble(), -32768d, delta);
Assert.assertEquals(read.readDouble(1000, true), 0d, delta);
Assert.assertEquals(read.readDouble(1000, false), 0d, delta);
Assert.assertEquals(read.readDouble(1000, true), 63d, delta);
Assert.assertEquals(read.readDouble(1000, false), 63d, delta);
Assert.assertEquals(read.readDouble(1000, true), 64d, delta);
Assert.assertEquals(read.readDouble(1000, false), 64d, delta);
Assert.assertEquals(read.readDouble(1000, true), 127d, delta);
Assert.assertEquals(read.readDouble(1000, false), 127d, delta);
Assert.assertEquals(read.readDouble(1000, true), 128d, delta);
Assert.assertEquals(read.readDouble(1000, false), 128d, delta);
Assert.assertEquals(read.readDouble(1000, true), 8191d, delta);
Assert.assertEquals(read.readDouble(1000, false), 8191d, delta);
Assert.assertEquals(read.readDouble(1000, true), 8192d, delta);
Assert.assertEquals(read.readDouble(1000, false), 8192d, delta);
Assert.assertEquals(read.readDouble(1000, true), 16383d, delta);
Assert.assertEquals(read.readDouble(1000, false), 16383d, delta);
Assert.assertEquals(read.readDouble(1000, true), 16384d, delta);
Assert.assertEquals(read.readDouble(1000, false), 16384d, delta);
Assert.assertEquals(read.readDouble(1000, true), 32767d, delta);
Assert.assertEquals(read.readDouble(1000, false), 32767d, delta);
Assert.assertEquals(read.readDouble(1000, false), -64d, delta);
Assert.assertEquals(read.readDouble(1000, true), -64d, delta);
Assert.assertEquals(read.readDouble(1000, false), -65d, delta);
Assert.assertEquals(read.readDouble(1000, true), -65d, delta);
Assert.assertEquals(read.readDouble(1000, false), -8192d, delta);
Assert.assertEquals(read.readDouble(1000, true), -8192d, delta);
Assert.assertEquals(1.23456d, read.readDouble(), delta);
}
@Test
public void testBooleans() {
runBooleanTest(new ByteBuffer2(4096));
}
private void runBooleanTest(ByteBuffer2 write) {
for (int i = 0; i < 100; i++) {
write.writeBoolean(true);
write.writeBoolean(false);
}
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
for (int i = 0; i < 100; i++) {
Assert.assertEquals(true, read.readBoolean());
Assert.assertEquals(false, read.readBoolean());
}
}
@Test
public void testChars() {
runCharTest(new ByteBuffer2(4096));
}
private void runCharTest(ByteBuffer2 write) {
write.writeChar((char) 0);
write.writeChar((char) 63);
write.writeChar((char) 64);
write.writeChar((char) 127);
write.writeChar((char) 128);
write.writeChar((char) 8192);
write.writeChar((char) 16384);
write.writeChar((char) 32767);
write.writeChar((char) 65535);
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
Assert.assertEquals(0, read.readChar());
Assert.assertEquals(63, read.readChar());
Assert.assertEquals(64, read.readChar());
Assert.assertEquals(127, read.readChar());
Assert.assertEquals(128, read.readChar());
Assert.assertEquals(8192, read.readChar());
Assert.assertEquals(16384, read.readChar());
Assert.assertEquals(32767, read.readChar());
Assert.assertEquals(65535, read.readChar());
}
@Test
public void testInputWithOffset() throws Exception {
final byte[] buf = new byte[30];
final ByteBuffer2 in = new ByteBuffer2(buf);
in.skip(20);
Assert.assertEquals(10, in.remaining());
}
@Test
public void testSmallBuffers() throws Exception {
ByteBuffer buf = ByteBuffer.allocate(1024);
ByteBuffer2 testOutput = new ByteBuffer2(buf.array());
testOutput.writeBytes(new byte[512]);
testOutput.writeBytes(new byte[512]);
ByteBuffer2 testInputs = new ByteBuffer2();
buf.flip();
testInputs.setBuffer(buf.array());
byte[] toRead = new byte[512];
testInputs.readBytes(toRead);
testInputs.readBytes(toRead);
}
}