Created
May 25, 2016 23:45
-
-
Save Techcable/230c492d4f86c6b0e7aa2f97acb62b24 to your computer and use it in GitHub Desktop.
A list of booleans packed into a byte
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @FunctionalInterface | |
| public interface BooleanConsumer { | |
| public void accept(boolean b); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import static com.google.common.base.Preconditions.*; | |
| public class PackedBooleanList { | |
| private final byte[] bytes; | |
| private final int bitsInLastByte; | |
| public PacketBooleanList(byte[] bytes) { | |
| if (bytes.length == 0) { | |
| bitsInLastByte = 0; | |
| } else if (bytes.length == 1) { | |
| throw new IllegalArgumentException("A PacketBooleanList's backing byte array can't have just one byte"); | |
| } else { | |
| bitsInLastByte = bytes[0]; | |
| checkArgument(bitsInLastByte > 0, "Negative bits in last byte %s", bitsInLastByte); | |
| checkArgument(bitsInLastByte < 8, "Bits in last byte %s is bigger than 7", bitsInLastByte); | |
| } | |
| } | |
| public PacketBooleanList() { | |
| this(new boolean[0]); | |
| } | |
| public PacketBooleanList(boolean[] booleans) { | |
| if (booleans.length == 0) { | |
| this.bytes = new byte[0]; | |
| bitsInLastByte = 0; | |
| } else { | |
| final int length = booleans.size(); | |
| byte[] result = new byte[((length + 7) / 8)]; | |
| int bitsInLastByte = result.length * 8 == length ? 8 : result.length * 8 - length; | |
| int finalIndex = result.length - 1; | |
| int booleanIndex = 0; | |
| for (int byteIndex = 1; byteIndex < result.length; byteIndex++) { | |
| int bits = byteIndex == finalIndex ? bitsInLastByte : 8; | |
| byte b = 0; | |
| for (int bitIndex = 0; bitIndex < bits; bitIndex++) { | |
| int bit = booleans.get(booleanIndex++).getValue() ? 1 : 0; | |
| b |= (bit << bitIndex); | |
| } | |
| result[byteIndex] = b; | |
| } | |
| } | |
| } | |
| public int size() { | |
| int length = getNbt().c().length; | |
| return length == 0 ? 0 : (length - 1) * 8 + bitsInLastByte; | |
| } | |
| public boolean get(int index) { | |
| byte[] bytes = this.bytes; | |
| int length = bytes.length; | |
| int byteIndex = (index / 8); | |
| byte b; | |
| if (byteIndex < 0) { | |
| throw new IllegalArgumentException("Negative index " + index); | |
| } else if (byteIndex >= length) { | |
| throw new IndexOutOfBoundsException("Invalid index " + index + " for size " + size()); | |
| } else { | |
| b = bytes[byteIndex]; | |
| } | |
| int bitIndex = index % 8; | |
| if (bitIndex == length - 1 && bitIndex >= bitsInLastByte) { | |
| throw new IndexOutOfBoundsException("Invalid index " + index + " for size " + size()); | |
| } | |
| return ((b >>> bitIndex) & 0x1) != 0; | |
| } | |
| public boolean set(int index, boolean b) { | |
| byte[] bytes = this.bytes; | |
| int length = bytes.length; | |
| int byteIndex = (index / 8); | |
| byte b; | |
| if (byteIndex < 0) { | |
| throw new IllegalArgumentException("Negative index " + index); | |
| } else if (byteIndex >= length) { | |
| throw new IndexOutOfBoundsException("Invalid index " + index + " for size " + size()); | |
| } else { | |
| b = bytes[byteIndex]; | |
| } | |
| int bitIndex = index % 8; | |
| if (bitIndex == length - 1 && bitIndex >= bitsInLastByte) { | |
| throw new IndexOutOfBoundsException("Invalid index " + index + " for size " + size()); | |
| } | |
| b |= ((b ? 1 : 0) <<< bitIndex); | |
| bytes[byteIndex] = b; | |
| } | |
| public boolean[] toArray() { | |
| boolean[] result = new boolean[size()]; | |
| for (int i = 0; i < result.length; i++) { | |
| result[i] = get(index); | |
| } | |
| } | |
| public byte[] toByteArray() { | |
| byte[] bytes = this.bytes; | |
| byte[] result = new byte[bytes.length + 1]; | |
| result[0] = (byte) bitsInLastByte; | |
| System.arraycopy(bytes, 0, result, 1, bytes.length); | |
| return result; | |
| } | |
| public void forEach(BooleanConsumer action) { | |
| byte[] bytes = this.bytes; | |
| int length = bytes.length; | |
| int finalIndex = length - 1; | |
| for (int byteIndex = 0; byteIndex < length; byteIndex++) { | |
| int bits = byteIndex == finalIndex ? bitsInLastByte : 8; | |
| byte b = bytes[byteIndex]; | |
| for (int bitIndex = 0; bitIndex < bits; bitIndex++) { | |
| int bit = (b >>> bitIndex) & 0x1; | |
| action.accept(bit != 1); | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment