/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: BitVector.java
 * Written by Eric Kim and JTom O'Neill.
 *
 * Copyright (c) 2005, Static Free Software. All rights reserved.
 *
 * Electric(tm) is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Electric(tm) is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.sun.electric.tool.simulation.test;

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

/**
 * Provides a fixed-length bit vector and methods for acting on it. Developed to
 * represent scan chain state variables.
 * <p>
 * Bits can be in the <tt>invalid</tt>, &nbsp; <tt>true</tt>, or
 * <tt>false</tt> state. The string representations for these values are "
 * <tt>-</tt>", "<tt>1</tt>", and "<tt>0</tt>", respectively. To help
 * catch bugs, bits are <tt>invalid</tt> (i.e., undefined or unknown) until
 * they have been explicitly set and <code>BitVector</code> methods crash if
 * you attempt to read an <tt>invalid</tt> bit. Here are some examples to
 * indicate how BitVector values are represented and used:
 * <p>
 * <TABLE border="1">
 * <TR>
 * <TH ROWSPAN=2>Bit representation
 * <TH COLSPAN=3>BitVector example
 * <TR>
 * <TH>example 1
 * <TH>example 2
 * <TH>example 3
 * <TR>
 * <TH>String
 * <TD>011
 * <TD>1-01
 * <TD>1000000000
 * <TR>
 * <TH>BigInteger
 * <TD>3
 * <TD>undefined
 * <TD>512
 * <TR>
 * <TH>"LittleInteger"
 * <TD>6
 * <TD>undefined
 * <TD>1
 * <TR>
 * <TH>BitVector state at index 0,1,2,...
 * <TD>false,true,true
 * <TD>true,invalid,false,true
 * <TD>true,false,false,...
 * <TR>
 * <TH>bits scanned into scan chain
 * <TD>1,1,0
 * <TD>undefined
 * <TD>0,0,0,0,0,0,0,0,0,1
 * <TR>
 * <TH>chain element states along s_in
 * <TD>0,1,1
 * <TD>undefined
 * <TD>1,0,0,0,0,0,0,0,0,0 </TABLE>
 * <p>
 * Bit zero is the LAST bit scanned into the scan chain. Thus the bit index
 * matches the position of the corresponding scan chain element along the s_in
 * chain. <code>BitVector</code> uses the big endian bit order convention for
 * the String representation. Strings should be read from left to right,
 * starting at bit zero. Thus the strings match the order in which scan chain
 * elements appear in most schematics. The MSB of a <code>BigInteger</code> or
 * <code>int</code> is stored in bit 0 of the <code>BitVector</code>. That
 * is, the bit order is opposite to that of the integer.
 * <p>
 * Key differences from <code>BitSet</code>: 1) addition of the <tt>invalid
 * </tt>
 * state; 2) the bit vector is fixed length; 3) ranges are specified by
 * (startIndex, numBits) rather than (startIndex, endIndex); 4) different
 * toString() method; addition of BigInteger I/O methods.
 * <p>
 */

public class BitVector {

    /** Number of bits in the bit vector */
    final private int numBits;

    /** Bit vector */
    private BitSet bitSet;

    /** Whether state of each bit is accurately known */
    private BitSet valid;

    /** Identifying name of bit vector, for errors etc. */
    private String name;

    /**
     * Severity of action when an unnamed BitVector is created. Default is
     * {@link Infrastructure#SEVERITY_WARNING}
     */
    public static int noNameSeverity = Infrastructure.SEVERITY_WARNING;

    /**
     * Main constructor creates a vector of <code>numBits</code> bits, set to
     * the <tt>invalid</tt> state.
     * 
     * @param numBits
     *            number of bits in the vector
     * @param name
     *            identifying name of the bit vector, e.g. for errors
     */
    public BitVector(int numBits, String name) {
        if (numBits < 0) {
            Infrastructure.fatal("Bad BitVector length " + numBits
                    + ", must be non-negative");
        }
        this.numBits = numBits;
        this.bitSet = new BitSet(numBits);
        this.valid = new BitSet(numBits);
        this.name = name;
    }

    /**
     * Convenience constructor creates a bit vector from the input string. The
     * length of the string is used for the length of the bit vector.
     * 
     * @param bitString
     *            bit sequence to initialize vector to
     * @param name
     *            identifying name of the bit vector, e.g. for errors
     */
    public BitVector(String bitString, String name) {
        this(bitString.length(), name);
        this.put(0, bitString);
    }
    /**
     * Convenience constructor copies contents of existing BitVector
     * 
     *  @param b BitVector to copy
     */
    public BitVector(BitVector b) {
    	this(b.getState(), b.getName());
    }

    /**
     * Convenience constructor creates a bit vector from the input string. The
     * length of the string is used for the length of the bit vector.
     *
     * @param bitArray
     *            bit sequence to initialize vector to
     * @param name
     *            identifying name of the bit vector, e.g. for errors
     */
    public BitVector(int[] bitArray, String name) {
        this(bitArray.length, name);
        this.put(0, bitArray);
    }

    /**
     * Returns number of bits in the bit vector
     * 
     * @return Number of bits in the bit vector
     */
    public int getNumBits() {
        return numBits;
    }

    /**
     * Returns the name of the bit vector.
     * 
     * @return Returns the name of the bit vector.
     */
    public String getName() {
        return name;
    }

    /**
     * Set the name of the bit vector.
     * 
     * @param name
     *            The name to set.
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Returns a string representation of the entire bit sequence, starting with
     * the lowest-index bit.
     * 
     * @return string representation of bit sequence
     */
    public String getState() {
        StringBuffer buf = new StringBuffer(numBits);
        for (int ind = 0; ind < numBits; ind++) {
            if (this.valid.get(ind) == false) {
                buf.append("-");
            } else if (this.get(ind)) {
                buf.append("1");
            } else {
                buf.append("0");
            }
        }
        return buf.toString();
    }

    /**
     * Returns the name and the bit vector and a string representing the entire
     * bit sequence, starting with the lowest-index bit.
     * 
     * @return string representation of bit sequence
     */
    public String toString() {
        return getName() + ": " + getState();
    }

    /**
     * Returns a <code>BigInteger</code> representation of the entire bit
     * vector, with bit 0 in the MSB.
     * 
     * @return <code>BigInteger</code> representation of bit sequence
     */
    public BigInteger toBigInteger() {
        checkRange(0, numBits, true);
        BigInteger out = BigInteger.ZERO;

        for (int ind = 0; ind < numBits; ind++) {
            if (this.get(ind) == true) {
                out = out.or(BigInteger.ONE.shiftLeft(numBits - ind - 1));
            }
        }

        return out;
    }

    /**
     * Returns a <code>BigInteger</code> representation of the entire bit
     * vector, with bit 0 in the LSB. Compare to toBigInteger().
     * 
     * @return <code>BigInteger</code> representation of bit sequence
     * @see #toBigInteger
     */
    public BigInteger toLittleInteger() {
        checkRange(0, numBits, true);
        BigInteger out = BigInteger.ZERO;

        for (int ind = 0; ind < numBits; ind++) {
            if (this.get(ind) == true) {
                out = out.or(BigInteger.ONE.shiftLeft(ind));
            }
        }

        return out;
    }

    /**
     * Returns an <code>int</code> array representation of the entire bit
     * vector. Values in the array are either 0, 1, or -1 for false, true, and
     * undefined, respectively.
     * @return an integer array representation of the bit vector.
     */
    public int[] toIntArray() {
        int [] array = new int[numBits];
        for (int ind = 0; ind < numBits; ind++) {
            if (this.valid.get(ind) == false) {
                array[ind] = -1;
            } else if (this.get(ind)) {
                array[ind] = 1;
            } else {
                array[ind] = 0;
            }
        }
        return array;
    }

