com.google.uzaygezen.core.BitSetBackedBitVector.java Source code

Java tutorial

Introduction

Here is the source code for com.google.uzaygezen.core.BitSetBackedBitVector.java

Source

/*
 * Copyright (C) 2008 Google 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.google.uzaygezen.core;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.BitSet;

import org.apache.commons.lang3.ArrayUtils;

import com.google.common.base.Preconditions;

/**
 * Adapts {@link java.util.BitSet} to the {@link BitVector} abstraction.
 * 
 * @author Mehmet Akin
 * @author Daniel Aioanei
 */
public final class BitSetBackedBitVector implements BitVector, Cloneable {

    private final BitSet bitset;
    private final int size;

    public BitSetBackedBitVector(int nbits) {
        this(nbits, new BitSet(nbits));
    }

    /**
     * Unsafe constructor. Keep it private.
     */
    private BitSetBackedBitVector(int size, BitSet bitset) {
        this.size = size;
        this.bitset = bitset;
    }

    private void checkSize(BitVector other) {
        if (other.size() != this.size()) {
            throw new IllegalArgumentException("Sizes are not equal. " + "this:" + size + " other:" + other.size());
        }
    }

    private void checkIndex(int bitIndex) {
        if (bitIndex < 0 | bitIndex >= size) {
            throw new IndexOutOfBoundsException("BitIndex should be smaller than size : " + bitIndex);
        }
    }

    @Override
    public void and(BitVector o) {
        checkSize(o);
        bitset.and(toPotentiallySharedBitSet(o));
    }

    @Override
    public void andNot(BitVector o) {
        checkSize(o);
        bitset.andNot(toPotentiallySharedBitSet(o));
    }

    @Override
    public int cardinality() {
        return bitset.cardinality();
    }

    @Override
    public void clear() {
        bitset.clear();
    }

    @Override
    public void clear(int bitIndex) {
        checkIndex(bitIndex);
        bitset.clear(bitIndex);
    }

    @Override
    public void clear(int fromIndex, int toIndex) {
        bitset.clear(fromIndex, toIndex);
    }

    @Override
    public void copyFrom(BitVector from) {
        if (from.size() <= 64) {
            copyFrom(from.toExactLong());
        } else {
            bitset.clear();
            bitset.or(toPotentiallySharedBitSet(from));
        }
    }

    @Override
    public void flip(int bitIndex) {
        checkIndex(bitIndex);
        bitset.flip(bitIndex);
    }

    @Override
    public void flip(int fromIndex, int toIndex) {
        bitset.flip(fromIndex, toIndex);
    }

    @Override
    public boolean get(int bitIndex) {
        checkIndex(bitIndex);
        return bitset.get(bitIndex);
    }

    @Override
    public void grayCode() {
        BitSetMath.grayCode(bitset);
    }

    @Override
    public void grayCodeInverse() {
        BitSetMath.grayCodeInverse(bitset);
    }

    @Override
    public boolean increment() {
        int tsb = bitset.nextClearBit(0);
        if (tsb == size) {
            return false;
        }
        bitset.set(tsb);
        bitset.clear(0, tsb);
        return true;
    }

    @Override
    public boolean intersects(BitVector o) {
        checkSize(o);
        return bitset.intersects(toPotentiallySharedBitSet(o));
    }

    @Override
    public int length() {
        return bitset.length();
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public int nextClearBit(int fromIndex) {
        Preconditions.checkArgument(fromIndex >= 0);
        int ncb = bitset.nextClearBit(fromIndex);
        if (ncb >= size) {
            ncb = -1;
        }
        assert -1 <= ncb & ncb < size;
        return ncb;
    }

    @Override
    public int nextSetBit(int fromIndex) {
        return bitset.nextSetBit(fromIndex);
    }

    @Override
    public void or(BitVector o) {
        checkSize(o);
        bitset.or(toPotentiallySharedBitSet(o));
    }

    @Override
    public void rotate(int count) {
        BitSetMath.rotate(bitset, size, count);
    }

    @Override
    public void set(int bitIndex) {
        checkIndex(bitIndex);
        bitset.set(bitIndex);
    }

    @Override
    public void set(int bitIndex, boolean value) {
        bitset.set(bitIndex, value);
    }

    @Override
    public void set(int fromIndex, int toIndex) {
        bitset.set(fromIndex, toIndex);
    }

    @Override
    public void set(int fromIndex, int toIndex, boolean value) {
        bitset.set(fromIndex, toIndex, value);
    }

    @Override
    public void xor(BitVector o) {
        checkSize(o);
        bitset.xor(toPotentiallySharedBitSet(o));
    }

    public BitSet getBitset() {
        return bitset;
    }

    @Override
    public boolean isEmpty() {
        return bitset.isEmpty();
    }

    @Override
    public BitSetBackedBitVector clone() {
        return new BitSetBackedBitVector(size, (BitSet) bitset.clone());
    }

    @Override
    public int hashCode() {
        return size + 31 * bitset.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof BitSetBackedBitVector) {
            BitSetBackedBitVector other = (BitSetBackedBitVector) obj;
            return size == other.size && bitset.equals(other.bitset);
        }
        if (obj instanceof BitVector) {
            BitVector other = (BitVector) obj;
            // optimisation
            if (size <= 64) {
                return size == other.size() && toExactLong() == other.toExactLong();
            } else {
                return size == other.size() && bitset.equals(other.toBitSet());
            }
        } else {
            return false;
        }
    }

