1 package net.mograsim.logic.core.types;
3 import static java.lang.String.format;
5 import java.util.Arrays;
6 import java.util.Iterator;
7 import java.util.NoSuchElementException;
8 import java.util.Objects;
9 import java.util.RandomAccess;
10 import java.util.function.BinaryOperator;
11 import java.util.function.UnaryOperator;
14 * Immutable class representing a {@link Bit}Vector
16 * @author Christian Femers
19 public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit>, RandomAccess
21 public static final BitVector SINGLE_U = new BitVector(Bit.U);
22 public static final BitVector SINGLE_X = new BitVector(Bit.X);
23 public static final BitVector SINGLE_0 = new BitVector(Bit.ZERO);
24 public static final BitVector SINGLE_1 = new BitVector(Bit.ONE);
25 public static final BitVector SINGLE_Z = new BitVector(Bit.Z);
27 private static final BitVector[] SINGLE_BIT_MAPPING = { SINGLE_U, SINGLE_X, SINGLE_0, SINGLE_1, SINGLE_Z };
29 private final Bit[] bits;
31 private BitVector(Bit single)
33 Objects.requireNonNull(single);
34 bits = new Bit[] { single };
37 private BitVector(Bit[] bits)
39 this.bits = Objects.requireNonNull(bits); // do this first to "catch" bits==null before the foreach loop
42 throw new NullPointerException();
45 public static BitVector of(Bit... bits)
48 return SINGLE_BIT_MAPPING[bits[0].ordinal()];
49 return new BitVector(bits.clone());
52 public static BitVector of(Bit bit, int length)
55 return SINGLE_BIT_MAPPING[bit.ordinal()];
56 return new BitVector(bit.makeArray(length));
59 public BitVectorMutator mutator()
61 return BitVectorMutator.of(this);
65 * Returns the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
67 public Bit getMSBit(int bitIndex)
69 return bits[bitIndex];
73 * Returns the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
75 public Bit getLSBit(int bitIndex)
77 return bits[bits.length - bitIndex - 1];
80 public Bit[] getBits()
86 public BitVector join(BitVector t)
88 checkCompatibility(t);
90 return SINGLE_BIT_MAPPING[bits[0].join(t.bits[0]).ordinal()];
91 return new BitVector(binOp(bits.clone(), t.bits, Bit::join));
95 public BitVector and(BitVector t)
97 checkCompatibility(t);
99 return SINGLE_BIT_MAPPING[bits[0].and(t.bits[0]).ordinal()];
100 return new BitVector(binOp(bits.clone(), t.bits, Bit::and));
104 public BitVector or(BitVector t)
106 checkCompatibility(t);
107 if (bits.length == 1)
108 return SINGLE_BIT_MAPPING[bits[0].or(t.bits[0]).ordinal()];
109 return new BitVector(binOp(bits.clone(), t.bits, Bit::or));
113 public BitVector xor(BitVector t)
115 checkCompatibility(t);
116 if (bits.length == 1)
117 return SINGLE_BIT_MAPPING[bits[0].xor(t.bits[0]).ordinal()];
118 return new BitVector(binOp(bits.clone(), t.bits, Bit::xor));
122 public BitVector not()
124 if (bits.length == 1)
125 return SINGLE_BIT_MAPPING[bits[0].not().ordinal()];
126 return new BitVector(unOp(bits.clone(), Bit::not));
134 public BitVector concat(BitVector other)
136 Bit[] newBits = Arrays.copyOf(bits, length() + other.length());
137 System.arraycopy(other.bits, 0, newBits, length(), other.length());
138 return new BitVector(newBits);
141 public BitVector subVector(int start)
143 return new BitVector(Arrays.copyOfRange(bits, start, length()));
146 public BitVector subVector(int start, int end)
148 return new BitVector(Arrays.copyOfRange(bits, start, end));
151 private void checkCompatibility(BitVector bv)
153 if (length() != bv.length())
154 throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", length(), bv.length()));
157 static Bit[] binOp(Bit[] dest, Bit[] second, BinaryOperator<Bit> op)
160 return second.clone();
161 for (int i = 0; i < dest.length; i++)
163 dest[i] = op.apply(dest[i], second[i]);
168 static Bit[] unOp(Bit[] dest, UnaryOperator<Bit> op)
172 for (int i = 0; i < dest.length; i++)
174 dest[i] = op.apply(dest[i]);
180 * Class for comfortable and efficient manipulation of {@link BitVector}s, similar to {@link StringBuilder}
182 * @author Christian Femers
184 public static final class BitVectorMutator implements LogicType<BitVectorMutator, BitVector>
188 private BitVectorMutator(Bit[] bits)
193 static BitVectorMutator of(BitVector bv)
195 return new BitVectorMutator(bv.getBits());
199 * Returns a new mutator of the specified length, <b>with all bits set to <code>null</code></b>. Use with care!
201 public static BitVectorMutator ofLength(int length)
203 return new BitVectorMutator(new Bit[length]);
207 * Returns an empty mutator which has no bits set and will simply copy the values from the first binary operation performed.
209 public static BitVectorMutator empty()
211 return new BitVectorMutator(null);
215 * Produces the resulting, immutable {@link BitVector}<br>
217 * @throws IllegalStateException if the mutator is (still) empty
219 public BitVector toBitVector()
222 throw new IllegalStateException("cannot create a BitVector from an empty mutator");
223 return new BitVector(bits);
227 public BitVectorMutator join(BitVector t)
229 checkCompatibility(t);
230 bits = binOp(bits, t.bits, Bit::join);
235 public BitVectorMutator and(BitVector t)
237 checkCompatibility(t);
238 bits = binOp(bits, t.bits, Bit::and);
243 public BitVectorMutator or(BitVector t)
245 checkCompatibility(t);
246 bits = binOp(bits, t.bits, Bit::or);
251 public BitVectorMutator xor(BitVector t)
253 checkCompatibility(t);
254 bits = binOp(bits, t.bits, Bit::xor);
259 public BitVectorMutator not()
261 unOp(bits, Bit::not);
266 * Set the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
268 public void setMSBit(int bitIndex, Bit bit)
270 bits[bitIndex] = bit;
274 * Set the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
276 public void setLSBit(int bitIndex, Bit bit)
278 bits[bits.length - bitIndex - 1] = bit;
282 * Returns the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
284 public Bit getMSBit(int bitIndex)
286 return bits[bitIndex];
290 * Returns the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
292 public Bit getLSBit(int bitIndex)
294 return bits[bits.length - bitIndex - 1];
302 private void checkCompatibility(BitVector bv)
304 if (bits != null && bits.length != bv.length())
305 throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", bits.length, bv.length()));
310 * @see Arrays#hashCode(Object[])
313 public int hashCode()
315 return Arrays.hashCode(bits);
319 * Does test for equality of values/content
321 * @see Object#equals(Object)
324 public boolean equals(Object obj)
328 if (!(obj instanceof BitVector))
330 BitVector other = (BitVector) obj;
331 return Arrays.equals(bits, other.bits);
335 * Does test for equality of values/content, shifting the other BitVector by <code>offset</code> to the right.<br>
336 * Therefore <code>offset + other.length() <= this.length()</code> needs to be true.
338 * @throws ArrayIndexOutOfBoundsException if <code>offset + other.length() > this.length()</code>
340 * @see Object#equals(Object)
342 public boolean equalsWithOffset(BitVector other, int offset)
346 return Arrays.equals(bits, offset, offset + other.length(), other.bits, 0, other.length());
350 * All {@link Bit}s symbols concatenated together (MSB first)
352 * @see #parse(String)
355 public String toString()
357 StringBuilder sb = new StringBuilder(bits.length);
360 return sb.toString();
364 * Parses a String containing solely {@link Bit} symbols (MSB first)
368 public static BitVector parse(String s)
370 Bit[] values = new Bit[s.length()];
371 for (int i = 0; i < s.length(); i++)
373 values[i] = Bit.parse(s, i);
375 return new BitVector(values);
379 * Iterate over the {@link Bit}s of the BitVector <b>from MSB to LSB</b> (left to right).
382 public Iterator<Bit> iterator()
384 return new Iterator<>()
392 throw new NoSuchElementException();
393 return getMSBit(pos++);
397 public boolean hasNext()
399 return pos != length();