    /**
     * Returns <tt>true</tt> if specified bit has a known state.
     * 
     * @param bitIndex
     *            index of bit to be checked
     * @return whether bit has known state
     */
    public boolean isValid(int bitIndex) {
        checkIndex(bitIndex, false);
        return valid.get(bitIndex);
    }

    /**
     * Sets the bit specified by the index to the <tt>invalid</tt> state.
     * 
     * @param bitIndex
     *            the index of the bit to be invalidated
     */
    public void invalidate(int bitIndex) {
        checkIndex(bitIndex, false);
        valid.clear(bitIndex);
    }

    /**
     * Sets the entire bit vector to the <tt>invalid</tt> state.
     */
    public void invalidate() {
        for (int ind = 0; ind < numBits; ind++) {
            invalidate(ind);
        }
    }

    /**
     * Returns the value of the bit with the specified index. The value is
     * <tt>true</tt> if the bit with the index <code>bitIndex</code> is
     * currently set in this <code>BitVector</code>; otherwise, the result is
     * <tt>false</tt>.
     * 
     * @param bitIndex
     *            the bit index
     * @return the value of the bit with the specified index
     */
    public boolean get(int bitIndex) {
        checkIndex(bitIndex, true);
        return bitSet.get(bitIndex);
    }

    /**
     * Sets the bit at the specified index to to the complement of its current
     * value.
     * 
     * @param bitIndex
     *            the index of the bit to flip
     */
    public void flip(int bitIndex) {
        checkIndex(bitIndex, true);
        bitSet.flip(bitIndex);
    }

    /**
     * Sets the bits in the specified index range to to the complements of their
     * current values.
     * 
     * @param fromIndex
     *            the starting index of the bits to flip
     * @param nbits
     *            the number of bits to flip
     */
    public void flip(int fromIndex, int nbits) {
        checkRange(fromIndex, nbits, true);
        for (int bitIndex = fromIndex; bitIndex < fromIndex + nbits; bitIndex++) {
            this.flip(bitIndex);
        }
    }

    /**
     * Sets the bit specified by the index to <tt>false</tt>.
     * 
     * @param bitIndex
     *            the index of the bit to be cleared
     */
    public void clear(int bitIndex) {
        checkIndex(bitIndex, false);
        bitSet.clear(bitIndex);
        valid.set(bitIndex);
    }

    /**
     * Sets the bit at the specified index to <tt>true</tt>.
     * 
     * @param bitIndex
     *            a bit index
     */
    public void set(int bitIndex) {
        checkIndex(bitIndex, false);
        bitSet.set(bitIndex);
        valid.set(bitIndex);
    }

    /**
     * Sets the bit at the specified index to the specified value.
     * 
     * @param bitIndex
     *            a bit index.
     * @param value
     *            a boolean value to set
     */
    public void set(int bitIndex, boolean value) {
        checkIndex(bitIndex, false);
        bitSet.set(bitIndex, value);
        valid.set(bitIndex);
    }

    /**
     * Sets the <code>nbits</code> bits starting at <code>fromIndex</code>
     * (inclusive) to the specified value.
     * 
     * @param fromIndex
     *            index of the first bit to be set
     * @param nbits
     *            number of bits to set
     * @param value
     *            value to set the selected bits to
     */
    public void set(int fromIndex, int nbits, boolean value) {
        checkRange(fromIndex, nbits, false);
        bitSet.set(fromIndex, fromIndex + nbits, value);
        valid.set(fromIndex, fromIndex + nbits);
    }

    /**
     * Returns a new <code>BitVector</code> composed of a subset of
     * <code>numBits</code> bits from this <code>BitVector</code>. Range is
     * from <code>fromIndex</code> (inclusive) to
     * <code>(toIndex + nbits)</code> (exclusive). Note this interface is
     * different from that of <code>BitSet.get()</code>. The range is not
     * allowed to include any invalid bits.
     * 
     * @param fromIndex
     *            index of the first bit to include
     * @param nbits
     *            number of bits to include
     * @return a new BitSet from a range of this BitVector
     */
    public BitVector get(int fromIndex, int nbits) {
        checkRange(fromIndex, nbits, true);
        return getIndiscriminate(fromIndex, nbits);
    }

