package org.basex.util; import static java.lang.Long.*; import java.util.BitSet; /** * Bit array that grows when needed. The implementation is similar to * {@link BitSet}. * * @author BaseX Team 2005-12, BSD License * @author Dimitar Popov */ public final class BitArray { /** Number of bits needed to address a bit in a word; 2<sup>6</sup> = 64. */ private static final int WORD_POWER = 6; /** Size of a word = 2<sup>{@link #WORD_POWER}</sup>. */ private static final int WORD_SIZE = 1 << WORD_POWER; /** A bit mask of 64 bits set to 1. */ private static final long WORD_MASK = -1L; /** Bit storage. */ private long[] words; /** Number of used bits. */ private long length; /** Construct a new bit array. */ public BitArray() { this(WORD_SIZE); } /** * Construct a new bit array with the specified number of bits. * @param n initial number of bits (> 0) */ public BitArray(final int n) { init(n); } /** * Construct a new bit array with the specified backing array. * @param a array with bits * @param l number of used bits */ public BitArray(final long[] a, final long l) { setWords(a, l); } /** Initialize the bit array with an empty array. */ public void init() { setWords(new long[1], 0); } /** * Initialize the bit array with a new size. All bits will be set to 0. * @param n initial number of bits (> 0) */ void init(final int n) { setWords(new long[(Math.max(0, n - 1) >>> WORD_POWER) + 1], n); } /** * Initialize the bit array with the specified backing array. * @param a array with bits * @param l number of used bits */ public void setWords(final long[] a, final long l) { words = a; length = l; } /** * The word array used to store the bits. The array is shrunk to the last * word, where a bit is set. * @return array of longs */ public long[] toArray() { // find the last index of a word which is different from 0: int i = words.length; while(--i >= 0 && words[i] == 0); final long[] result = new long[++i]; System.arraycopy(words, 0, result, 0, i); return result; } /** * Get the value of the i<sup>th</sup> bit. * @param i index of the bit * @return <code>true</code> if the i<sup>th</sup> bit is set */ public boolean get(final int i) { if(i >= length) return false; // calculate the index of the word in the array: i div 2^6 = i >> 6 final int wordIndex = i >>> WORD_POWER; // check if the ith bit is 1 return (words[wordIndex] & 1L << i) != 0; } /** * Set the i<sup>th</sup> bit to 1. * @param i index of the bit */ public void set(final int i) { // calculate the index of the word in the array: i div 2^6 = i >> 6 final int wordIndex = i >>> WORD_POWER; if(wordIndex >= words.length) expandTo(wordIndex + 1); words[wordIndex] |= 1L << i; if(i >= length) length = i + 1L; } /** * Set the i<sup>th</sup> bit to 0. * @param i index of the bit */ public void clear(final int i) { // calculate the index of the word in the array: i div 2^6 = i >> 6 final int wordIndex = i >>> WORD_POWER; if(wordIndex >= words.length) expandTo(wordIndex + 1); words[wordIndex] &= ~(1L << i); // it is not necessary to set the last used bit } /** * Get the next bit set to 0, starting from the i<sup>th</sup> bit. * @param i index from which to start the search (inclusive) * @return index of the next clear bit after the i<sup>th</sup> bit */ public int nextClearBit(final int i) { // calculate the index of the word in the array: i div 2^6 = i >> 6 int wordIndex = i >>> WORD_POWER; // invert the word and skip the first i bits: long word = ~words[wordIndex] & WORD_MASK << i; if(word != 0) { return (wordIndex << WORD_POWER) + numberOfTrailingZeros(word); } while(++wordIndex < words.length) { if((word = ~words[wordIndex]) != 0) { return (wordIndex << WORD_POWER) + numberOfTrailingZeros(word); } } // wordIndex * 2^6: return wordIndex << WORD_POWER; } /** * Expand the {@link #words} array to the desired size. * @param s new size */ private void expandTo(final int s) { final long[] newWords = new long[Math.max(words.length << 1, s)]; System.arraycopy(words, 0, newWords, 0, words.length); words = newWords; } }