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 private final Bit[] bits;
23 private BitVector(Bit[] bits)
25 this.bits = Objects.requireNonNull(bits); // do this first to "catch" bits==null before the foreach loop
28 throw new NullPointerException();
31 public static BitVector of(Bit... bits)
33 return new BitVector(bits.clone());
36 public static BitVector of(Bit bit, int length)
38 return new BitVector(bit.makeArray(length));
41 public BitVectorMutator mutator()
43 return BitVectorMutator.of(this);
47 * Returns the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
49 public Bit getMSBit(int bitIndex)
51 return bits[bitIndex];
55 * Returns the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
57 public Bit getLSBit(int bitIndex)
59 return bits[bits.length - bitIndex - 1];
62 public Bit[] getBits()
68 public BitVector join(BitVector t)
70 checkCompatibility(t);
71 return new BitVector(binOp(bits.clone(), t.bits, Bit::join));
75 public BitVector and(BitVector t)
77 checkCompatibility(t);
78 return new BitVector(binOp(bits.clone(), t.bits, Bit::and));
82 public BitVector or(BitVector t)
84 checkCompatibility(t);
85 return new BitVector(binOp(bits.clone(), t.bits, Bit::or));
89 public BitVector xor(BitVector t)
91 checkCompatibility(t);
92 return new BitVector(binOp(bits.clone(), t.bits, Bit::xor));
96 public BitVector not()
98 return new BitVector(unOp(bits.clone(), Bit::not));
106 public BitVector concat(BitVector other)
108 Bit[] newBits = Arrays.copyOf(bits, length() + other.length());
109 System.arraycopy(other.bits, 0, newBits, length(), other.length());
110 return new BitVector(newBits);
113 public BitVector subVector(int start)
115 return new BitVector(Arrays.copyOfRange(bits, start, length()));
118 public BitVector subVector(int start, int end)
120 return new BitVector(Arrays.copyOfRange(bits, start, end));
123 private void checkCompatibility(BitVector bv)
125 if (length() != bv.length())
126 throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", length(), bv.length()));
129 static Bit[] binOp(Bit[] dest, Bit[] second, BinaryOperator<Bit> op)
132 return second.clone();
133 for (int i = 0; i < dest.length; i++)
135 dest[i] = op.apply(dest[i], second[i]);
140 static Bit[] unOp(Bit[] dest, UnaryOperator<Bit> op)
144 for (int i = 0; i < dest.length; i++)
146 dest[i] = op.apply(dest[i]);
152 * Class for comfortable and efficient manipulation of {@link BitVector}s, similar to {@link StringBuilder}
154 * @author Christian Femers
156 public static final class BitVectorMutator implements LogicType<BitVectorMutator, BitVector>
160 private BitVectorMutator(Bit[] bits)
165 static BitVectorMutator of(BitVector bv)
167 return new BitVectorMutator(bv.getBits());
171 * Returns a new mutator of the specified length, <b>with all bits set to <code>null</code></b>. Use with care!
173 public static BitVectorMutator ofLength(int length)
175 return new BitVectorMutator(new Bit[length]);
179 * Returns an empty mutator which has no bits set and will simply copy the values from the first binary operation performed.
181 public static BitVectorMutator empty()
183 return new BitVectorMutator(null);
187 * Produces the resulting, immutable {@link BitVector}<br>
189 * @throws IllegalStateException if the mutator is (still) empty
191 public BitVector toBitVector()
194 throw new IllegalStateException("cannot create a BitVector from an empty mutator");
195 return new BitVector(bits);
199 public BitVectorMutator join(BitVector t)
201 checkCompatibility(t);
202 bits = binOp(bits, t.bits, Bit::join);
207 public BitVectorMutator and(BitVector t)
209 checkCompatibility(t);
210 bits = binOp(bits, t.bits, Bit::and);
215 public BitVectorMutator or(BitVector t)
217 checkCompatibility(t);
218 bits = binOp(bits, t.bits, Bit::or);
223 public BitVectorMutator xor(BitVector t)
225 checkCompatibility(t);
226 bits = binOp(bits, t.bits, Bit::xor);
231 public BitVectorMutator not()
233 unOp(bits, Bit::not);
238 * Set the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
240 public void setMSBit(int bitIndex, Bit bit)
242 bits[bitIndex] = bit;
246 * Set the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
248 public void setLSBit(int bitIndex, Bit bit)
250 bits[bits.length - bitIndex - 1] = bit;
254 * Returns the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
256 public Bit getMSBit(int bitIndex)
258 return bits[bitIndex];
262 * Returns the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
264 public Bit getLSBit(int bitIndex)
266 return bits[bits.length - bitIndex - 1];
274 private void checkCompatibility(BitVector bv)
276 if (bits != null && bits.length != bv.length())
277 throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", bits.length, bv.length()));
282 * @see Arrays#hashCode(Object[])
285 public int hashCode()
287 return Arrays.hashCode(bits);
291 * Does test for equality of values/content
293 * @see Object#equals(Object)
296 public boolean equals(Object obj)
300 if (!(obj instanceof BitVector))
302 BitVector other = (BitVector) obj;
303 return Arrays.equals(bits, other.bits);
307 * Does test for equality of values/content, shifting the other BitVector by <code>offset</code> to the right.<br>
308 * Therefore <code>offset + other.length() <= this.length()</code> needs to be true.
310 * @throws ArrayIndexOutOfBoundsException if <code>offset + other.length() > this.length()</code>
312 * @see Object#equals(Object)
314 public boolean equalsWithOffset(BitVector other, int offset)
318 return Arrays.equals(bits, offset, offset + other.length(), other.bits, 0, other.length());
322 * All {@link Bit}s symbols concatenated together (MSB first)
324 * @see #parse(String)
327 public String toString()
329 StringBuilder sb = new StringBuilder(bits.length);
332 return sb.toString();
336 * Parses a String containing solely {@link Bit} symbols (MSB first)
340 public static BitVector parse(String s)
342 Bit[] values = new Bit[s.length()];
343 for (int i = 0; i < s.length(); i++)
345 values[i] = Bit.parse(s, i);
347 return new BitVector(values);
351 * Iterate over the {@link Bit}s of the BitVector <b>from MSB to LSB</b> (left to right).
354 public Iterator<Bit> iterator()
356 return new Iterator<>()
364 throw new NoSuchElementException();
365 return getMSBit(pos++);
369 public boolean hasNext()
371 return pos != length();