/*
* Author: tdanford
* Date: Nov 21, 2008
*/
package org.seqcode.gseutils;
import java.util.*;
public class PackedBitVector implements BitVector {
private int[] bits;
private int length, extra;
public PackedBitVector(int length) {
bits = new int[(length/32)+1];
this.length = length;
for(int i = 0; i < bits.length; i++) {
bits[i] = 0;
}
extra = bits.length*32-length;
}
public PackedBitVector(PackedBitVector v) {
bits = new int[v.bits.length];
length = v.length;
for(int i =0; i < bits.length; i++) {
bits[i] = v.bits[i];
}
}
public int[] asIndices(boolean value) {
int[] array = new int[countOnBits()];
for(int i = 0, j = 0; i < length; i++) {
if(isOn(i) == value) {
array[j++] = i;
}
}
return array;
}
public void copy(PackedBitVector v) {
if(v.length() != length()) {
throw new IllegalArgumentException(String.valueOf(v.length()));
}
for(int i = 0; i < bits.length; i++) {
bits[i] = v.bits[i];
}
}
public void and(PackedBitVector v) {
if(v.length() != length()) {
throw new IllegalArgumentException(String.valueOf(v.length()));
}
for(int i = 0; i < bits.length; i++) {
bits[i] = bits[i] & v.bits[i];
}
}
public void or(PackedBitVector v) {
if(v.length() != length()) {
throw new IllegalArgumentException(String.valueOf(v.length()));
}
for(int i = 0; i < bits.length; i++) {
bits[i] = bits[i] | v.bits[i];
}
}
public void not() {
for(int i = 0; i < bits.length; i++) {
bits[i] = ~bits[i];
}
clearExtraBits();
}
private void clearExtraBits() {
// Make sure we don't flip the "hanging" bits at the end.
int last = bits.length-1;
for(int k = 1; k <= extra; k++) {
bits[last] = BitMasker.setBit(bits[last], 32-k, false);
}
}
public int countOnBits() {
int count = 0;
for(int i = 0; i < bits.length; i++) {
count += BitMasker.countBits(bits[i], true);
}
return count;
}
public boolean isOff(int index) {
int idx = index / 32;
int offset = index % 32;
return !BitMasker.hasBit(bits[idx], offset);
}
public boolean isOn(int index) {
int idx = index / 32;
int offset = index % 32;
return BitMasker.hasBit(bits[idx], offset);
}
public int length() {
return length;
}
public String toHexString() {
StringBuilder sb = new StringBuilder();
for(int i = 0; i < bits.length; i++) {
sb.append(String.format("%08x", bits[i]));
}
return sb.toString();
}
public void turnAllOn() {
for(int i = 0; i < bits.length; i++) {
bits[i] = 0xffffffff;
}
clearExtraBits();
}
public void turnAllOff() {
for(int i = 0;i < bits.length; i++) {
bits[i] = 0;
}
}
public void turnOnRange(int i1, int i2) {
for(int i = i1; i < i2; i++) {
turnOnBit(i);
}
}
public void turnOffRange(int i1, int i2) {
for(int i = i1; i < i2; i++) {
turnOffBit(i);
}
}
public void turnOffBit(int index) {
int idx = index / 32;
int offset = index % 32;
bits[idx] = BitMasker.setBit(bits[idx], offset, false);
}
public void turnOnBit(int index) {
int idx = index / 32;
int offset = index % 32;
bits[idx] = BitMasker.setBit(bits[idx], offset, true);
}
public int hashCode() {
int code = 17;
for(int i = 0; i < bits.length; i++) {
code += bits[i];
}
code *= 37;
return code;
}
public boolean equal(Object o) {
if(!(o instanceof PackedBitVector)) { return false; }
PackedBitVector v = (PackedBitVector)o;
if(bits.length != v.bits.length) { return false; }
if(length != v.length) { return false; }
for(int i = 0; i < bits.length; i++) {
if(bits[i] != v.bits[i]) {
return false;
}
}
return true;
}
public String toString() {
return String.format("%d: %s", length, toHexString());
}
}