    /**
     * Like {@link #get(int, int)}, but the range is allowed to include invalid
     * bits.
     * 
     * @param fromIndex
     *            index of the first bit to include
     * @param nbits
     *            number of bits to include
     * @return a new BitSet from a range of this BitVector
     */
    public BitVector getIndiscriminate(int fromIndex, int nbits) {
        checkRange(fromIndex, nbits, false);
        BitVector result = new BitVector(nbits, "bits [" + fromIndex + ":"
                + (fromIndex + nbits - 1) + "] of " + getName());
        result.bitSet = bitSet.get(fromIndex, fromIndex + nbits);
        result.valid = valid.get(fromIndex, fromIndex + nbits);
        return result;
    }

    /**
     * Copies the source bit vector into the receiver, starting at index
     * <code>fromIndex</code>. If the source bit vector does not extend to
     * the end of the receiver, the high-index bits will not be modified. The
     * source bit vector is required to contain no invalid bits.
     * 
     * @param fromIndex
     *            starting index
     * @param source
     *            source bits
     */
    public void put(int fromIndex, BitVector source) {
        int nbits = source.getNumBits();
        checkRange(fromIndex, nbits, false);
        source.checkRange(0, nbits, true);

        putIndiscriminate(fromIndex, source);
    }

    /**
     * Like {@link #put(int, BitVector)}, but the source bit vector is allowed
     * to have invalid bits.
     * 
     * @param fromIndex
     *            starting index
     * @param source
     *            source bits
     */
    public void putIndiscriminate(int fromIndex, BitVector source) {
        int nbits = source.getNumBits();
        checkRange(fromIndex, nbits, false);
        source.checkRange(0, nbits, false);

        for (int ind = 0; ind < nbits; ind++) {
            if (source.isValid(ind) == false) {
                invalidate(fromIndex + ind);
            } else if (source.get(ind)) {
                set(fromIndex + ind);
            } else {
                clear(fromIndex + ind);
            }
        }
    }

    /**
     * Sets bits in bit vector according to a big endian input
     * <code>String</code>, starting at bit index <code>fromIndex</code>.
     * If the string does not extend to the end of the bit vector, the
     * high-index bits will not be modified.
     * 
     * @param fromIndex
     *            index of the first bit to be set
     * @param inp
     *            new bit values (e.g., "<tt>10101</tt>")
     */
    public void put(int fromIndex, String inp) {
        int length = inp.length();
        if (length == 0) return;
        checkRange(fromIndex, length, false);

        for (int ind = 0; ind < length; ind++) {
            char character = inp.charAt(ind);
            if (character == '1') {
                set(fromIndex + ind);
            } else if (character == '0') {
                clear(fromIndex + ind);
            } else {
                Infrastructure.fatal("Bad character " + character
                        + " in bit string " + inp
                        + ", only '0' and '1' are allowed for put method.");
            }
        }
    }

    /**
     * Sets bits in bit vector according to an
     * <code>int[]</code>, starting at bit index <code>fromIndex</code>.
     * If the array does not extend to the end of the bit vector, the
     * high-index bits will not be modified. The array must
     * be an array of 1's and 0's (1 for true, 0 for false).
     *
     * @param fromIndex
     *            index of the first bit to be set
     * @param array
     *            new bit values
     */
    public void put(int fromIndex, int[] array) {
        int length = array.length;
        if (length == 0) return;
        checkRange(fromIndex, length, false);

        for (int ind = 0; ind < length; ind++) {
            int i = array[ind];
            if (i == 1) {
                set(fromIndex + ind);
            } else if (i == 0) {
                clear(fromIndex + ind);
            } else {
                Infrastructure.fatal("Bad value " + i
                        + " in int[] " + array.toString()
                        + ", only 0 and 1 are allowed for put method.");
            }
        }
    }


    /**
     * Sets <code>nbits</code> bits in bit vector according to the bit
     * sequence in a <code>BigInteger</code>, starting at bit index
     * <code>fromIndex</code>. The integer's bit sequence is reversed upon
     * storage.
     * 
     * @param fromIndex
     *            index of the first bit to be set
     * @param nbits
     *            number of bits to set
     * @param inp
     *            number containing new bit values in reverse order
     */
    public void put(int fromIndex, int nbits, BigInteger inp) {
        checkRange(fromIndex, nbits, false);

        for (int ind = 0; ind < nbits; ind++) {
            BigInteger bit = inp.shiftRight(nbits - ind - 1);
            bit = bit.and(BigInteger.ONE);

            if (bit.equals(BigInteger.ONE)) {
                set(fromIndex + ind);
            } else if (bit.equals(BigInteger.ZERO)) {
                clear(fromIndex + ind);
            } else {
                Infrastructure.fatal("Programming error: bad bit value " + bit
                        + " in BigInteger " + inp);
            }
        }
    }

    /**
     * Sets <code>nbits</code> bits in bit vector according to the bit
     * sequence in a <code>BigInteger</code>, starting at bit index
     * <code>fromIndex</code>.
     * 
     * @param fromIndex
     *            index of the first bit to be set
     * @param nbits
     *            number of bits to set
     * @param inp
     *            number containing new bit values in reverse order
     */
    public void putLittle(int fromIndex, int nbits, BigInteger inp) {
        checkRange(fromIndex, nbits, false);

        for (int ind = 0; ind < nbits; ind++) {
            BigInteger bit = inp.shiftRight(ind);
            bit = bit.and(BigInteger.ONE);

            if (bit.equals(BigInteger.ONE)) {
                set(fromIndex + ind);
            } else if (bit.equals(BigInteger.ZERO)) {
                clear(fromIndex + ind);
            } else {
                Infrastructure.fatal("Programming error: bad bit value " + bit
                        + " in BigInteger " + inp);
            }
        }
    }

    /**
     * Returns the number of bits set to <tt>true</tt> in this
     * <code>BitVector</code>.
     * 
     * @return the number of bits set to <tt>true</tt> in this
     *         <code>BitVector</code>.
     */
    public int cardinality() {
        int numGoodBits = valid.cardinality();
        if (numGoodBits < numBits) {
            Infrastructure.fatal("Only " + numGoodBits + " out of " + numBits
                    + " bits valid in BitVector '" + getName()
                    + "'.  Can only count cardinality of"
                    + " a fully-valid (i.e. initialized) BitVector.");
        }
        return bitSet.cardinality();
    }

    /**
     * Returns <tt>true</tt> if this <code>BitSet</code> contains only bits
     * that are <tt>false</tt>.
     * 
     * @return whether this <code>BitSet</code> is empty.
     */
    public boolean isEmpty() {
        checkRange(0, getNumBits(), true);
        return bitSet.isEmpty();
    }

    /**
     * Returns <tt>true</tt> if all of the bits in this <code>BitSet</code>
     * are in the <tt>invalid</tt> state.
     * 
     * @return whether this <code>BitSet</code> is completely invalid.
     */
    public boolean isInvalid() {
        checkRange(0, getNumBits(), false);
        return valid.isEmpty();
    }
    
    //-------------------------------------------------------------------------
    /** I'm adding a bunch of methods that will make BitVector convenient for
     * writing test code.  This code will behave as if BitVector is a big
     * endian integer. RKao
     */
    private void fatalIfAnyBitInvalid(String op) {
    	for (int i=0; i<getNumBits(); i++) {
    		if (!isValid(i)) {
    			Infrastructure.fatal(op+" operand contains invalid bits");
    		}
    	}
    }
    /** Compare BitVectors. number of bits must match. */
    public boolean equals(Object o) {
    	if (!(o instanceof BitVector)) return false;
    	String s1 = getState();
    	String s2 = ((BitVector) o).getState();
    	return s1.equals(s2);
    }
    
    public int hashCode() {return getState().hashCode();}
    
    /** Generate concatenation of bit vectors. Put bits from b on the right */
    public BitVector cat(BitVector b) {
    	String s = getState() + b.getState();
    	return new BitVector(s, "cat");
    }
    /** Generate the complement all bits */
    public BitVector not() {
    	BitVector r = new BitVector(this);
    	r.flip(0, r.getNumBits());
    	return r;
    }
    /**
     * Logical AND this BitVector with b. Pad the shorter
     * of the two operands with zeros on the left.
     * @param b second operand
     * @return a new BitVector that is this AND b
     */
    public BitVector and(BitVector b) {
    	BitVector a = this;
    	int lenA = a.getNumBits();
    	int lenB = b.getNumBits();
    	int l = Math.max(lenA, lenB);
    	BitVector ans = new BitVector(l, "and");
    	int aNdx = lenA-1;
    	int bNdx = lenB-1;
    	for (int i=l-1; i>=0; i--) {
    		if (!a.isValid(aNdx) || !b.isValid(bNdx)) {
    			ans.invalidate(i);
    		} else {
    			boolean av = a.get(aNdx);
    			boolean bv = b.get(bNdx);
    			boolean ansv = av && bv;
    			ans.set(i, ansv);
    		}
    		if (aNdx>0) aNdx--;
    		if (bNdx>0) bNdx--;
    	}
    	return ans;
    }
    /**
     * Return a new BitVector that is the bit reverse of the
     * bits in this BitVector. That is the MSB
     * moves to the LSB and all other bits are shifted to the left.
     * @return the new rotated BitVector
     */
    public BitVector bitReverse() {
    	int l = getNumBits();
    	BitVector ans = new BitVector(l, "bitReverse");
    	int j=l-1;
    	for (int i=0; i<l; i++, j--) {
    		if (!isValid(i)) continue;
    		ans.set(j, get(i));
    	}
    	return ans;
    }
    /** Set the value of BitVector from an long value.  Right justify. 
     * Sign extend if longValue is too short.  Truncate MSBs if longValue
     *  is too long */
    public void setFromLong(long longValue) {
    	for (int i=getNumBits()-1; i>=0; i--) {
    		set(i, (longValue & 1)==1);
    		longValue = longValue >> 1;
    	}
    }
    /** Set the value of BitVector from a BigInteger.  Right justify. 
     * Sign extend if bigValue is too short.  Truncate MSBs if bigValue
     *  is too large */
    public void setFromBigInteger(BigInteger bigValue) {
    	BigInteger ONE = BigInteger.ONE;
    	for (int i=getNumBits()-1; i>=0; i--) {
    		set(i, (bigValue.and(ONE)).equals(ONE));
    		bigValue = bigValue.shiftRight(1);
    	}
    }
    /** Sign extend the shorter operand to the length of the longer
     * longer operand.
     * Add the two numbers. Truncate the result to the length of the
     * longer operand. */
    public BitVector add(BitVector bv) {
    	fatalIfAnyBitInvalid("add");
    	bv.fatalIfAnyBitInvalid("add");
    	
    	int len = Math.max(getNumBits(), bv.getNumBits());
    	BitVector ans = new BitVector(len, "add");
    	BigInteger a = this.toBigInteger();
    	BigInteger b = bv.toBigInteger();
    	ans.setFromBigInteger(a.add(b));
    	return ans;
    }
    /** Sign extend the shorter operand to the length of the longer
     * longer operand.
     * Subtract (this - bv). Truncate the result to the length of the
     * longer operand. */
    public BitVector subtract(BitVector bv) {
    	fatalIfAnyBitInvalid("subtract");
    	bv.fatalIfAnyBitInvalid("subtract");
    	
    	int len = Math.max(getNumBits(), bv.getNumBits());
    	BitVector ans = new BitVector(len, "subtract");
    	BigInteger a = this.toBigInteger();
    	BigInteger b = bv.toBigInteger();
    	ans.setFromBigInteger(a.subtract(b));
    	return ans;
    }
    /** Shift right, filling with sign bit */
    public BitVector shiftRight(int n) {
    	fatalIfAnyBitInvalid("shiftRight");
    	int len = getNumBits();
    	BitVector ans = new BitVector(len, "shiftRight");
    	for (int i=0; i<len; i++) {
    		int j = Math.max(0, i-n);
    		if (!isValid(j)) continue;
    		ans.set(i, get(j));
    	}
    	return ans;
    }
    /** convert to long. Truncate MSBs if BitVector is too large */
    public long toLong() {
    	fatalIfAnyBitInvalid("toLong");
    	BigInteger big = toBigInteger();
    	return big.longValue();
    }
    /** sign extend shorter operand to length of longer operand.
     * Then test for equality */
    public boolean equalsLong(long v) {
    	fatalIfAnyBitInvalid("equalsLong");
    	int len = Math.max(64, getNumBits());
    	BitVector a = new BitVector(len, "equalsLong a");
    	BitVector b = new BitVector (len, "equalsLong b");
    	a.setFromBigInteger(toBigInteger());
    	b.setFromLong(v);
    	return a.equals(b);
    }
    