    @Override
    public BitSet toBitSet() {
        return (BitSet) bitset.clone();
    }

    @Override
    public String toString() {
        return "size: " + size + " bitset: " + bitset;
    }

    @Override
    public long toLong() {
        long value = 0;
        for (int i = bitset.nextSetBit(0); i != -1 & i < 64; i = bitset.nextSetBit(i + 1)) {
            assert i < size;
            value |= 1L << i;
        }
        return value;
    }

    public void copyFrom(long value) {
        int bitLength = 64 - Long.numberOfLeadingZeros(value);
        Preconditions.checkArgument(bitLength <= size, "value doesn't fit");
        bitset.clear();
        int lowestSetBit = Long.numberOfTrailingZeros(value);
        for (int i = lowestSetBit; i < bitLength; ++i) {
            if ((value & 1L << i) != 0) {
                bitset.set(i);
            }
        }
    }

    @Override
    public int compareTo(BitVector o) {
        checkSize(o);
        return BitSetComparator.INSTANCE.compare(bitset, toPotentiallySharedBitSet(o));
    }

    @Override
    public void copyFrom(BitSet from) {
        Preconditions.checkArgument(from.length() <= size, "bit set is too large");
        bitset.clear();
        bitset.or(from);
    }

    @Override
    public void copyFromSection(BitVector src, int fromIndex) {
        Preconditions.checkArgument(fromIndex >= 0, "fromIndex must be non-negative");
        int srcSize = src.size();
        int toIndex = fromIndex + size;
        Preconditions.checkArgument(toIndex <= srcSize, "not enough bits in src");
        bitset.clear();
        for (int i = src.nextSetBit(fromIndex); i < toIndex && i != -1; i = src.nextSetBit(i + 1)) {
            bitset.set(i - fromIndex);
        }
    }

    @Override
    public long toExactLong() {
        long value = 0;
        for (int i = bitset.nextSetBit(0); i != -1; i = bitset.nextSetBit(i + 1)) {
            assert i < size;
            Preconditions.checkState(i < 64, "does not fit in long");
            value |= 1L << i;
        }
        return value;
    }

    private static BitSet toPotentiallySharedBitSet(BitVector bv) {
        if (bv instanceof BitSetBackedBitVector) {
            return ((BitSetBackedBitVector) bv).bitset;
        } else {
            return bv.toBitSet();
        }
    }

    @Override
    public void smallerEvenAndGrayCode() {
        if (bitset.get(0)) {
            bitset.clear(0);
            grayCode();
        } else {
            // Could use zero as well as the starting point.
            int firstSetIndex = bitset.nextSetBit(1);
            if (firstSetIndex != -1) {
                // Subtract 2 from this positive even number.
                bitset.clear(firstSetIndex);
                bitset.set(1, firstSetIndex, true);
                assert !bitset.get(0);
                grayCode();
            }
        }
    }

    @Override
    public void grayCodeRank(BitVector mu, BitVector w) {
        Preconditions.checkArgument(size() == mu.cardinality(), "r has the wrong size");
        Preconditions.checkArgument(mu.size() == w.size(), "mu/w size mismatch");
        clear();
        int pos = 0;
        for (int j = mu.size() == 0 ? -1 : mu.nextSetBit(0); j != -1; j = j == mu.size() - 1 ? -1
                : mu.nextSetBit(j + 1)) {
            if (w.get(j)) {
                bitset.set(pos);
            }
            ++pos;
        }
    }

    @Override
    public int lowestDifferentBit() {
        final int value;
        if (bitset.isEmpty()) {
            value = 0;
        } else {
            if (bitset.get(0)) {
                int tsb = bitset.nextClearBit(0);
                assert tsb <= size : "bitset=" + bitset;
                value = tsb == size ? 0 : tsb;
            } else {
                int tcb = bitset.nextSetBit(0);
                assert 0 < tcb & tcb < size;
                value = tcb;
            }
        }
        assert value == 0 || (0 < value & value < size);
        return value;
    }

    @Override
    public void grayCodeRankInverse(BitVector mu, BitVector known, BitVector r) {
        Preconditions.checkArgument(r.size() == mu.cardinality(), "r.size()/mu.cardinality() mismatch");
        int muSize = mu.size();
        Preconditions.checkArgument(size == muSize, "i/mu size mismatch");
        // Will fail if the sizes are different.
        Preconditions.checkArgument(!known.intersects(mu), "known and mu must not intersect");
        bitset.clear();
        int pos = 0;
        int highestFreeBitIndex = -1;
        for (int k = muSize == 0 ? -1 : mu.nextSetBit(0); k != -1; k = k == muSize - 1 ? -1
                : mu.nextSetBit(k + 1)) {
            highestFreeBitIndex = k;
            if (r.get(pos)) {
                bitset.set(k);
            }
            ++pos;
        }
        // TODO: Use previousClearBit in Java 7.
        for (int k = Math.max(highestFreeBitIndex, known.length()); --k >= 0;) {
            if (!mu.get(k)) {
                assert !bitset.get(k);
                if (known.get(k) ^ bitset.get(k + 1)) {
                    bitset.set(k);
                }
            }
        }
    }

    @Override
    public void copySectionFrom(int offset, BitVector src) {
        int srcSize = src.size();
        int toIndex = offset + srcSize;
        if (offset < 0 | toIndex > size) {
            throw new IndexOutOfBoundsException("invalid range: offset=" + offset + " src.size()=" + src.size());
        }
        bitset.clear(offset, toIndex);
        for (int j = srcSize == 0 ? -1 : src.nextSetBit(0); j != -1; j = j == srcSize - 1 ? -1
                : src.nextSetBit(j + 1)) {
            bitset.set(offset + j);
        }
    }

    @Override
    public long[] toLongArray() {
        long[] array = bitset.toLongArray();
        // Pad it to correct length.
        int n = (size + 63) >>> 6;
        if (array.length < n) {
            return Arrays.copyOf(array, n);
        } else {
            assert array.length == n;
        }
        return array;
    }

    @Override
    public byte[] toBigEndianByteArray() {
        int n = MathUtils.bitCountToByteCount(size);
        byte[] littleEndian = bitset.toByteArray();
        assert n >= littleEndian.length;
        byte[] a = Arrays.copyOf(littleEndian, n);
        ArrayUtils.reverse(a);
        return a;
    }

    @Override
    public BigInteger toBigInteger() {
        return new BigInteger(isEmpty() ? 0 : 1, toBigEndianByteArray());
    }

    @Override
    public void copyFrom(long[] array) {
        int len = (size + 63) >>> 6;
        Preconditions.checkArgument(array.length == len, "Length must be %s.", len);
        if (size == 0) {
            return;
        }
        Preconditions.checkArgument(Long.numberOfLeadingZeros(array[len - 1]) >= (len << 6) - size,
                "Some bit positions are too high.");
        BitSet bs = BitSet.valueOf(array);
        bitset.clear();
        bitset.or(bs);
    }

    @Override
    public void copyFromBigEndian(byte[] array) {
        int len = MathUtils.bitCountToByteCount(size);
        Preconditions.checkArgument(array.length == len, "Length must be %s.", len);
        if (len == 0) {
            return;
        }
        Preconditions.checkArgument(MathUtils.numberOfLeadingZeros(array[0]) >= (len << 3) - size,
                "Some bit positions are too high.");
        BitSet bs;
        ArrayUtils.reverse(array);
        try {
            bs = BitSet.valueOf(array);
        } finally {
            ArrayUtils.reverse(array);
        }
        bitset.clear();
        bitset.or(bs);
    }

    @Override
    public boolean areAllLowestBitsClear(int bitCount) {
        Preconditions.checkArgument(0 <= bitCount & bitCount <= size, "bitCount is out of range");
        int firstSetBit = bitset.nextSetBit(0);
        return firstSetBit == -1 | firstSetBit >= bitCount;
    }

    @Override
    public void copyFrom(BigInteger s) {
        byte[] array = BigIntegerMath.nonnegativeBigIntegerToBigEndianByteArrayForBitSize(s, size);
        copyFromBigEndian(array);
    }
}