X-Git-Url: https://mograsim.net/gitweb/?a=blobdiff_plain;f=era.mi%2Fsrc%2Fera%2Fmi%2Flogic%2Ftypes%2FBitVector.java;fp=era.mi%2Fsrc%2Fera%2Fmi%2Flogic%2Ftypes%2FBitVector.java;h=51545f740005e020ddd5874adb12e7a267b7d7b3;hb=dcbba0b189fd37135adc4487f1b8b645e7045bc4;hp=0000000000000000000000000000000000000000;hpb=2ccdd5a2ed812bc4eb864ab4fbb1adb1c723a1c9;p=Mograsim.git diff --git a/era.mi/src/era/mi/logic/types/BitVector.java b/era.mi/src/era/mi/logic/types/BitVector.java new file mode 100644 index 00000000..51545f74 --- /dev/null +++ b/era.mi/src/era/mi/logic/types/BitVector.java @@ -0,0 +1,316 @@ +package era.mi.logic.types; + +import static java.lang.String.format; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.RandomAccess; +import java.util.function.BinaryOperator; +import java.util.function.UnaryOperator; + +/** + * Immutable class representing a {@link Bit}Vector + * + * + * @author Christian Femers + * + */ +public final class BitVector implements StrictLogicType, Iterable, RandomAccess +{ + private final Bit[] bits; + + private BitVector(Bit[] bits) + { + this.bits = Objects.requireNonNull(bits); + } + + public static BitVector of(Bit... bits) + { + return new BitVector(bits.clone()); + } + + public static BitVector of(Bit bit, int length) + { + return new BitVector(bit.makeArray(length)); + } + + public BitVectorMutator mutator() + { + return BitVectorMutator.of(this); + } + + public Bit getBit(int bitIndex) + { + return bits[bitIndex]; + } + + public Bit[] getBits() + { + return bits.clone(); + } + + @Override + public BitVector join(BitVector t) + { + checkCompatibility(t); + return new BitVector(binOp(bits.clone(), t.bits, Bit::join)); + } + + @Override + public BitVector and(BitVector t) + { + checkCompatibility(t); + return new BitVector(binOp(bits.clone(), t.bits, Bit::and)); + } + + @Override + public BitVector or(BitVector t) + { + checkCompatibility(t); + return new BitVector(binOp(bits.clone(), t.bits, Bit::or)); + } + + @Override + public BitVector xor(BitVector t) + { + checkCompatibility(t); + return new BitVector(binOp(bits.clone(), t.bits, Bit::xor)); + } + + @Override + public BitVector not() + { + return new BitVector(unOp(bits.clone(), Bit::not)); + } + + public int length() + { + 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()); + return new BitVector(newBits); + } + + public BitVector subVector(int start) + { + return new BitVector(Arrays.copyOfRange(bits, start, length())); + } + + public BitVector subVector(int start, int end) + { + return new BitVector(Arrays.copyOfRange(bits, start, 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())); + } + + static Bit[] binOp(Bit[] dest, Bit[] second, BinaryOperator op) + { + if (dest == null) + return second.clone(); + for (int i = 0; i < dest.length; i++) + { + dest[i] = op.apply(dest[i], second[i]); + } + return dest; + } + + static Bit[] unOp(Bit[] dest, UnaryOperator op) + { + if (dest == null) + return null; + for (int i = 0; i < dest.length; i++) + { + dest[i] = op.apply(dest[i]); + } + return dest; + } + + /** + * Class for comfortable and efficient manipulation of {@link BitVector}s, similar to {@link StringBuilder} + * + * @author Christian Femers + */ + @SuppressWarnings("synthetic-access") + public static final class BitVectorMutator implements LogicType + { + private Bit[] bits; + + private BitVectorMutator(Bit[] bits) + { + this.bits = bits; + } + + static BitVectorMutator of(BitVector bv) + { + return new BitVectorMutator(bv.getBits()); + } + + /** + * Returns an empty mutator which has no bits set and will simply copy the values from the first binary operation performed. + * + */ + public static BitVectorMutator empty() + { + return new BitVectorMutator(null); + } + + /** + * Produces the resulting, immutable {@link BitVector}
+ * + * @throws IllegalStateException if the mutator is (still) empty + */ + public BitVector get() + { + if (bits == null) + throw new IllegalStateException("cannot create a BitVector from an empty mutator"); + return new BitVector(bits); + } + + @Override + public BitVectorMutator join(BitVector t) + { + checkCompatibility(t); + bits = binOp(bits, t.bits, Bit::join); + return this; + } + + @Override + public BitVectorMutator and(BitVector t) + { + checkCompatibility(t); + bits = binOp(bits, t.bits, Bit::and); + return this; + } + + @Override + public BitVectorMutator or(BitVector t) + { + checkCompatibility(t); + bits = binOp(bits, t.bits, Bit::or); + return this; + } + + @Override + public BitVectorMutator xor(BitVector t) + { + checkCompatibility(t); + bits = binOp(bits, t.bits, Bit::xor); + return this; + } + + @Override + public BitVectorMutator not() + { + unOp(bits, Bit::not); + return this; + } + + 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())); + } + } + + /** + * @see Arrays#hashCode(Object[]) + */ + @Override + public int hashCode() + { + return Arrays.hashCode(bits); + } + + /** + * Does test for equality of values/content + * + * @see Object#equals(Object) + */ + @Override + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (!(obj instanceof BitVector)) + return false; + BitVector other = (BitVector) obj; + return Arrays.equals(bits, other.bits); + } + + /** + * Does test for equality of values/content, shifting the other BitVector by offset to the right.
+ * Therefore offset + other.length() <= this.length() needs to be true. + * + * @throws ArrayIndexOutOfBoundsException if offset + other.length() > this.length() + * + * @see Object#equals(Object) + */ + public boolean equals(BitVector other, int offset) + { + if (other == null) + return false; + return Arrays.equals(bits, offset, offset + other.length(), other.bits, 0, other.length()); + } + + /** + * All {@link Bit}s symbols concatenated together + * + * @see #parse(String) + */ + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(bits.length); + for (Bit bit : bits) + sb.append(bit); + return sb.toString(); + } + + /** + * Parses a String containing solely {@link Bit} symbols + * + * @see #toString() + */ + public static BitVector parse(String s) + { + Bit[] values = new Bit[s.length()]; + for (int i = 0; i < s.length(); i++) + { + values[i] = Bit.parse(s, i); + } + return new BitVector(values); + } + + @Override + public Iterator iterator() + { + return new Iterator<>() + { + private int pos = 0; + + @Override + public Bit next() + { + if (!hasNext()) + throw new NoSuchElementException(); + return getBit(pos++); + } + + @Override + public boolean hasNext() + { + return pos != length(); + } + }; + } +}