    /**
     * Return a new BitVector that consists of the
     * bits in this BitVector rotated left. That is the MSB
     * moves to the LSB and all other bits are shifted to the 
     * left.
     * @param amountToRotate number of bit positions to rotate 
     * @return the new rotated BitVector
     */
    public BitVector rotateLeft(int amountToRotate) {
    	int len = getNumBits();
    	BitVector ans = new BitVector(len, "rotateLeft");
    	for (int i=0; i<len; i++) {
    		int j = (i+len-amountToRotate) % len;
    		if (this.isValid(i)) {
    			ans.set(j, this.get(i));
    		}
    	}
    	return ans;
    }

    /**
     * Return a new BitVector that consists of the
     * bits in this BitVector rotated right. That is the LSB
     * moves to the MSB and all other bits are shifted to the 
     * right.
     * @param amountToRotate number of bit positions to rotate 
     * @return the new rotated BitVector
     */
    public BitVector rotateRight(int amountToRotate) {
    	int len = getNumBits();
    	BitVector ans = new BitVector(len, "rotateLeft");
    	for (int i=0; i<len; i++) {
    		int j = (i+len+amountToRotate) % len;
    		if (this.isValid(i)) {
    			ans.set(j, this.get(i));
    		}
    	}
    	return ans;
    }
    //-------------------------------------------------------------------------
    

    /**
     * Checks if <code>BitVector</code> includes a bit at index
     * <code>bitIndex</code> and, optionally, if the bit has a known state. If
     * not, prints an error message and exits the JVM.
     * 
     * @param bitIndex
     *            bit index
     * @param checkValidity
     *            whether to insist bit is valid
     */
    private void checkIndex(int bitIndex, boolean checkValidity) {
        if (bitIndex < 0 || bitIndex > numBits) {
            Infrastructure.fatal("Bit index " + bitIndex
                    + " outside allowed range of 0.." + numBits
                    + " in BitVector " + toString());
        }
        if (checkValidity && this.valid.get(bitIndex) == false) {
            printInvalidError(bitIndex);
        }
    }

    /**
     * @param bitIndex
     *            index of invalid bit being accessed
     */
    private void printInvalidError(int bitIndex) {
        Infrastructure.fatal("Attempt to access the bit at position "
                + bitIndex + " in BitVector '" + getName()
                + "', which is in the 'invalid' state.  "
                + "Bits must be explicitly set before being read.  "
                + "This error probably indicates incorrect "
                + "initialization of the BitVector.  "
                + "The BitVector state is " + getState());
    }

