/*
* Copyright (C) 2014 Indeed Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.indeed.imhotep;
import org.apache.log4j.Logger;
/**
* @author jplaisance
*/
public final class BitTree {
private static final Logger log = Logger.getLogger(BitTree.class);
final long[][] bitsets;
boolean cleared = true;
int iteratorIndex;
int depth;
int current;
public BitTree(int size) {
bitsets = new long[log2(size-1)/6+1][];
for (int i = 0; i < bitsets.length; i++) {
size = (size+63)/64;
bitsets[i] = new long[size];
}
depth = bitsets.length-1;
}
private static int log2(final int size) {
return 31-Integer.numberOfLeadingZeros(size);
}
public void set(int index) {
if (!cleared) throw new IllegalStateException();
for (int i = 0; i < bitsets.length; i++) {
final int nextIndex = index>>>6;
bitsets[i][nextIndex] |= 1L<<(index&0x3F);
index = nextIndex;
}
}
public void set(int[] indexes, int n) {
if (!cleared) throw new IllegalStateException();
for (int j = 0; j < n; j++) {
int index = indexes[j];
for (int i = 0; i < bitsets.length; i++) {
final int nextIndex = index>>>6;
bitsets[i][nextIndex] |= 1L<<(index&0x3F);
index = nextIndex;
}
}
}
public boolean get(int index) {
return (bitsets[0][index>>6]&(1L<<(index&0x3F))) != 0;
}
public void clear() {
cleared = true;
while (true) {
while (bitsets[depth][iteratorIndex] == 0) {
if (depth == bitsets.length-1) {
return;
}
depth++;
iteratorIndex >>>= 6;
}
while (depth != 0) {
final long lsb = bitsets[depth][iteratorIndex] & -bitsets[depth][iteratorIndex];
bitsets[depth][iteratorIndex] ^= lsb;
depth--;
iteratorIndex = (iteratorIndex <<6)+Long.bitCount(lsb-1);
}
bitsets[0][iteratorIndex] = 0;
depth = 1;
iteratorIndex >>>= 6;
}
}
public boolean next() {
cleared = false;
long bits = bitsets[depth][iteratorIndex];
while (bits == 0) {
if (depth == bitsets.length-1) {
return false;
}
depth++;
iteratorIndex >>>= 6;
bits = bitsets[depth][iteratorIndex];
}
while (depth != 0) {
final long lsb = bits & -bits;
bitsets[depth][iteratorIndex] ^= lsb;
depth--;
iteratorIndex = (iteratorIndex <<6)+Long.bitCount(lsb-1);
bits = bitsets[depth][iteratorIndex];
}
final long lsb = bits & -bits;
bitsets[0][iteratorIndex] ^= lsb;
current = (iteratorIndex <<6)+Long.bitCount(lsb-1);
return true;
}
public int getValue() {
return current;
}
public int dump(int[] buffer) {
int count = 0;
int depth = bitsets.length-1;
int index = 0;
cleared = true;
while (true) {
while (bitsets[depth][index] == 0) {
if (depth == bitsets.length-1) {
return count;
}
depth++;
index >>>= 6;
}
while (depth != 0) {
final long lsb = bitsets[depth][index] & -bitsets[depth][index];
bitsets[depth][index] ^= lsb;
depth--;
index = (index<<6)+Long.bitCount(lsb-1);
}
while (bitsets[0][index] != 0) {
final long lsb = bitsets[0][index] & -bitsets[0][index];
bitsets[0][index] ^= lsb;
buffer[count++] = (index<<6)+Long.bitCount(lsb-1);
}
if (bitsets.length == 1) return count;
depth = 1;
index >>>= 6;
}
}
}