import static java.lang.String.format;
+import java.math.BigInteger;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Immutable class representing a {@link Bit}Vector
*
- *
* @author Christian Femers
*
*/
public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit>, RandomAccess
{
+ public static final BitVector SINGLE_U = new BitVector(Bit.U);
+ public static final BitVector SINGLE_X = new BitVector(Bit.X);
+ public static final BitVector SINGLE_0 = new BitVector(Bit.ZERO);
+ public static final BitVector SINGLE_1 = new BitVector(Bit.ONE);
+ public static final BitVector SINGLE_Z = new BitVector(Bit.Z);
+
+ private static final BitVector[] SINGLE_BIT_MAPPING = { SINGLE_U, SINGLE_X, SINGLE_0, SINGLE_1, SINGLE_Z };
+
private final Bit[] bits;
+ private BitVector(Bit single)
+ {
+ Objects.requireNonNull(single);
+ bits = new Bit[] { single };
+ }
+
private BitVector(Bit[] bits)
{
- this.bits = Objects.requireNonNull(bits);// do this first to "catch" bits==null before the foreach loop
+ this.bits = Objects.requireNonNull(bits); // do this first to "catch" bits==null before the foreach loop
for (Bit bit : bits)
if (bit == null)
throw new NullPointerException();
public static BitVector of(Bit... bits)
{
+ if (bits.length == 1)
+ return SINGLE_BIT_MAPPING[bits[0].ordinal()];
return new BitVector(bits.clone());
}
- public static BitVector of(Bit bit, int length)
+ public static BitVector of(Bit bit, int width)
+ {
+ if (width == 1)
+ return SINGLE_BIT_MAPPING[bit.ordinal()];
+ return new BitVector(bit.makeArray(width));
+ }
+
+ public static BitVector from(long value, int bits)
+ {
+ return from(BigInteger.valueOf(value), bits);
+ }
+
+ public static BitVector from(BigInteger value, int bits)
{
- return new BitVector(bit.makeArray(length));
+ Bit[] values = new Bit[bits];
+ for (int i = 0; i < bits; i++)
+ {
+ values[bits - i - 1] = Bit.of(value.testBit(i));
+ }
+ return new BitVector(values);
}
public BitVectorMutator mutator()
return BitVectorMutator.of(this);
}
- public Bit getBit(int bitIndex)
+ /**
+ * Returns the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
+ */
+ public Bit getMSBit(int bitIndex)
{
return bits[bitIndex];
}
+ /**
+ * Returns the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
+ */
+ public Bit getLSBit(int bitIndex)
+ {
+ return bits[bits.length - bitIndex - 1];
+ }
+
public Bit[] getBits()
{
return bits.clone();
}
+ /**
+ * Checks if all bits are {@link Bit#isBinary() binary}.
+ *
+ * @see Bit#isBinary()
+ */
+ public boolean isBinary()
+ {
+ for (int i = 0; i < bits.length; i++)
+ {
+ if (!bits[i].isBinary())
+ return false;
+ }
+ return true;
+ }
+
@Override
public BitVector join(BitVector t)
{
checkCompatibility(t);
+ if (bits.length == 1)
+ return SINGLE_BIT_MAPPING[bits[0].join(t.bits[0]).ordinal()];
return new BitVector(binOp(bits.clone(), t.bits, Bit::join));
}
public BitVector and(BitVector t)
{
checkCompatibility(t);
+ if (bits.length == 1)
+ return SINGLE_BIT_MAPPING[bits[0].and(t.bits[0]).ordinal()];
return new BitVector(binOp(bits.clone(), t.bits, Bit::and));
}
public BitVector or(BitVector t)
{
checkCompatibility(t);
+ if (bits.length == 1)
+ return SINGLE_BIT_MAPPING[bits[0].or(t.bits[0]).ordinal()];
return new BitVector(binOp(bits.clone(), t.bits, Bit::or));
}
public BitVector xor(BitVector t)
{
checkCompatibility(t);
+ if (bits.length == 1)
+ return SINGLE_BIT_MAPPING[bits[0].xor(t.bits[0]).ordinal()];
return new BitVector(binOp(bits.clone(), t.bits, Bit::xor));
}
@Override
public BitVector not()
{
+ if (bits.length == 1)
+ return SINGLE_BIT_MAPPING[bits[0].not().ordinal()];
return new BitVector(unOp(bits.clone(), Bit::not));
}
- public int length()
+ public int width()
{
return bits.length;
}
public BitVector concat(BitVector other)
{
- Bit[] newBits = Arrays.copyOf(bits, length() + other.length());
- System.arraycopy(other.bits, 0, newBits, length(), other.length());
+ Bit[] newBits = Arrays.copyOf(bits, width() + other.width());
+ System.arraycopy(other.bits, 0, newBits, width(), other.width());
return new BitVector(newBits);
}
public BitVector subVector(int start)
{
- return new BitVector(Arrays.copyOfRange(bits, start, length()));
+ return new BitVector(Arrays.copyOfRange(bits, start, width()));
}
public BitVector subVector(int start, int end)
private void checkCompatibility(BitVector bv)
{
- if (length() != bv.length())
- throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", length(), bv.length()));
+ if (width() != bv.width())
+ throw new IllegalArgumentException(format("BitVector width does not match: %d and %d", width(), bv.width()));
}
static Bit[] binOp(Bit[] dest, Bit[] second, BinaryOperator<Bit> op)
}
/**
- * Returns a new mutator of the specified length, <b>with all bits set to <code>null</code></b>. Use with care!
+ * Returns a new mutator of the specified width, <b>with all bits set to <code>null</code></b>. Use with care!
*/
- public static BitVectorMutator ofLength(int length)
+ public static BitVectorMutator ofWidth(int width)
{
- return new BitVectorMutator(new Bit[length]);
+ return new BitVectorMutator(new Bit[width]);
}
/**
* Returns an empty mutator which has no bits set and will simply copy the values from the first binary operation performed.
+ * <p>
+ * An empty BitVectorMutator <b>must not</b> be converted to BitVector or used to manipulate single bits until at least one two
+ * operand logic operation is performed.
*/
public static BitVectorMutator empty()
{
return new BitVectorMutator(null);
}
+ /**
+ * @see #empty()
+ */
+ public boolean isEmpty()
+ {
+ return bits == null;
+ }
+
/**
* Produces the resulting, immutable {@link BitVector}<br>
*
return this;
}
- public void setBit(int bitIndex, Bit bit)
+ /**
+ * Set the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
+ */
+ public void setMSBit(int bitIndex, Bit bit)
{
+ if (bits == null)
+ throw new IllegalStateException("cannot set a bit of an empty mutator");
bits[bitIndex] = bit;
}
- public Bit getBit(int bitIndex)
+ /**
+ * Set the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
+ */
+ public void setLSBit(int bitIndex, Bit bit)
+ {
+ if (bits == null)
+ throw new IllegalStateException("cannot set a bit of an empty mutator");
+ bits[bits.length - bitIndex - 1] = bit;
+ }
+
+ /**
+ * Returns the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
+ */
+ public Bit getMSBit(int bitIndex)
{
+ if (bits == null)
+ throw new IllegalStateException("cannot get a bit of an empty mutator");
return bits[bitIndex];
}
- public int length()
+ /**
+ * Returns the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
+ */
+ public Bit getLSBit(int bitIndex)
+ {
+ if (bits == null)
+ throw new IllegalStateException("cannot get a bit of an empty mutator");
+ return bits[bits.length - bitIndex - 1];
+ }
+
+ public int width()
{
+ if (bits == null)
+ throw new IllegalStateException("cannot obtain a width of an empty mutator");
return bits.length;
}
private void checkCompatibility(BitVector bv)
{
- if (bits != null && bits.length != bv.length())
- throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", bits.length, bv.length()));
+ if (bits != null && bits.length != bv.width())
+ throw new IllegalArgumentException(format("BitVector width does not match: %d and %d", bits.length, bv.width()));
}
}
/**
* Does test for equality of values/content, shifting the other BitVector by <code>offset</code> to the right.<br>
- * Therefore <code>offset + other.length() <= this.length()</code> needs to be true.
+ * Therefore <code>offset + other.width() <= this.wdith()</code> needs to be true.
*
- * @throws ArrayIndexOutOfBoundsException if <code>offset + other.length() > this.length()</code>
+ * @throws ArrayIndexOutOfBoundsException if <code>offset + other.width() > this.width()</code>
*
* @see Object#equals(Object)
*/
{
if (other == null)
return false;
- return Arrays.equals(bits, offset, offset + other.length(), other.bits, 0, other.length());
- }
-
- @Override
- public String toString()
- {
- return toBitStringMSBFirst();
+ return Arrays.equals(bits, offset, offset + other.width(), other.bits, 0, other.width());
}
/**
- * All {@link Bit}s symbols concatenated together
+ * All {@link Bit}s symbols concatenated together (MSB first)
*
* @see #parse(String)
*/
- public String toBitStringLSBFirst()
+ @Override
+ public String toString()
{
StringBuilder sb = new StringBuilder(bits.length);
for (Bit bit : bits)
}
/**
- * All {@link Bit}s symbols concatenated together, with the MSB coming first (like a binary number)
+ * Returns the value of the BitVector as BigInteger.
*
- * @see #parse(String)
+ * @throws NumberFormatException if the BitVector is not {@link #isBinary() binary}.
*/
- public String toBitStringMSBFirst()
+ public BigInteger getUnsignedValue()
{
- StringBuilder sb = new StringBuilder(bits.length);
- for (Bit bit : bits)
- sb.append(bit);
- sb.reverse();
- return sb.toString();
+ if (!isBinary())
+ throw new NumberFormatException(this + " is not binary");
+ byte[] bytes = new byte[(bits.length / 8) + 1];
+ for (int i = 0; i < bits.length; i++)
+ {
+ if (Bit.ONE == bits[i])
+ {
+ bytes[i / 8] |= 1 << (i % 8);
+ }
+ }
+ return new BigInteger(bytes);
}
/**
- * Parses a String containing solely {@link Bit} symbols
+ * Parses a String containing solely {@link Bit} symbols (MSB first)
*
- * @see #toBitStringLSBFirst()
+ * @see #toString()
*/
- public static BitVector parseLSBFirst(String s)
+ public static BitVector parse(String s)
{
Bit[] values = new Bit[s.length()];
for (int i = 0; i < s.length(); i++)
}
/**
- * Parses a String containing solely {@link Bit} symbols, with the MSB coming first (like a binary number)
- *
- * @see #toBitStringLSBFirst()
+ * Iterate over the {@link Bit}s of the BitVector <b>from MSB to LSB</b> (left to right).
*/
- public static BitVector parseMSBFirst(String s)
- {
- Bit[] values = new Bit[s.length()];
- for (int i = 0, j = s.length() - 1; j >= 0; i++, j--)
- {
- values[i] = Bit.parse(s, j);
- }
- return new BitVector(values);
- }
-
@Override
public Iterator<Bit> iterator()
{
{
if (!hasNext())
throw new NoSuchElementException();
- return getBit(pos++);
+ return getMSBit(pos++);
}
@Override
public boolean hasNext()
{
- return pos != length();
+ return pos != width();
}
};
}