    /**
     * Checks if bit range is consistent with this <code>BitVector</code>. If
     * not, prints an error message and exits the JVM.
     * 
     * @param fromIndex
     *            starting index
     * @param nbits
     *            number of bits in range
     * @param checkValidity
     *            whether to insist bit is valid
     */
    private void checkRange(int fromIndex, int nbits, boolean checkValidity) {
        if (nbits <= 0) {
            Infrastructure.fatal("Attempt to read " + nbits
                    + " bits, number must be positive");
        }
        if ((fromIndex + nbits) > numBits) {
            Infrastructure
                    .fatal("Attempt to read past the end" + " of BitVector '"
                            + getName() + "', which has length " + numBits
                            + ": fromIndex=" + fromIndex + ", nbits=" + nbits);
        }
        if (checkValidity) {
            for (int ind = fromIndex; ind < fromIndex + nbits; ind++) {
                if (this.valid.get(ind) == false) {
                    printInvalidError(ind);
                }
            }
        }
    }

    /**
     * Unit test, sets and prints some bit vectors. If args[0] is present, it is
     * the string (e.g., "01110") to set <code>BitVector b1</code> to. If
     * args[1] is prsent, it is the string to set <code>BitVector b2</code>
     * to. Otherwise default values of "1101" and "1001" are used.
     */
    public static void main(String[] args) {
        String b2String;

        // Test put(string), toString().
        BitVector b1 = new BitVector(7, "b1");
        if (args.length > 0) {
            b1.put(0, args[0]);
        } else {
            b1.put(0, "1101");
        }
        System.out.print(b1 + ": bitSet=" + b1.bitSet);
        System.out.println(", length=" + b1.numBits + ", size="
                + b1.bitSet.size());

        // Test get(), set(), clear()
        System.out.println("3 bits starting at 1: " + b1.get(1, 3));
        b1.set(2);
        b1.clear(1);
        System.out.println("After setting 2, clearing 1: " + b1);

        // Test put()
        if (args.length > 1) {
            b2String = args[1];
        } else {
            b2String = "1001";
        }
        BitVector b2 = new BitVector(b2String.length(), "b2");
        b2.put(0, b2String);
        b1.put(2, b2);
        System.out.println("inserted " + b2 + " at position 2: " + b1);
        b1.put(2, "010");
        System.out.println("inserted 3 bits 010 at position 2: " + b1);

        BitVector b3 = new BitVector(40, "b3");
        BigInteger biggy = new BigInteger("3");
        b3.set(0, b3.getNumBits(), false);
        b3.put(0, 2, biggy);
        System.out.println("biggy = " + biggy + ", b3 = " + b3.getState()
                + ", biggy2 = " + b3.toBigInteger() + " ("
                + b3.toLittleInteger() + ")");
        biggy = new BigInteger("536870912");
        b3.put(3, 30, biggy);
        System.out.println("biggy = " + biggy + ", b3 = " + b3.getState()
                + ", biggy2 = " + b3.toBigInteger() + " ("
                + b3.toLittleInteger() + ")");

        BitVector b4 = new BitVector(10, "b4");
        biggy = new BigInteger("512");
        b4.put(0, 10, biggy);
        System.out.println("biggy = " + biggy + ", b4 = " + b4.getState()
                + ", biggy2 = " + b4.toBigInteger() + " ("
                + b4.toLittleInteger() + ")");

        biggy = new BigInteger("11");
        b4.putLittle(2, 5, biggy);
        System.out.println("biggy = " + biggy + ", b4 = " + b4.getState()
                + ", biggy2 = " + b4.toBigInteger() + " ("
                + b4.toLittleInteger() + ")");

        System.out.println("Convenience constructor: "
                + new BitVector("101", "convenience"));
    }

}
