Created
December 14, 2016 11:58
-
-
Save sangupta/2601a9f81307ec4541ec31791e507cc2 to your computer and use it in GitHub Desktop.
Sparse BitArray implementation in Java
This file contains 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
package com.sangupta.jerry.ds.bitarray; | |
import java.io.IOException; | |
import com.sangupta.jerry.util.BitUtils; | |
import com.sangupta.jerry.util.ByteArrayUtils; | |
import net.jcip.annotations.NotThreadSafe; | |
@NotThreadSafe | |
public class SparseBitArray implements BitArray { | |
/** | |
* Bits per element - we are using <code>long</code> for elements | |
* and thus 64 bits | |
*/ | |
private final int BITS_PER_ELEMENT = Long.SIZE; | |
/** | |
* Number of bytes per element | |
*/ | |
private final int BYTES_PER_ELEMENT = BITS_PER_ELEMENT / 8; | |
/** | |
* Number of buckets that we need to initialize | |
*/ | |
private final int numBuckets; | |
/** | |
* Bits held in one bucket | |
*/ | |
private final int bitsPerBucket; | |
/** | |
* Number of elements or long values per bucket | |
*/ | |
private final int elementsNeededPerBucket; | |
/** | |
* Maximum index that we can accomodate in this sparse array | |
*/ | |
private final int maxIndex; | |
/** | |
* The backing array | |
*/ | |
private final long[][] array; | |
/** | |
* Constructor | |
* | |
* @param numBuckets | |
* @param bucketSize | |
*/ | |
public SparseBitArray(int numBuckets, int bucketSize) { | |
this.numBuckets = numBuckets; | |
this.bitsPerBucket = bucketSize; | |
this.maxIndex = bucketSize * numBuckets; | |
int elements = this.bitsPerBucket / BITS_PER_ELEMENT; | |
if(this.bitsPerBucket % BITS_PER_ELEMENT > 0) { | |
elements++; | |
} | |
this.elementsNeededPerBucket = elements; | |
this.array = new long[this.numBuckets][]; | |
} | |
@Override | |
public void close() throws IOException { | |
// nothing to do here | |
} | |
@Override | |
public boolean getBit(int index) { | |
if(index < 0) { | |
throw new IndexOutOfBoundsException("Index is out of range: " + index); | |
} | |
if(index > this.maxIndex) { | |
throw new IndexOutOfBoundsException("Index is out of range: " + index); | |
} | |
int bucket = index / this.bitsPerBucket; | |
if(this.array[bucket] == null) { | |
return false; | |
} | |
int subIndex = index % this.bitsPerBucket; | |
int element = subIndex / BITS_PER_ELEMENT; | |
int bit = subIndex % BITS_PER_ELEMENT; | |
long[] subArray = this.array[bucket]; | |
long value = subArray[element]; | |
return BitUtils.isBitSet(value, bit); | |
} | |
@Override | |
public boolean setBit(int index) { | |
if(index < 0) { | |
throw new IndexOutOfBoundsException("Index is out of range: " + index); | |
} | |
if(index > this.maxIndex) { | |
throw new IndexOutOfBoundsException("Index is out of range: " + index); | |
} | |
int bucket = index / this.bitsPerBucket; | |
if(this.array[bucket] == null) { | |
this.array[bucket] = new long[this.elementsNeededPerBucket]; | |
} | |
int subIndex = index % this.bitsPerBucket; | |
int element = subIndex / BITS_PER_ELEMENT; | |
int bit = subIndex % BITS_PER_ELEMENT; | |
long[] subArray = this.array[bucket]; | |
long value = subArray[element]; | |
long updated = BitUtils.setBit(value, bit); | |
if(value != updated) { | |
subArray[element] = updated; | |
return true; | |
} | |
return false; | |
} | |
@Override | |
public void clear() { | |
for(int bucket = 0; bucket < this.numBuckets; bucket++) { | |
this.array[bucket] = null; | |
} | |
} | |
@Override | |
public void clearBit(int index) { | |
if(index < 0) { | |
throw new IndexOutOfBoundsException("Index is out of range: " + index); | |
} | |
if(index > this.maxIndex) { | |
throw new IndexOutOfBoundsException("Index is out of range: " + index); | |
} | |
int bucket = index / this.bitsPerBucket; | |
if(this.array[bucket] == null) { | |
return; | |
} | |
int subIndex = index % this.bitsPerBucket; | |
int element = subIndex / BITS_PER_ELEMENT; | |
int bit = subIndex % BITS_PER_ELEMENT; | |
long[] subArray = this.array[bucket]; | |
long value = subArray[element]; | |
long updated = BitUtils.clearBit(value, bit); | |
this.array[bucket][element] = updated; | |
} | |
@Override | |
public boolean setBitIfUnset(int index) { | |
if(index < 0) { | |
throw new IndexOutOfBoundsException("Index is out of range: " + index); | |
} | |
if(index > this.maxIndex) { | |
throw new IndexOutOfBoundsException("Index is out of range: " + index); | |
} | |
int bucket = index / this.bitsPerBucket; | |
if(this.array[bucket] == null) { | |
this.array[bucket] = new long[this.elementsNeededPerBucket]; | |
} | |
int subIndex = index % this.bitsPerBucket; | |
int element = subIndex / BITS_PER_ELEMENT; | |
int bit = subIndex % BITS_PER_ELEMENT; | |
long[] subArray = this.array[bucket]; | |
long value = subArray[element]; | |
long updated = BitUtils.setBit(value, bit); | |
if(value != updated) { | |
subArray[element] = updated; | |
return true; | |
} | |
return false; | |
} | |
@Override | |
public void or(BitArray bitArray) { | |
throw new RuntimeException("not yet implemented"); | |
} | |
@Override | |
public void and(BitArray bitArray) { | |
if(array == null) { | |
throw new IllegalArgumentException("Array to be combined with cannot be null"); | |
} | |
if(bitArray instanceof SparseBitArray) { | |
throw new RuntimeException("not yet implemented"); | |
} | |
@Override | |
public int bitSize() { | |
return this.maxIndex; | |
} | |
@Override | |
public int numBytes() { | |
return this.numBuckets * this.elementsNeededPerBucket * (this.BITS_PER_ELEMENT / BYTES_PER_ELEMENT); | |
} | |
@Override | |
public byte[] toByteArray() { | |
throw new RuntimeException("not yet implemented"); | |
} | |
@Override | |
public int getHighestBitSet() { | |
throw new RuntimeException("not yet implemented"); | |
} | |
@Override | |
public int getLowestBitSet() { | |
throw new RuntimeException("not yet implemented"); | |
} | |
@Override | |
public int getNextSetBit(int fromIndex) { | |
throw new RuntimeException("not yet implemented"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment