The final restructured version for automatic build using maven tycho
[Mograsim.git] / plugins / net.mograsim.logic.core / src / net / mograsim / logic / core / types / BitVector.java
1 package net.mograsim.logic.core.types;
2
3 import static java.lang.String.format;
4
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;
13
14 /**
15  * Immutable class representing a {@link Bit}Vector
16  *
17  * @author Christian Femers
18  *
19  */
20 public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit>, RandomAccess
21 {
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);
27
28         private static final BitVector[] SINGLE_BIT_MAPPING = { SINGLE_U, SINGLE_X, SINGLE_0, SINGLE_1, SINGLE_Z };
29
30         private final Bit[] bits;
31
32         private BitVector(Bit single)
33         {
34                 Objects.requireNonNull(single);
35                 bits = new Bit[] { single };
36         }
37
38         private BitVector(Bit[] bits)
39         {
40                 this.bits = Objects.requireNonNull(bits); // do this first to "catch" bits==null before the foreach loop
41                 for (Bit bit : bits)
42                         if (bit == null)
43                                 throw new NullPointerException();
44         }
45
46         public static BitVector of(Bit... bits)
47         {
48                 if (bits.length == 1)
49                         return SINGLE_BIT_MAPPING[bits[0].ordinal()];
50                 return new BitVector(bits.clone());
51         }
52
53         public static BitVector of(Bit bit, int length)
54         {
55                 if (length == 1)
56                         return SINGLE_BIT_MAPPING[bit.ordinal()];
57                 return new BitVector(bit.makeArray(length));
58         }
59
60         public static BitVector from(long value, int bits)
61         {
62                 return from(BigInteger.valueOf(value), bits);
63         }
64
65         public static BitVector from(BigInteger value, int bits)
66         {
67                 Bit[] values = new Bit[bits];
68                 for (int i = 0; i < bits; i++)
69                         values[bits - i - 1] = Bit.of(value.testBit(i));
70                 return new BitVector(values);
71         }
72
73         public BitVectorMutator mutator()
74         {
75                 return BitVectorMutator.of(this);
76         }
77
78         /**
79          * Returns the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
80          */
81         public Bit getMSBit(int bitIndex)
82         {
83                 return bits[bitIndex];
84         }
85
86         /**
87          * Returns the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
88          */
89         public Bit getLSBit(int bitIndex)
90         {
91                 return bits[bits.length - bitIndex - 1];
92         }
93
94         public Bit[] getBits()
95         {
96                 return bits.clone();
97         }
98
99         /**
100          * Checks if all bits are {@link Bit#isBinary() binary}.
101          * 
102          * @see Bit#isBinary()
103          */
104         public boolean isBinary()
105         {
106                 for (int i = 0; i < bits.length; i++)
107                 {
108                         if (!bits[i].isBinary())
109                                 return false;
110                 }
111                 return true;
112         }
113
114         @Override
115         public BitVector join(BitVector t)
116         {
117                 checkCompatibility(t);
118                 if (bits.length == 1)
119                         return SINGLE_BIT_MAPPING[bits[0].join(t.bits[0]).ordinal()];
120                 return new BitVector(binOp(bits.clone(), t.bits, Bit::join));
121         }
122
123         @Override
124         public BitVector and(BitVector t)
125         {
126                 checkCompatibility(t);
127                 if (bits.length == 1)
128                         return SINGLE_BIT_MAPPING[bits[0].and(t.bits[0]).ordinal()];
129                 return new BitVector(binOp(bits.clone(), t.bits, Bit::and));
130         }
131
132         @Override
133         public BitVector or(BitVector t)
134         {
135                 checkCompatibility(t);
136                 if (bits.length == 1)
137                         return SINGLE_BIT_MAPPING[bits[0].or(t.bits[0]).ordinal()];
138                 return new BitVector(binOp(bits.clone(), t.bits, Bit::or));
139         }
140
141         @Override
142         public BitVector xor(BitVector t)
143         {
144                 checkCompatibility(t);
145                 if (bits.length == 1)
146                         return SINGLE_BIT_MAPPING[bits[0].xor(t.bits[0]).ordinal()];
147                 return new BitVector(binOp(bits.clone(), t.bits, Bit::xor));
148         }
149
150         @Override
151         public BitVector not()
152         {
153                 if (bits.length == 1)
154                         return SINGLE_BIT_MAPPING[bits[0].not().ordinal()];
155                 return new BitVector(unOp(bits.clone(), Bit::not));
156         }
157
158         public int length()
159         {
160                 return bits.length;
161         }
162
163         public BitVector concat(BitVector other)
164         {
165                 Bit[] newBits = Arrays.copyOf(bits, length() + other.length());
166                 System.arraycopy(other.bits, 0, newBits, length(), other.length());
167                 return new BitVector(newBits);
168         }
169
170         public BitVector subVector(int start)
171         {
172                 return new BitVector(Arrays.copyOfRange(bits, start, length()));
173         }
174
175         public BitVector subVector(int start, int end)
176         {
177                 return new BitVector(Arrays.copyOfRange(bits, start, end));
178         }
179
180         private void checkCompatibility(BitVector bv)
181         {
182                 if (length() != bv.length())
183                         throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", length(), bv.length()));
184         }
185
186         static Bit[] binOp(Bit[] dest, Bit[] second, BinaryOperator<Bit> op)
187         {
188                 if (dest == null)
189                         return second.clone();
190                 for (int i = 0; i < dest.length; i++)
191                 {
192                         dest[i] = op.apply(dest[i], second[i]);
193                 }
194                 return dest;
195         }
196
197         static Bit[] unOp(Bit[] dest, UnaryOperator<Bit> op)
198         {
199                 if (dest == null)
200                         return null;
201                 for (int i = 0; i < dest.length; i++)
202                 {
203                         dest[i] = op.apply(dest[i]);
204                 }
205                 return dest;
206         }
207
208         /**
209          * Class for comfortable and efficient manipulation of {@link BitVector}s, similar to {@link StringBuilder}
210          *
211          * @author Christian Femers
212          */
213         public static final class BitVectorMutator implements LogicType<BitVectorMutator, BitVector>
214         {
215                 private Bit[] bits;
216
217                 private BitVectorMutator(Bit[] bits)
218                 {
219                         this.bits = bits;
220                 }
221
222                 static BitVectorMutator of(BitVector bv)
223                 {
224                         return new BitVectorMutator(bv.getBits());
225                 }
226
227                 /**
228                  * Returns a new mutator of the specified length, <b>with all bits set to <code>null</code></b>. Use with care!
229                  */
230                 public static BitVectorMutator ofLength(int length)
231                 {
232                         return new BitVectorMutator(new Bit[length]);
233                 }
234
235                 /**
236                  * Returns an empty mutator which has no bits set and will simply copy the values from the first binary operation performed.
237                  * <p>
238                  * An empty BitVectorMutator <b>must not</b> be converted to BitVector or used to manipulate single bits until at least one two
239                  * operand logic operation is performed.
240                  */
241                 public static BitVectorMutator empty()
242                 {
243                         return new BitVectorMutator(null);
244                 }
245
246                 /**
247                  * @see #empty()
248                  */
249                 public boolean isEmpty()
250                 {
251                         return bits == null;
252                 }
253
254                 /**
255                  * Produces the resulting, immutable {@link BitVector}<br>
256                  * 
257                  * @throws IllegalStateException if the mutator is (still) empty
258                  */
259                 public BitVector toBitVector()
260                 {
261                         if (bits == null)
262                                 throw new IllegalStateException("cannot create a BitVector from an empty mutator");
263                         return new BitVector(bits);
264                 }
265
266                 @Override
267                 public BitVectorMutator join(BitVector t)
268                 {
269                         checkCompatibility(t);
270                         bits = binOp(bits, t.bits, Bit::join);
271                         return this;
272                 }
273
274                 @Override
275                 public BitVectorMutator and(BitVector t)
276                 {
277                         checkCompatibility(t);
278                         bits = binOp(bits, t.bits, Bit::and);
279                         return this;
280                 }
281
282                 @Override
283                 public BitVectorMutator or(BitVector t)
284                 {
285                         checkCompatibility(t);
286                         bits = binOp(bits, t.bits, Bit::or);
287                         return this;
288                 }
289
290                 @Override
291                 public BitVectorMutator xor(BitVector t)
292                 {
293                         checkCompatibility(t);
294                         bits = binOp(bits, t.bits, Bit::xor);
295                         return this;
296                 }
297
298                 @Override
299                 public BitVectorMutator not()
300                 {
301                         unOp(bits, Bit::not);
302                         return this;
303                 }
304
305                 /**
306                  * Set the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
307                  */
308                 public void setMSBit(int bitIndex, Bit bit)
309                 {
310                         if (bits == null)
311                                 throw new IllegalStateException("cannot set a bit of an empty mutator");
312                         bits[bitIndex] = bit;
313                 }
314
315                 /**
316                  * Set the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
317                  */
318                 public void setLSBit(int bitIndex, Bit bit)
319                 {
320                         if (bits == null)
321                                 throw new IllegalStateException("cannot set a bit of an empty mutator");
322                         bits[bits.length - bitIndex - 1] = bit;
323                 }
324
325                 /**
326                  * Returns the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
327                  */
328                 public Bit getMSBit(int bitIndex)
329                 {
330                         if (bits == null)
331                                 throw new IllegalStateException("cannot get a bit of an empty mutator");
332                         return bits[bitIndex];
333                 }
334
335                 /**
336                  * Returns the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
337                  */
338                 public Bit getLSBit(int bitIndex)
339                 {
340                         if (bits == null)
341                                 throw new IllegalStateException("cannot get a bit of an empty mutator");
342                         return bits[bits.length - bitIndex - 1];
343                 }
344
345                 public int length()
346                 {
347                         if (bits == null)
348                                 throw new IllegalStateException("cannot obtain a length of an empty mutator");
349                         return bits.length;
350                 }
351
352                 private void checkCompatibility(BitVector bv)
353                 {
354                         if (bits != null && bits.length != bv.length())
355                                 throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", bits.length, bv.length()));
356                 }
357         }
358
359         /**
360          * @see Arrays#hashCode(Object[])
361          */
362         @Override
363         public int hashCode()
364         {
365                 return Arrays.hashCode(bits);
366         }
367
368         /**
369          * Does test for equality of values/content
370          * 
371          * @see Object#equals(Object)
372          */
373         @Override
374         public boolean equals(Object obj)
375         {
376                 if (this == obj)
377                         return true;
378                 if (!(obj instanceof BitVector))
379                         return false;
380                 BitVector other = (BitVector) obj;
381                 return Arrays.equals(bits, other.bits);
382         }
383
384         /**
385          * Does test for equality of values/content, shifting the other BitVector by <code>offset</code> to the right.<br>
386          * Therefore <code>offset + other.length() <= this.wdith()</code> needs to be true.
387          * 
388          * @throws ArrayIndexOutOfBoundsException if <code>offset + other.length() > this.length()</code>
389          * 
390          * @see Object#equals(Object)
391          */
392         public boolean equalsWithOffset(BitVector other, int offset)
393         {
394                 if (other == null)
395                         return false;
396                 return Arrays.equals(bits, offset, offset + other.length(), other.bits, 0, other.length());
397         }
398
399         /**
400          * All {@link Bit}s symbols concatenated together (MSB first)
401          * 
402          * @see #parse(String)
403          */
404         @Override
405         public String toString()
406         {
407                 StringBuilder sb = new StringBuilder(bits.length);
408                 for (Bit bit : bits)
409                         sb.append(bit);
410                 return sb.toString();
411         }
412
413         /**
414          * Returns the value of the BitVector as BigInteger.
415          * 
416          * @throws NumberFormatException if the BitVector is not {@link #isBinary() binary}.
417          */
418         public BigInteger getUnsignedValue()
419         {
420                 if (!isBinary())
421                         throw new NumberFormatException(this + " is not binary");
422                 byte[] bytes = new byte[(bits.length / 8 + (bits.length % 8 == 0 ? 0 : 1)) + 1];
423                 for (int i = bits.length - 1; i >= 0; i--)
424                 {
425                         if (Bit.ONE == bits[bits.length - i - 1])
426                         {
427                                 try
428                                 {
429                                         bytes[bytes.length - (i / 8) - 1] |= 1 << (i % 8);
430                                 }
431                                 catch (IndexOutOfBoundsException e)
432                                 {
433                                         e.printStackTrace();
434                                 }
435                         }
436                 }
437                 return new BigInteger(bytes);
438         }
439
440         public long getUnsignedValueLong()
441         {
442                 return getUnsignedValue().longValue();
443         }
444
445         /**
446          * Returns the value of the BitVector as BigInteger interpreted as a two's complement number.
447          * 
448          * @throws NumberFormatException if the BitVector is not {@link #isBinary() binary}.
449          * 
450          * @author Daniel Kirschten
451          */
452         public BigInteger getSignedValue()
453         {
454                 BigInteger unsignedValue = getUnsignedValue();
455                 if (bits[bits.length - 1] == Bit.ZERO)
456                         return unsignedValue;
457                 return unsignedValue.subtract(BitVector.of(Bit.ONE, bits.length).getUnsignedValue()).subtract(BigInteger.ONE);// TODO speed this up!
458         }
459
460         public long getSignedValueLong()
461         {
462                 return getSignedValue().longValue();
463         }
464
465         /**
466          * Parses a String containing solely {@link Bit} symbols (MSB first)
467          * 
468          * @see #toString()
469          */
470         public static BitVector parse(String s)
471         {
472                 Bit[] values = new Bit[s.length()];
473                 for (int i = 0; i < s.length(); i++)
474                 {
475                         values[i] = Bit.parse(s, i);
476                 }
477                 return new BitVector(values);
478         }
479
480         /**
481          * Changes a single Bit using the given operation. This can be used to set, clear or flip bits.
482          * 
483          * @param msbIndex           index of the MSB to be changed
484          * @param singleBitOperation the operation to perform on that Bit
485          * @return the resulting, new BitVektor
486          */
487         public BitVector withBitChanged(int msbIndex, UnaryOperator<Bit> singleBitOperation)
488         {
489                 Bit[] newBits = bits.clone();
490                 newBits[msbIndex] = singleBitOperation.apply(newBits[msbIndex]);
491                 return new BitVector(newBits);
492         }
493
494         /**
495          * Iterate over the {@link Bit}s of the BitVector <b>from MSB to LSB</b> (left to right).
496          */
497         @Override
498         public Iterator<Bit> iterator()
499         {
500                 return new Iterator<>()
501                 {
502                         private int pos = 0;
503
504                         @Override
505                         public Bit next()
506                         {
507                                 if (!hasNext())
508                                         throw new NoSuchElementException();
509                                 return getMSBit(pos++);
510                         }
511
512                         @Override
513                         public boolean hasNext()
514                         {
515                                 return pos != length();
516                         }
517                 };
518         }
519
520         public BitVector reverse()
521         {
522                 int length = length();
523                 Bit[] other = new Bit[length];
524                 for (int i = 0, j = length - 1; i < length; i++, j--)
525                 {
526                         other[i] = bits[j];
527                 }
528                 return new BitVector(other);
529         }
530 }