|
|
@ -28,8 +28,10 @@ |
|
|
package common; |
|
|
package common; |
|
|
|
|
|
|
|
|
import java.util.BitSet; |
|
|
import java.util.BitSet; |
|
|
import java.util.Iterator; |
|
|
|
|
|
import java.util.NoSuchElementException; |
|
|
import java.util.NoSuchElementException; |
|
|
|
|
|
import java.util.PrimitiveIterator.OfInt; |
|
|
|
|
|
|
|
|
|
|
|
import common.iterable.IterableInt; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Convenience class to loop easily over the set/clear bits of a BitSet. |
|
|
* Convenience class to loop easily over the set/clear bits of a BitSet. |
|
|
@ -37,10 +39,11 @@ import java.util.NoSuchElementException; |
|
|
* For example:<br/><br/> |
|
|
* For example:<br/><br/> |
|
|
* <code>for (Integer index : getSetBits(set)) { ... }</code><br/> |
|
|
* <code>for (Integer index : getSetBits(set)) { ... }</code><br/> |
|
|
*/ |
|
|
*/ |
|
|
public class IterableBitSet implements Iterable<Integer> |
|
|
|
|
|
|
|
|
public class IterableBitSet implements IterableInt |
|
|
{ |
|
|
{ |
|
|
private BitSet set; |
|
|
private BitSet set; |
|
|
private boolean clearBits = false; |
|
|
private boolean clearBits = false; |
|
|
|
|
|
private boolean reversed = false; |
|
|
private Integer maxIndex = null; |
|
|
private Integer maxIndex = null; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
@ -50,59 +53,127 @@ public class IterableBitSet implements Iterable<Integer> |
|
|
{ |
|
|
{ |
|
|
this.set = set; |
|
|
this.set = set; |
|
|
this.clearBits = false; |
|
|
this.clearBits = false; |
|
|
|
|
|
this.reversed = false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Constructor for an Iterable that iterates over bits of the given set {@code set}, |
|
|
|
|
|
* up to the maximal index given by {@code maxIndex} (optional). |
|
|
|
|
|
* If {@code clearBits} is {@code true}, iterate over the cleared bits instead of the set bits |
|
|
|
|
|
* (requires {@code maxIndex} to be non-null). |
|
|
|
|
|
* @param set the underlying BitSet |
|
|
|
|
|
* @param maxIndex the maximal index for iteration (negative = iterate over the empty set, {@code null} = no restrictions) |
|
|
|
|
|
* @param clearBits if true, iterate over the cleared bits in the BitSet |
|
|
|
|
|
*/ |
|
|
|
|
|
public IterableBitSet(BitSet set, Integer maxIndex, boolean clearBits) |
|
|
|
|
|
{ |
|
|
|
|
|
this(set, maxIndex, clearBits, false); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Constructor for an Iterable that iterates over bits of the given set {@code set}, |
|
|
* Constructor for an Iterable that iterates over bits of the given set {@code set}, |
|
|
* up to the maximal index given by {@code maxIndex}. If {@code clearBits} is {@code true}, |
|
|
|
|
|
* iterate over the cleared bits instead of the set bits. |
|
|
|
|
|
|
|
|
* up to the maximal index given by {@code maxIndex} (optional). |
|
|
|
|
|
* If {@code clearBits} is {@code true}, iterate over the cleared bits instead of the set bits |
|
|
|
|
|
* (requires {@code maxIndex} to be non-null). |
|
|
|
|
|
* If {@code reversed} is set, iterate in reverse order (highest to lowest). |
|
|
* @param set the underlying BitSet |
|
|
* @param set the underlying BitSet |
|
|
* @param maxIndex the maximal index for iteration (negative = iterate over the empty set) |
|
|
|
|
|
|
|
|
* @param maxIndex the maximal index for iteration (negative = iterate over the empty set, {@code null} = no restrictions) |
|
|
* @param clearBits if true, iterate over the cleared bits in the BitSet |
|
|
* @param clearBits if true, iterate over the cleared bits in the BitSet |
|
|
|
|
|
* @param reversed if true, iterate in reversed order |
|
|
*/ |
|
|
*/ |
|
|
public IterableBitSet(BitSet set, int maxIndex, boolean clearBits) |
|
|
|
|
|
|
|
|
public IterableBitSet(BitSet set, Integer maxIndex, boolean clearBits, boolean reversed) |
|
|
{ |
|
|
{ |
|
|
this.set = set; |
|
|
this.set = set; |
|
|
this.maxIndex = maxIndex; |
|
|
this.maxIndex = maxIndex; |
|
|
this.clearBits = clearBits; |
|
|
this.clearBits = clearBits; |
|
|
|
|
|
this.reversed = reversed; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** Implementation of the iterator over the set bits */ |
|
|
/** Implementation of the iterator over the set bits */ |
|
|
private class SetBitsIterator implements Iterator<Integer> { |
|
|
|
|
|
private int index = set.nextSetBit(0); |
|
|
|
|
|
|
|
|
private class SetBitsIterator implements OfInt |
|
|
|
|
|
{ |
|
|
|
|
|
private int current = -1; |
|
|
|
|
|
private int next = set.nextSetBit(0); |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public boolean hasNext() { |
|
|
|
|
|
if (maxIndex != null && index > maxIndex) { |
|
|
|
|
|
|
|
|
public boolean hasNext() |
|
|
|
|
|
{ |
|
|
|
|
|
if (maxIndex != null && next > maxIndex) { |
|
|
// limit to 0 ... maxIndex |
|
|
// limit to 0 ... maxIndex |
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
return index >= 0; |
|
|
|
|
|
|
|
|
return next >= 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public int nextInt() |
|
|
|
|
|
{ |
|
|
|
|
|
if (hasNext()) { |
|
|
|
|
|
current = next; |
|
|
|
|
|
next = set.nextSetBit(current + 1); |
|
|
|
|
|
return current; |
|
|
|
|
|
} |
|
|
|
|
|
throw new NoSuchElementException(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public void remove() |
|
|
|
|
|
{ |
|
|
|
|
|
set.clear(current); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Implementation of the iterator over the set bits (reverse order) */ |
|
|
|
|
|
private class SetBitsReversedIterator implements OfInt |
|
|
|
|
|
{ |
|
|
|
|
|
private int current = -1; |
|
|
|
|
|
private int next = set.nextSetBit(0); |
|
|
|
|
|
|
|
|
|
|
|
public SetBitsReversedIterator() |
|
|
|
|
|
{ |
|
|
|
|
|
current = -1; |
|
|
|
|
|
if (maxIndex != null) { |
|
|
|
|
|
// only consider set bits with index <= maxIndex |
|
|
|
|
|
next = set.previousSetBit(maxIndex); |
|
|
|
|
|
} else { |
|
|
|
|
|
next = set.length() - 1; // highest set bit |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public boolean hasNext() |
|
|
|
|
|
{ |
|
|
|
|
|
return next >= 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public Integer next() { |
|
|
|
|
|
|
|
|
public int nextInt() |
|
|
|
|
|
{ |
|
|
if (hasNext()) { |
|
|
if (hasNext()) { |
|
|
Integer next = index; |
|
|
|
|
|
index = set.nextSetBit(index + 1); |
|
|
|
|
|
return next; |
|
|
|
|
|
|
|
|
current = next; |
|
|
|
|
|
next = set.previousSetBit(current - 1); |
|
|
|
|
|
return current; |
|
|
} |
|
|
} |
|
|
throw new NoSuchElementException(); |
|
|
throw new NoSuchElementException(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public void remove() { |
|
|
|
|
|
throw new UnsupportedOperationException(); |
|
|
|
|
|
|
|
|
public void remove() |
|
|
|
|
|
{ |
|
|
|
|
|
set.clear(current); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** Implementation of the iterator over the cleared bits, requires that {@code maxIndex != null} */ |
|
|
/** Implementation of the iterator over the cleared bits, requires that {@code maxIndex != null} */ |
|
|
private class ClearBitsIterator implements Iterator<Integer> { |
|
|
|
|
|
private int index = set.nextClearBit(0); |
|
|
|
|
|
|
|
|
private class ClearBitsIterator implements OfInt |
|
|
|
|
|
{ |
|
|
|
|
|
private int current = -1; |
|
|
|
|
|
private int next = set.nextClearBit(0); |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public boolean hasNext() { |
|
|
|
|
|
if (index > maxIndex) { |
|
|
|
|
|
|
|
|
public boolean hasNext() |
|
|
|
|
|
{ |
|
|
|
|
|
if (next > maxIndex) { |
|
|
// limit to 0 ... maxIndex |
|
|
// limit to 0 ... maxIndex |
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
@ -110,27 +181,75 @@ public class IterableBitSet implements Iterable<Integer> |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public Integer next() { |
|
|
|
|
|
|
|
|
public int nextInt() |
|
|
|
|
|
{ |
|
|
if (hasNext()) { |
|
|
if (hasNext()) { |
|
|
Integer next = index; |
|
|
|
|
|
index = set.nextClearBit(index + 1); |
|
|
|
|
|
return next; |
|
|
|
|
|
|
|
|
current = next; |
|
|
|
|
|
next = set.nextClearBit(current + 1); |
|
|
|
|
|
return current; |
|
|
} |
|
|
} |
|
|
throw new NoSuchElementException(); |
|
|
throw new NoSuchElementException(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public void remove() { |
|
|
|
|
|
throw new UnsupportedOperationException(); |
|
|
|
|
|
|
|
|
public void remove() |
|
|
|
|
|
{ |
|
|
|
|
|
set.set(current); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Implementation of the iterator over the clear bits (reverse order), requires that {@code maxIndex != null} */ |
|
|
|
|
|
private class ClearBitsReversedIterator implements OfInt |
|
|
|
|
|
{ |
|
|
|
|
|
private int current = -1; |
|
|
|
|
|
private int next = set.nextSetBit(0); |
|
|
|
|
|
|
|
|
|
|
|
public ClearBitsReversedIterator() |
|
|
|
|
|
{ |
|
|
|
|
|
current = -1; |
|
|
|
|
|
// only consider clear bits with index <= maxIndex |
|
|
|
|
|
next = set.previousClearBit(maxIndex); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public boolean hasNext() |
|
|
|
|
|
{ |
|
|
|
|
|
return next >= 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public int nextInt() |
|
|
|
|
|
{ |
|
|
|
|
|
if (hasNext()) { |
|
|
|
|
|
current = next; |
|
|
|
|
|
next = set.previousClearBit(current - 1); |
|
|
|
|
|
return current; |
|
|
|
|
|
} |
|
|
|
|
|
throw new NoSuchElementException(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public void remove() |
|
|
|
|
|
{ |
|
|
|
|
|
set.clear(current); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public Iterator<Integer> iterator() { |
|
|
|
|
|
|
|
|
public OfInt iterator() |
|
|
|
|
|
{ |
|
|
if (clearBits == false) { |
|
|
if (clearBits == false) { |
|
|
return new SetBitsIterator(); |
|
|
|
|
|
|
|
|
if (reversed) { |
|
|
|
|
|
return new SetBitsReversedIterator(); |
|
|
|
|
|
} else { |
|
|
|
|
|
return new SetBitsIterator(); |
|
|
|
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
return new ClearBitsIterator(); |
|
|
|
|
|
|
|
|
if (reversed) { |
|
|
|
|
|
return new ClearBitsReversedIterator(); |
|
|
|
|
|
} else { |
|
|
|
|
|
return new ClearBitsIterator(); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -144,6 +263,17 @@ public class IterableBitSet implements Iterable<Integer> |
|
|
return new IterableBitSet(set); |
|
|
return new IterableBitSet(set); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Get an IterableBitSet that iterates over the bits of {@code set} that are set, |
|
|
|
|
|
* in reverse order (highest to lowest index). |
|
|
|
|
|
* @param set a BitSet |
|
|
|
|
|
* @return an IterableBitSet over the set bits |
|
|
|
|
|
*/ |
|
|
|
|
|
public static IterableBitSet getSetBitsReversed(BitSet set) |
|
|
|
|
|
{ |
|
|
|
|
|
return new IterableBitSet(set, null, false, true); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Get an IterableBitSet that iterates over the cleared bits of {@code set}, up to {@code maxIndex} |
|
|
* Get an IterableBitSet that iterates over the cleared bits of {@code set}, up to {@code maxIndex} |
|
|
* @param set a BitSet |
|
|
* @param set a BitSet |
|
|
@ -155,6 +285,17 @@ public class IterableBitSet implements Iterable<Integer> |
|
|
return new IterableBitSet(set, maxIndex, true); |
|
|
return new IterableBitSet(set, maxIndex, true); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Get an IterableBitSet that iterates over the cleared bits of {@code set}, up to {@code maxIndex}, |
|
|
|
|
|
* in reverse order (highest to lowest index). |
|
|
|
|
|
* @param set a BitSet |
|
|
|
|
|
* @return an IterableBitSet over the set bits |
|
|
|
|
|
*/ |
|
|
|
|
|
public static IterableBitSet getClearBitsReversed(BitSet set, int maxIndex) |
|
|
|
|
|
{ |
|
|
|
|
|
return new IterableBitSet(set, maxIndex, true, true); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Simple test method. |
|
|
* Simple test method. |
|
|
* |
|
|
* |
|
|
@ -177,7 +318,8 @@ public class IterableBitSet implements Iterable<Integer> |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
test.clear(); |
|
|
test.clear(); |
|
|
for (@SuppressWarnings("unused") Integer index : getSetBits(test)) { |
|
|
|
|
|
|
|
|
for (@SuppressWarnings("unused") |
|
|
|
|
|
Integer index : getSetBits(test)) { |
|
|
throw new RuntimeException("BitSet should be empty!"); |
|
|
throw new RuntimeException("BitSet should be empty!"); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|