package org.torrent.internal.util; import java.util.Arrays; import java.util.Iterator; import java.util.NoSuchElementException; public class Bits implements Iterable<Boolean>, Cloneable { private int size; private int[] bits; public Bits(int size) { this.size = size; bits = new int[(size + 31) >> 5]; } public Bits(Bits bitSet) { size = bitSet.size; bits = Arrays.copyOf(bitSet.bits, bitSet.bits.length); } @Override public Object clone() { try { Bits b = (Bits) super.clone(); b.bits = Arrays.copyOf(bits, bits.length); return b; } catch (CloneNotSupportedException e) { throw new InternalError(e.getLocalizedMessage()); } } public Bits(int size, int[] bits) { this.size = size; this.bits = Arrays.copyOf(bits, bits.length); } public Bits unmodifableBits() { return new Bits(size, bits) { @Override public void set(int i, boolean b) { throw new UnsupportedOperationException(); } @Override public void setSize(int size) { throw new UnsupportedOperationException(); } }; } public int size() { return size; } public boolean get(int i) { Validator.isTrue(i >= 0 && i < size, "Index out of bounds: " + i); return (bits[i >> 5] & (1 << (i & 0x1f))) != 0; } @Override public int hashCode() { return Arrays.hashCode(bits); } @Override public String toString() { StringBuilder b = new StringBuilder(); b.append("[Bitset size: "); b.append(size); for (int i = 0; i < 8 && i < size; i++) { b.append(' '); b.append(get(i)); } if (size > 8) { b.append("..."); } b.append(']'); return b.toString(); } @Override public boolean equals(Object obj) { if (obj instanceof Bits) { Bits o = (Bits) obj; return Arrays.equals(bits, o.bits); } return false; } @Override public Iterator<Boolean> iterator() { return new Iterator<Boolean>() { private int index = 0; private int j = 1; private int bitidx = 0; @Override public boolean hasNext() { return bitidx < size; } @Override public Boolean next() { if (!hasNext()) { throw new NoSuchElementException(); } bitidx++; boolean res = (bits[index] & j) != 0; j <<= 1; if (j == 0) { j = 1; index++; } return res; } @Override public void remove() { throw new UnsupportedOperationException(); } }; } public void set(int i, boolean b) { Validator.isTrue(i >= 0 && i < size, "Index out of bounds: " + i); int j = i & 0x1f; i >>= 5; if (b) { bits[i] |= ((1 << j)); } else { bits[i] &= (~(1 << j)); } } public void setSize(int size) { Validator.isTrue(size >= 0, "Invalid size: " + size); this.size = size; bits = Arrays.copyOf(bits, (size + 31) >> 5); } public void set(Bits toField) { Validator.notNull(toField, "Bitfield is null!"); size = toField.size; bits = Arrays.copyOf(toField.bits, toField.bits.length); } public int firstIndexOf(boolean b, int start) { Validator .isTrue(start >= 0 && start <= size, "Invalid start: " + start); for (int i = start; i < size; i++) { if ((bits[i >> 5] & (1 << (i & 0x1f))) == 0 ^ b) { return i; } } return -1; } public int firstIndexOf(boolean value) { return firstIndexOf(value, 0); } public int count(boolean b) { int sum = 0; for (int i = 0; i < size; i++) { if (get(i) == b) { sum++; } } return sum; } public static Bits filledBits(int piecesCount) { Bits b = new Bits(piecesCount); for (int i = 0; i < b.size; i++) { b.set(i, true); } return b; } }