1 package net.mograsim.logic.core.types;
3 import static java.lang.String.format;
5 import java.math.BigInteger;
6 import java.util.Arrays;
7 import java.util.Iterator;
8 import java.util.NoSuchElementException;
9 import java.util.Objects;
10 import java.util.RandomAccess;
11 import java.util.function.BinaryOperator;
12 import java.util.function.UnaryOperator;
15 * Immutable class representing a {@link Bit}Vector
17 * @author Christian Femers
20 public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit>, RandomAccess
22 public static final BitVector SINGLE_U = new BitVector(Bit.U);
23 public static final BitVector SINGLE_X = new BitVector(Bit.X);
24 public static final BitVector SINGLE_0 = new BitVector(Bit.ZERO);
25 public static final BitVector SINGLE_1 = new BitVector(Bit.ONE);
26 public static final BitVector SINGLE_Z = new BitVector(Bit.Z);
28 private static final BitVector[] SINGLE_BIT_MAPPING = { SINGLE_U, SINGLE_X, SINGLE_0, SINGLE_1, SINGLE_Z };
30 private final Bit[] bits;
32 private BitVector(Bit single)
34 Objects.requireNonNull(single);
35 bits = new Bit[] { single };
38 private BitVector(Bit[] bits)
40 this.bits = Objects.requireNonNull(bits); // do this first to "catch" bits==null before the foreach loop
43 throw new NullPointerException();
46 public static BitVector of(Bit... bits)
49 return SINGLE_BIT_MAPPING[bits[0].ordinal()];
50 return new BitVector(bits.clone());
53 public static BitVector of(Bit bit, int length)
56 return SINGLE_BIT_MAPPING[bit.ordinal()];
57 return new BitVector(bit.makeArray(length));
60 public BigInteger getUnsignedValue()
63 throw new NumberFormatException("BitVector is non binary: " + toString());
64 Bit[] bits = getBits();
65 int length = length();
66 byte[] bytes = new byte[(length / 8) + 1];
67 for (int i = 0; i < length; i++)
69 if (Bit.ONE.equals(bits[i]))
71 bytes[(i / 8) + 1] |= 1 << (i % 8);
74 return new BigInteger(bytes);
77 public static BitVector from(BigInteger b, int length)
79 int bitLength = b.bitLength();
80 int actualLength = Integer.min(bitLength, length);
81 Bit[] bits = new Bit[length];
82 for (int i = 0; i < actualLength; i++)
83 bits[i] = b.testBit(i) ? Bit.ONE : Bit.ZERO;
85 for (int i = actualLength; i < length; i++)
88 for (int i = actualLength; i < length; i++)
90 return BitVector.of(bits);
93 public BitVectorMutator mutator()
95 return BitVectorMutator.of(this);
99 * Returns the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
101 public Bit getMSBit(int bitIndex)
103 return bits[bitIndex];
107 * Returns the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
109 public Bit getLSBit(int bitIndex)
111 return bits[bits.length - bitIndex - 1];
114 public Bit[] getBits()
119 public boolean isBinary()
121 for (int i = 0; i < bits.length; i++)
123 if (!bits[i].isBinary())
130 public BitVector join(BitVector t)
132 checkCompatibility(t);
133 if (bits.length == 1)
134 return SINGLE_BIT_MAPPING[bits[0].join(t.bits[0]).ordinal()];
135 return new BitVector(binOp(bits.clone(), t.bits, Bit::join));
139 public BitVector and(BitVector t)
141 checkCompatibility(t);
142 if (bits.length == 1)
143 return SINGLE_BIT_MAPPING[bits[0].and(t.bits[0]).ordinal()];
144 return new BitVector(binOp(bits.clone(), t.bits, Bit::and));
148 public BitVector or(BitVector t)
150 checkCompatibility(t);
151 if (bits.length == 1)
152 return SINGLE_BIT_MAPPING[bits[0].or(t.bits[0]).ordinal()];
153 return new BitVector(binOp(bits.clone(), t.bits, Bit::or));
157 public BitVector xor(BitVector t)
159 checkCompatibility(t);
160 if (bits.length == 1)
161 return SINGLE_BIT_MAPPING[bits[0].xor(t.bits[0]).ordinal()];
162 return new BitVector(binOp(bits.clone(), t.bits, Bit::xor));
166 public BitVector not()
168 if (bits.length == 1)
169 return SINGLE_BIT_MAPPING[bits[0].not().ordinal()];
170 return new BitVector(unOp(bits.clone(), Bit::not));
178 public BitVector concat(BitVector other)
180 Bit[] newBits = Arrays.copyOf(bits, length() + other.length());
181 System.arraycopy(other.bits, 0, newBits, length(), other.length());
182 return new BitVector(newBits);
185 public BitVector subVector(int start)
187 return new BitVector(Arrays.copyOfRange(bits, start, length()));
190 public BitVector subVector(int start, int end)
192 return new BitVector(Arrays.copyOfRange(bits, start, end));
195 private void checkCompatibility(BitVector bv)
197 if (length() != bv.length())
198 throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", length(), bv.length()));
201 static Bit[] binOp(Bit[] dest, Bit[] second, BinaryOperator<Bit> op)
204 return second.clone();
205 for (int i = 0; i < dest.length; i++)
207 dest[i] = op.apply(dest[i], second[i]);
212 static Bit[] unOp(Bit[] dest, UnaryOperator<Bit> op)
216 for (int i = 0; i < dest.length; i++)
218 dest[i] = op.apply(dest[i]);
224 * Class for comfortable and efficient manipulation of {@link BitVector}s, similar to {@link StringBuilder}
226 * @author Christian Femers
228 public static final class BitVectorMutator implements LogicType<BitVectorMutator, BitVector>
232 private BitVectorMutator(Bit[] bits)
237 static BitVectorMutator of(BitVector bv)
239 return new BitVectorMutator(bv.getBits());
243 * Returns a new mutator of the specified length, <b>with all bits set to <code>null</code></b>. Use with care!
245 public static BitVectorMutator ofLength(int length)
247 return new BitVectorMutator(new Bit[length]);
251 * Returns an empty mutator which has no bits set and will simply copy the values from the first binary operation performed.
253 public static BitVectorMutator empty()
255 return new BitVectorMutator(null);
259 * Produces the resulting, immutable {@link BitVector}<br>
261 * @throws IllegalStateException if the mutator is (still) empty
263 public BitVector toBitVector()
266 throw new IllegalStateException("cannot create a BitVector from an empty mutator");
267 return new BitVector(bits);
271 public BitVectorMutator join(BitVector t)
273 checkCompatibility(t);
274 bits = binOp(bits, t.bits, Bit::join);
279 public BitVectorMutator and(BitVector t)
281 checkCompatibility(t);
282 bits = binOp(bits, t.bits, Bit::and);
287 public BitVectorMutator or(BitVector t)
289 checkCompatibility(t);
290 bits = binOp(bits, t.bits, Bit::or);
295 public BitVectorMutator xor(BitVector t)
297 checkCompatibility(t);
298 bits = binOp(bits, t.bits, Bit::xor);
303 public BitVectorMutator not()
305 unOp(bits, Bit::not);
310 * Set the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
312 public void setMSBit(int bitIndex, Bit bit)
314 bits[bitIndex] = bit;
318 * Set the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
320 public void setLSBit(int bitIndex, Bit bit)
322 bits[bits.length - bitIndex - 1] = bit;
326 * Returns the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
328 public Bit getMSBit(int bitIndex)
330 return bits[bitIndex];
334 * Returns the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
336 public Bit getLSBit(int bitIndex)
338 return bits[bits.length - bitIndex - 1];
346 private void checkCompatibility(BitVector bv)
348 if (bits != null && bits.length != bv.length())
349 throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", bits.length, bv.length()));
354 * @see Arrays#hashCode(Object[])
357 public int hashCode()
359 return Arrays.hashCode(bits);
363 * Does test for equality of values/content
365 * @see Object#equals(Object)
368 public boolean equals(Object obj)
372 if (!(obj instanceof BitVector))
374 BitVector other = (BitVector) obj;
375 return Arrays.equals(bits, other.bits);
379 * Does test for equality of values/content, shifting the other BitVector by <code>offset</code> to the right.<br>
380 * Therefore <code>offset + other.length() <= this.length()</code> needs to be true.
382 * @throws ArrayIndexOutOfBoundsException if <code>offset + other.length() > this.length()</code>
384 * @see Object#equals(Object)
386 public boolean equalsWithOffset(BitVector other, int offset)
390 return Arrays.equals(bits, offset, offset + other.length(), other.bits, 0, other.length());
394 * All {@link Bit}s symbols concatenated together (MSB first)
396 * @see #parse(String)
399 public String toString()
401 StringBuilder sb = new StringBuilder(bits.length);
404 return sb.toString();
408 * Parses a String containing solely {@link Bit} symbols (MSB first)
412 public static BitVector parse(String s)
414 Bit[] values = new Bit[s.length()];
415 for (int i = 0; i < s.length(); i++)
417 values[i] = Bit.parse(s, i);
419 return new BitVector(values);
422 public static BitVector of(long value, int bits)
424 return of(BigInteger.valueOf(value), bits);
427 public static BitVector of(BigInteger value, int bits)
429 Bit[] values = new Bit[bits];
430 for (int i = 0; i < bits; i++)
432 values[bits - i - 1] = Bit.of(value.testBit(i));
434 return new BitVector(values);
438 * Iterate over the {@link Bit}s of the BitVector <b>from MSB to LSB</b> (left to right).
441 public Iterator<Bit> iterator()
443 return new Iterator<>()
451 throw new NoSuchElementException();
452 return getMSBit(pos++);
456 public boolean hasNext()
458 return pos != length();