Skip to content

Commit

Permalink
Implement out-of-order set
Browse files Browse the repository at this point in the history
  • Loading branch information
gssiyankai committed Sep 7, 2014
1 parent 2bd52ca commit a6a5265
Show file tree
Hide file tree
Showing 6 changed files with 945 additions and 46 deletions.
154 changes: 141 additions & 13 deletions src/main/java/com/googlecode/javaewah/EWAHCompressedBitmap.java
Original file line number Diff line number Diff line change
Expand Up @@ -1190,13 +1190,13 @@ public boolean get(final int i) {
public int getFirstSetBit() {
int nword = 0;
for(int pos = 0; pos < this.actualSizeInWords;++pos) {
long rl = (this.buffer[pos] >>> 1) & RunningLengthWord.LARGEST_RUNNING_LENGTH_COUNT;
boolean rb = (this.buffer[pos] & 1) != 0;
long rl = RunningLengthWord.getRunningLength(this.buffer, pos);
boolean rb = RunningLengthWord.getRunningBit(this.buffer, pos);
if((rl > 0) && rb) {
return nword * WORD_IN_BITS;
}
nword += rl;
long lw = (this.buffer[pos] >>> (1 + RunningLengthWord.RUNNING_LENGTH_BITS));
long lw = RunningLengthWord.getNumberOfLiteralWords(this.buffer, pos);
if(lw > 0) {
long word = this.buffer[pos + 1];
if(word != 0l) {
Expand All @@ -1210,9 +1210,7 @@ public int getFirstSetBit() {


/**
* Set the bit at position i to true, the bits must be set in (strictly)
* increasing order. For example, set(15) and then set(7) will fail. You
* must do set(7) and then set(15).
* Set the bit at position i to true.
*
* Since this modifies the bitmap, this method is not thread-safe.
*
Expand All @@ -1228,21 +1226,33 @@ public boolean set(final int i) {
"Set values should be between 0 and "
+ (Integer.MAX_VALUE - WORD_IN_BITS)
);
if (i < this.sizeInBits)
return false;
// distance in words:
if (i < this.sizeInBits) {
locateAndSet(i);
} else {
extendAndSet(i);
}
return true;
}

/**
* For internal use.
*
* @param i the index
*/
private void extendAndSet(int i) {
final int dist = distanceInWords(i);
this.sizeInBits = i + 1;
if (dist > 0) {// easy
if (dist > 1)
if (dist > 1) {
fastaddStreamOfEmptyWords(false, dist - 1);
}
addLiteralWord(1l << (i % WORD_IN_BITS));
return true;
return;
}
if (this.rlw.getNumberOfLiteralWords() == 0) {
this.rlw.setRunningLength(this.rlw.getRunningLength() - 1);
addLiteralWord(1l << (i % WORD_IN_BITS));
return true;
return;
}
this.buffer[this.actualSizeInWords - 1] |= 1l << (i % WORD_IN_BITS);
if (this.buffer[this.actualSizeInWords - 1] == ~0l) {
Expand All @@ -1253,7 +1263,125 @@ public boolean set(final int i) {
// next we add one clean word
addEmptyWord(true);
}
return true;
}

/**
* For internal use.
*
* @param i the index
*/
private void locateAndSet(int i) {
int nbits = 0;
for(int pos = 0; pos < this.actualSizeInWords; ) {
long rl = RunningLengthWord.getRunningLength(this.buffer, pos);
boolean rb = RunningLengthWord.getRunningBit(this.buffer, pos);
long lw = RunningLengthWord.getNumberOfLiteralWords(this.buffer, pos);
long rbits = rl * WORD_IN_BITS;
if(i < nbits + rbits) {
setInRunningLength(i, nbits, pos, rl, rb, lw);
return;
}
nbits += rbits;
long lbits = lw * WORD_IN_BITS;
if(i < nbits + lbits) {
setInLiteralWords(i, nbits, pos, rl, rb, lw);
return;
}
nbits += lbits;
pos += lw + 1;
}
}

private void setInRunningLength(int i, int nbits, int pos, long rl, boolean rb, long lw) {
if(!rb) {
int wordPosition = (i - nbits) / WORD_IN_BITS + 1;
int addedWords = (wordPosition==rl) ? 1 : 2;
int size = newSizeInWords(addedWords);
final long oldBuffer[] = this.buffer;
if(size >= this.buffer.length) {
this.buffer = new long[size];
System.arraycopy(oldBuffer, 0, this.buffer, 0, pos + 1);
}
System.arraycopy(oldBuffer, pos + 1, this.buffer, pos + 1 + addedWords, this.actualSizeInWords - pos - 1);
this.actualSizeInWords += addedWords;
this.buffer[pos+1] = 1l << i % WORD_IN_BITS;
if(this.rlw.position >= pos+1) {
this.rlw.position += addedWords;
}
if(addedWords==1) {
setRLWInfo(pos, false, rl-1, lw+1);
} else {
setRLWInfo(pos, false, wordPosition-1, 1l);
setRLWInfo(pos+2, false, rl-wordPosition, lw);
if(this.rlw.position == pos) {
this.rlw.position += 2;
}
}
}
}

private void setInLiteralWords(int i, int nbits, int pos, long rl, boolean rb, long lw) {
int wordPosition = (i - nbits) / WORD_IN_BITS + 1;
this.buffer[pos + wordPosition] |= 1l << i % WORD_IN_BITS;
if(this.buffer[pos + wordPosition]==(~0l)) {
boolean canMergeInCurrentRLW = mergeLiteralWordInCurrentRunningLength(rb, rl, wordPosition);
boolean canMergeInNextRLW = mergeLiteralWordInNextRunningLength(lw, pos, wordPosition);
if(canMergeInCurrentRLW && canMergeInNextRLW) {
long nextRl = RunningLengthWord.getRunningLength(this.buffer, pos + 2);
long nextLw = RunningLengthWord.getNumberOfLiteralWords(this.buffer, pos + 2);
System.arraycopy(this.buffer, pos + 2, this.buffer, pos, this.actualSizeInWords - pos - 2);
this.buffer[--this.actualSizeInWords] = 0l;
this.buffer[--this.actualSizeInWords] = 0l;
setRLWInfo(pos, true, rl + 1 + nextRl, nextLw);
if(this.rlw.position >= pos+2) {
this.rlw.position -= 2;
}
} else if(canMergeInCurrentRLW) {
System.arraycopy(this.buffer, pos + 2, this.buffer, pos + 1, this.actualSizeInWords - pos - 2);
this.buffer[--this.actualSizeInWords] = 0l;
setRLWInfo(pos, true, rl+1, lw-1);
if(this.rlw.position >= pos+2) {
this.rlw.position--;
}
} else if(canMergeInNextRLW) {
int nextRLWPos = (int) (pos + lw + 1);
long nextRl = RunningLengthWord.getRunningLength(this.buffer, nextRLWPos);
long nextLw = RunningLengthWord.getNumberOfLiteralWords(this.buffer, nextRLWPos);
System.arraycopy(this.buffer, nextRLWPos, this.buffer, pos+wordPosition, this.actualSizeInWords - nextRLWPos);
this.buffer[--this.actualSizeInWords] = 0l;
setRLWInfo(pos, rb, rl, lw-1);
setRLWInfo(pos+wordPosition, true, nextRl+1, nextLw);
if(this.rlw.position >= nextRLWPos) {
this.rlw.position -= lw + 1 - wordPosition;
}
} else {
setRLWInfo(pos, rb, rl, wordPosition-1);
setRLWInfo(pos+wordPosition, true, 1l, lw-wordPosition);
if(this.rlw.position == pos) {
this.rlw.position += wordPosition;
}
}
}
}

private boolean mergeLiteralWordInCurrentRunningLength(boolean rb, long rl, int wordPosition) {
return (rb || rl==0) && wordPosition==1;
}

private boolean mergeLiteralWordInNextRunningLength(long lw, int pos, int wordPosition) {
int nextRLWPos = (int) (pos + lw + 1);
if(lw==wordPosition && nextRLWPos<this.actualSizeInWords) {
long nextRl = RunningLengthWord.getRunningLength(this.buffer, nextRLWPos);
boolean nextRb = RunningLengthWord.getRunningBit(this.buffer, nextRLWPos);
return (nextRb || nextRl == 0);
}
return false;
}

private void setRLWInfo(int pos, boolean rb, long rl, long lw) {
RunningLengthWord.setRunningBit(this.buffer, pos, rb);
RunningLengthWord.setRunningLength(this.buffer, pos, rl);
RunningLengthWord.setNumberOfLiteralWords(this.buffer, pos, lw);
}

@Override
Expand Down
42 changes: 33 additions & 9 deletions src/main/java/com/googlecode/javaewah/RunningLengthWord.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ public final class RunningLengthWord implements Cloneable {
* @return the number of literal words
*/
public int getNumberOfLiteralWords() {
return (int) (this.parent.buffer[this.position] >>> (1 + RUNNING_LENGTH_BITS));
return getNumberOfLiteralWords(this.parent.buffer, this.position);
}

static int getNumberOfLiteralWords(final long[] buffer, final int position) {
return (int) (buffer[position] >>> (1 + RUNNING_LENGTH_BITS));
}

/**
Expand All @@ -40,7 +44,11 @@ public int getNumberOfLiteralWords() {
* @return the running bit
*/
public boolean getRunningBit() {
return (this.parent.buffer[this.position] & 1) != 0;
return getRunningBit(this.parent.buffer, this.position);
}

static boolean getRunningBit(final long[] buffer, final int position) {
return (buffer[position] & 1) != 0;
}

/**
Expand All @@ -49,7 +57,11 @@ public boolean getRunningBit() {
* @return the running length
*/
public long getRunningLength() {
return (this.parent.buffer[this.position] >>> 1) & LARGEST_RUNNING_LENGTH_COUNT;
return getRunningLength(this.parent.buffer, this.position);
}

static long getRunningLength(final long[] buffer, final int position) {
return (buffer[position] >>> 1) & LARGEST_RUNNING_LENGTH_COUNT;
}

/**
Expand All @@ -58,8 +70,12 @@ public long getRunningLength() {
* @param number the new number of literal words
*/
public void setNumberOfLiteralWords(final long number) {
this.parent.buffer[this.position] |= NOT_RUNNING_LENGTH_PLUS_RUNNING_BIT;
this.parent.buffer[this.position] &= (number << (RUNNING_LENGTH_BITS + 1))
setNumberOfLiteralWords(this.parent.buffer, this.position, number);
}

static void setNumberOfLiteralWords(final long[] buffer, final int position, final long number) {
buffer[position] |= NOT_RUNNING_LENGTH_PLUS_RUNNING_BIT;
buffer[position] &= (number << (RUNNING_LENGTH_BITS + 1))
| RUNNING_LENGTH_PLUS_RUNNING_BIT;
}

Expand All @@ -69,10 +85,14 @@ public void setNumberOfLiteralWords(final long number) {
* @param b the new running bit
*/
public void setRunningBit(final boolean b) {
setRunningBit(this.parent.buffer, this.position, b);
}

static void setRunningBit(final long[] buffer, final int position, final boolean b) {
if (b)
this.parent.buffer[this.position] |= 1l;
buffer[position] |= 1l;
else
this.parent.buffer[this.position] &= ~1l;
buffer[position] &= ~1l;
}

/**
Expand All @@ -81,8 +101,12 @@ public void setRunningBit(final boolean b) {
* @param number the new running length
*/
public void setRunningLength(final long number) {
this.parent.buffer[this.position] |= SHIFTED_LARGEST_RUNNING_LENGTH_COUNT;
this.parent.buffer[this.position] &= (number << 1)
setRunningLength(this.parent.buffer, this.position, number);
}

static void setRunningLength(final long[] buffer, final int position, final long number) {
buffer[position] |= SHIFTED_LARGEST_RUNNING_LENGTH_COUNT;
buffer[position] &= (number << 1)
| NOT_SHIFTED_LARGEST_RUNNING_LENGTH_COUNT;
}

Expand Down

0 comments on commit a6a5265

Please sign in to comment.