add BitArray
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
package mc.utils.array;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public abstract class AbstractBitBufferArray implements BitArray {
|
||||
|
||||
protected int bitPerEntity;
|
||||
protected int arraySize;
|
||||
protected long maxEntityValue;
|
||||
protected ByteBuffer byteBuffer;
|
||||
|
||||
protected int writePosition = 0;
|
||||
|
||||
protected AbstractBitBufferArray(int bitPerEntity, int arraySize, boolean direct) {
|
||||
this.bitPerEntity = bitPerEntity;
|
||||
this.arraySize = arraySize;
|
||||
this.maxEntityValue = (1L << bitPerEntity) - 1L;
|
||||
|
||||
int capaticy = calculateCapacity();
|
||||
if (direct) {
|
||||
this.byteBuffer = ByteBuffer.allocateDirect(capaticy);
|
||||
} else {
|
||||
this.byteBuffer = ByteBuffer.allocate(capaticy);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(int value) {
|
||||
put(writePosition, value);
|
||||
writePosition++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer byteBuffer() {
|
||||
return this.byteBuffer;
|
||||
}
|
||||
|
||||
protected void validateIndex(int index) {
|
||||
if (index < 0 || index > arraySize - 1) {
|
||||
throw new IllegalArgumentException("Index " + index + " out of range [0;" + arraySize + "]");
|
||||
}
|
||||
}
|
||||
|
||||
protected void validateValue(int value) {
|
||||
if ((value | maxEntityValue) > maxEntityValue) {
|
||||
throw new IllegalArgumentException("Invalide value " + value + ". Value bits: " + Integer.bitCount(value) + ", maximum bits: " + bitPerEntity);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract int calculateCapacity();
|
||||
}
|
||||
13
utils/src/main/java/mc/utils/array/BitArray.java
Normal file
13
utils/src/main/java/mc/utils/array/BitArray.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package mc.utils.array;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public interface BitArray {
|
||||
|
||||
void put(int value);
|
||||
void put(int index, int value);
|
||||
|
||||
int get(int index);
|
||||
|
||||
ByteBuffer byteBuffer();
|
||||
}
|
||||
62
utils/src/main/java/mc/utils/array/BitByteArray.java
Normal file
62
utils/src/main/java/mc/utils/array/BitByteArray.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package mc.utils.array;
|
||||
|
||||
public class BitByteArray extends AbstractBitBufferArray {
|
||||
|
||||
public BitByteArray(int bitPerEntity, int arraySize, boolean direct) {
|
||||
super(bitPerEntity, arraySize, direct);
|
||||
}
|
||||
|
||||
public BitByteArray(int bitPerEntity, int arraySize) {
|
||||
this(bitPerEntity, arraySize, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(int index, int value) {
|
||||
validateIndex(index);
|
||||
validateValue(value);
|
||||
|
||||
//@formatter:off
|
||||
int headValueIndex = ((index + 1) * bitPerEntity - 1) / Byte.SIZE;
|
||||
int var1 = index * bitPerEntity;
|
||||
int tailValueIndex = var1 / Byte.SIZE;
|
||||
int offsetValue = var1 % Byte.SIZE;
|
||||
//@formatter:on
|
||||
|
||||
byteBuffer.put(tailValueIndex,
|
||||
(byte) (byteBuffer.get(tailValueIndex) & ~(maxEntityValue << offsetValue)
|
||||
| ((byte) value & maxEntityValue) << offsetValue));
|
||||
|
||||
if (headValueIndex != tailValueIndex) {
|
||||
int shift1 = Byte.SIZE - offsetValue;
|
||||
int shift2 = bitPerEntity - shift1;
|
||||
|
||||
byteBuffer.put(headValueIndex,
|
||||
(byte) (byteBuffer.get(headValueIndex) >>> shift2 << shift2
|
||||
| ((byte) value & maxEntityValue) >> shift1));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get(int index) {
|
||||
validateIndex(index);
|
||||
|
||||
//@formatter:off
|
||||
int headValueIndex = ((index + 1) * bitPerEntity - 1) / Byte.SIZE;
|
||||
int var1 = index * bitPerEntity;
|
||||
int tailValueIndex = var1 / Byte.SIZE;
|
||||
int offsetValue = var1 % Byte.SIZE;
|
||||
//@formatter:on
|
||||
|
||||
if (headValueIndex == tailValueIndex) {
|
||||
return (int) (byteBuffer.get(tailValueIndex) >>> offsetValue & maxEntityValue);
|
||||
} else {
|
||||
return (int) ((byteBuffer.get(tailValueIndex) >>> offsetValue
|
||||
| byteBuffer.get(headValueIndex) << (Byte.SIZE - offsetValue)) & maxEntityValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int calculateCapacity() {
|
||||
return (arraySize * bitPerEntity / Byte.SIZE + 1) * Byte.BYTES;
|
||||
}
|
||||
}
|
||||
67
utils/src/main/java/mc/utils/array/BitLongArray.java
Normal file
67
utils/src/main/java/mc/utils/array/BitLongArray.java
Normal file
@@ -0,0 +1,67 @@
|
||||
package mc.utils.array;
|
||||
|
||||
import java.nio.LongBuffer;
|
||||
|
||||
public class BitLongArray extends AbstractBitBufferArray {
|
||||
|
||||
private final LongBuffer longBuffer;
|
||||
|
||||
public BitLongArray(int bitPerEntity, int arraySize, boolean direct) {
|
||||
super(bitPerEntity, arraySize, direct);
|
||||
this.longBuffer = this.byteBuffer.asLongBuffer();
|
||||
}
|
||||
|
||||
public BitLongArray(int bitPerEntity, int arraySize) {
|
||||
this(bitPerEntity, arraySize, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(int index, int value) {
|
||||
validateIndex(index);
|
||||
validateValue(value);
|
||||
|
||||
//@formatter:off
|
||||
int headValueIndex = ((index + 1) * bitPerEntity - 1) / Long.SIZE;
|
||||
int var1 = index * bitPerEntity;
|
||||
int tailValueIndex = var1 / Long.SIZE;
|
||||
int offsetValue = var1 % Long.SIZE;
|
||||
//@formatter:on
|
||||
|
||||
longBuffer.put(tailValueIndex,
|
||||
longBuffer.get(tailValueIndex) & ~(maxEntityValue << offsetValue)
|
||||
| ((long) value & maxEntityValue) << offsetValue);
|
||||
|
||||
if (headValueIndex != tailValueIndex) {
|
||||
int shift1 = Long.SIZE - offsetValue;
|
||||
int shift2 = bitPerEntity - shift1;
|
||||
|
||||
longBuffer.put(headValueIndex,
|
||||
longBuffer.get(headValueIndex) >>> shift2 << shift2
|
||||
| ((long) value & maxEntityValue) >> shift1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get(int index) {
|
||||
validateIndex(index);
|
||||
|
||||
//@formatter:off
|
||||
int headValueIndex = ((index + 1) * bitPerEntity - 1) / Long.SIZE;
|
||||
int var1 = index * bitPerEntity;
|
||||
int tailValueIndex = var1 / Long.SIZE;
|
||||
int offsetValue = var1 % Long.SIZE;
|
||||
//@formatter:on
|
||||
|
||||
if (headValueIndex == tailValueIndex) {
|
||||
return (int) (longBuffer.get(tailValueIndex) >>> offsetValue & maxEntityValue);
|
||||
} else {
|
||||
return (int) ((longBuffer.get(tailValueIndex) >>> offsetValue
|
||||
| longBuffer.get(headValueIndex) << (Long.SIZE - offsetValue)) & maxEntityValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int calculateCapacity() {
|
||||
return (arraySize * bitPerEntity / Long.SIZE + 1) * Long.BYTES;
|
||||
}
|
||||
}
|
||||
80
utils/src/test/java/mc/utils/array/BitByteArrayTest.java
Normal file
80
utils/src/test/java/mc/utils/array/BitByteArrayTest.java
Normal file
@@ -0,0 +1,80 @@
|
||||
package mc.utils.array;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class BitByteArrayTest {
|
||||
|
||||
@Test
|
||||
void initTest() {
|
||||
BitArray bitArray = new BitByteArray(4, 1, false);
|
||||
ByteBuffer byteBuffer = bitArray.byteBuffer();
|
||||
|
||||
assertEquals(1, byteBuffer.capacity());
|
||||
assertEquals(1, byteBuffer.limit());
|
||||
assertEquals(0, byteBuffer.position());
|
||||
assertEquals(1, byteBuffer.array().length);
|
||||
|
||||
bitArray = new BitByteArray(4, 2);
|
||||
byteBuffer = bitArray.byteBuffer();
|
||||
|
||||
assertEquals(2, byteBuffer.capacity());
|
||||
assertEquals(2, byteBuffer.limit());
|
||||
}
|
||||
|
||||
@Test
|
||||
void writeTest1() {
|
||||
int value = 0b00001001;
|
||||
int expected = 0b10011001;
|
||||
|
||||
BitArray bitArray = new BitByteArray(4, 2);
|
||||
bitArray.put(value);
|
||||
bitArray.put(value);
|
||||
|
||||
ByteBuffer byteBuffer = bitArray.byteBuffer();
|
||||
assertEquals(expected, byteBuffer.get(0) & 0xFF); //Unsigned Byte
|
||||
}
|
||||
|
||||
@Test
|
||||
void writeTest2() {
|
||||
int value1 = 0b00001001;
|
||||
int value2 = 0b00001111;
|
||||
int expected1 = 0b10011001;
|
||||
int expected2 = 0b11111111;
|
||||
|
||||
BitArray bitArray = new BitByteArray(4, 4);
|
||||
bitArray.put(value1);
|
||||
bitArray.put(value1);
|
||||
bitArray.put(value2);
|
||||
bitArray.put(value2);
|
||||
|
||||
ByteBuffer byteBuffer = bitArray.byteBuffer();
|
||||
assertEquals(expected1, byteBuffer.get(0) & 0xFF); //Unsigned Byte
|
||||
assertEquals(expected2, byteBuffer.get(1) & 0xFF); //Unsigned Byte
|
||||
}
|
||||
|
||||
@Test
|
||||
void writeOffsetTest() {
|
||||
int value = 0b00001001;
|
||||
int expected = 0b10010000;
|
||||
|
||||
BitArray bitArray = new BitByteArray(4, 2);
|
||||
bitArray.put(1, value);
|
||||
|
||||
ByteBuffer byteBuffer = bitArray.byteBuffer();
|
||||
assertEquals(expected, byteBuffer.get(0) & 0xFF); //Unsigned Byte
|
||||
}
|
||||
|
||||
@Test
|
||||
void readTest() {
|
||||
int excepted = 0b00000110;
|
||||
|
||||
BitArray bitArray = new BitByteArray(4, 2);
|
||||
bitArray.put(1, excepted);
|
||||
|
||||
assertEquals(excepted, bitArray.get(1));
|
||||
}
|
||||
}
|
||||
81
utils/src/test/java/mc/utils/array/BitLongArrayTest.java
Normal file
81
utils/src/test/java/mc/utils/array/BitLongArrayTest.java
Normal file
@@ -0,0 +1,81 @@
|
||||
package mc.utils.array;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class BitLongArrayTest {
|
||||
|
||||
@Test
|
||||
void initTest() {
|
||||
BitArray bitArray = new BitLongArray(13, 1, false);
|
||||
ByteBuffer byteBuffer = bitArray.byteBuffer();
|
||||
|
||||
assertEquals(8, byteBuffer.capacity());
|
||||
assertEquals(8, byteBuffer.limit());
|
||||
assertEquals(0, byteBuffer.position());
|
||||
assertEquals(8, byteBuffer.array().length);
|
||||
|
||||
bitArray = new BitLongArray(13, 5);
|
||||
byteBuffer = bitArray.byteBuffer();
|
||||
|
||||
assertEquals(16, byteBuffer.capacity());
|
||||
assertEquals(16, byteBuffer.limit());
|
||||
}
|
||||
|
||||
@Test
|
||||
void writeTest1() {
|
||||
int value = 0b00010000_00000011;
|
||||
long expected = 0b00000000_00000000_00000000_00000000_00000010_00000000_01110000_00000011L;
|
||||
|
||||
BitArray bitArray = new BitLongArray(13, 2);
|
||||
bitArray.put(value);
|
||||
bitArray.put(value);
|
||||
|
||||
LongBuffer longBuffer = bitArray.byteBuffer().asLongBuffer();
|
||||
assertEquals(expected, longBuffer.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void writeTest2() {
|
||||
int value = 0b00010000_00000011;
|
||||
long expected1 = 0b00000000_00111000_00000001_11000000_00001110_00000000_01110000_00000011L;
|
||||
long expected2 = 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000001L;
|
||||
|
||||
BitArray bitArray = new BitLongArray(13, 5);
|
||||
bitArray.put(value);
|
||||
bitArray.put(value);
|
||||
bitArray.put(value);
|
||||
bitArray.put(value);
|
||||
bitArray.put(value);
|
||||
|
||||
LongBuffer longBuffer = bitArray.byteBuffer().asLongBuffer();
|
||||
assertEquals(expected1, longBuffer.get(0));
|
||||
assertEquals(expected2, longBuffer.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void writeOffsetTest() {
|
||||
int value = 0b00010000_00000011;
|
||||
long expected = 0b00000000_00000000_00000000_00000000_00000010_00000000_01100000_00000000;
|
||||
|
||||
BitArray bitArray = new BitLongArray(13, 2);
|
||||
bitArray.put(1, value);
|
||||
|
||||
LongBuffer longBuffer = bitArray.byteBuffer().asLongBuffer();
|
||||
assertEquals(expected, longBuffer.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void readTest() {
|
||||
int excepted = 0b00010000_00000011;
|
||||
|
||||
BitArray bitArray = new BitLongArray(13, 2);
|
||||
bitArray.put(1, excepted);
|
||||
|
||||
assertEquals(excepted, bitArray.get(1));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user