Refactored BitVector methods to resolve ambiguity
[Mograsim.git] / 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.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;
12
13 /**
14  * Immutable class representing a {@link Bit}Vector
15  *
16  * @author Christian Femers
17  *
18  */
19 public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit>, RandomAccess
20 {
21         private final Bit[] bits;
22
23         private BitVector(Bit[] bits)
24         {
25                 this.bits = Objects.requireNonNull(bits); // do this first to "catch" bits==null before the foreach loop
26                 for (Bit bit : bits)
27                         if (bit == null)
28                                 throw new NullPointerException();
29         }
30
31         public static BitVector of(Bit... bits)
32         {
33                 return new BitVector(bits.clone());
34         }
35
36         public static BitVector of(Bit bit, int length)
37         {
38                 return new BitVector(bit.makeArray(length));
39         }
40
41         public BitVectorMutator mutator()
42         {
43                 return BitVectorMutator.of(this);
44         }
45
46         /**
47          * Returns the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
48          */
49         public Bit getMSBit(int bitIndex)
50         {
51                 return bits[bitIndex];
52         }
53
54         /**
55          * Returns the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
56          */
57         public Bit getLSBit(int bitIndex)
58         {
59                 return bits[bits.length - bitIndex - 1];
60         }
61
62         public Bit[] getBits()
63         {
64                 return bits.clone();
65         }
66
67         @Override
68         public BitVector join(BitVector t)
69         {
70                 checkCompatibility(t);
71                 return new BitVector(binOp(bits.clone(), t.bits, Bit::join));
72         }
73
74         @Override
75         public BitVector and(BitVector t)
76         {
77                 checkCompatibility(t);
78                 return new BitVector(binOp(bits.clone(), t.bits, Bit::and));
79         }
80
81         @Override
82         public BitVector or(BitVector t)
83         {
84                 checkCompatibility(t);
85                 return new BitVector(binOp(bits.clone(), t.bits, Bit::or));
86         }
87
88         @Override
89         public BitVector xor(BitVector t)
90         {
91                 checkCompatibility(t);
92                 return new BitVector(binOp(bits.clone(), t.bits, Bit::xor));
93         }
94
95         @Override
96         public BitVector not()
97         {
98                 return new BitVector(unOp(bits.clone(), Bit::not));
99         }
100
101         public int length()
102         {
103                 return bits.length;
104         }
105
106         public BitVector concat(BitVector other)
107         {
108                 Bit[] newBits = Arrays.copyOf(bits, length() + other.length());
109                 System.arraycopy(other.bits, 0, newBits, length(), other.length());
110                 return new BitVector(newBits);
111         }
112
113         public BitVector subVector(int start)
114         {
115                 return new BitVector(Arrays.copyOfRange(bits, start, length()));
116         }
117
118         public BitVector subVector(int start, int end)
119         {
120                 return new BitVector(Arrays.copyOfRange(bits, start, end));
121         }
122
123         private void checkCompatibility(BitVector bv)
124         {
125                 if (length() != bv.length())
126                         throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", length(), bv.length()));
127         }
128
129         static Bit[] binOp(Bit[] dest, Bit[] second, BinaryOperator<Bit> op)
130         {
131                 if (dest == null)
132                         return second.clone();
133                 for (int i = 0; i < dest.length; i++)
134                 {
135                         dest[i] = op.apply(dest[i], second[i]);
136                 }
137                 return dest;
138         }
139
140         static Bit[] unOp(Bit[] dest, UnaryOperator<Bit> op)
141         {
142                 if (dest == null)
143                         return null;
144                 for (int i = 0; i < dest.length; i++)
145                 {
146                         dest[i] = op.apply(dest[i]);
147                 }
148                 return dest;
149         }
150
151         /**
152          * Class for comfortable and efficient manipulation of {@link BitVector}s, similar to {@link StringBuilder}
153          *
154          * @author Christian Femers
155          */
156         public static final class BitVectorMutator implements LogicType<BitVectorMutator, BitVector>
157         {
158                 private Bit[] bits;
159
160                 private BitVectorMutator(Bit[] bits)
161                 {
162                         this.bits = bits;
163                 }
164
165                 static BitVectorMutator of(BitVector bv)
166                 {
167                         return new BitVectorMutator(bv.getBits());
168                 }
169
170                 /**
171                  * Returns a new mutator of the specified length, <b>with all bits set to <code>null</code></b>. Use with care!
172                  */
173                 public static BitVectorMutator ofLength(int length)
174                 {
175                         return new BitVectorMutator(new Bit[length]);
176                 }
177
178                 /**
179                  * Returns an empty mutator which has no bits set and will simply copy the values from the first binary operation performed.
180                  */
181                 public static BitVectorMutator empty()
182                 {
183                         return new BitVectorMutator(null);
184                 }
185
186                 /**
187                  * Produces the resulting, immutable {@link BitVector}<br>
188                  * 
189                  * @throws IllegalStateException if the mutator is (still) empty
190                  */
191                 public BitVector toBitVector()
192                 {
193                         if (bits == null)
194                                 throw new IllegalStateException("cannot create a BitVector from an empty mutator");
195                         return new BitVector(bits);
196                 }
197
198                 @Override
199                 public BitVectorMutator join(BitVector t)
200                 {
201                         checkCompatibility(t);
202                         bits = binOp(bits, t.bits, Bit::join);
203                         return this;
204                 }
205
206                 @Override
207                 public BitVectorMutator and(BitVector t)
208                 {
209                         checkCompatibility(t);
210                         bits = binOp(bits, t.bits, Bit::and);
211                         return this;
212                 }
213
214                 @Override
215                 public BitVectorMutator or(BitVector t)
216                 {
217                         checkCompatibility(t);
218                         bits = binOp(bits, t.bits, Bit::or);
219                         return this;
220                 }
221
222                 @Override
223                 public BitVectorMutator xor(BitVector t)
224                 {
225                         checkCompatibility(t);
226                         bits = binOp(bits, t.bits, Bit::xor);
227                         return this;
228                 }
229
230                 @Override
231                 public BitVectorMutator not()
232                 {
233                         unOp(bits, Bit::not);
234                         return this;
235                 }
236
237                 /**
238                  * Set the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
239                  */
240                 public void setMSBit(int bitIndex, Bit bit)
241                 {
242                         bits[bitIndex] = bit;
243                 }
244
245                 /**
246                  * Set the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
247                  */
248                 public void setLSBit(int bitIndex, Bit bit)
249                 {
250                         bits[bits.length - bitIndex - 1] = bit;
251                 }
252
253                 /**
254                  * Returns the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
255                  */
256                 public Bit getMSBit(int bitIndex)
257                 {
258                         return bits[bitIndex];
259                 }
260
261                 /**
262                  * Returns the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
263                  */
264                 public Bit getLSBit(int bitIndex)
265                 {
266                         return bits[bits.length - bitIndex - 1];
267                 }
268
269                 public int length()
270                 {
271                         return bits.length;
272                 }
273
274                 private void checkCompatibility(BitVector bv)
275                 {
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()));
278                 }
279         }
280
281         /**
282          * @see Arrays#hashCode(Object[])
283          */
284         @Override
285         public int hashCode()
286         {
287                 return Arrays.hashCode(bits);
288         }
289
290         /**
291          * Does test for equality of values/content
292          * 
293          * @see Object#equals(Object)
294          */
295         @Override
296         public boolean equals(Object obj)
297         {
298                 if (this == obj)
299                         return true;
300                 if (!(obj instanceof BitVector))
301                         return false;
302                 BitVector other = (BitVector) obj;
303                 return Arrays.equals(bits, other.bits);
304         }
305
306         /**
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.
309          * 
310          * @throws ArrayIndexOutOfBoundsException if <code>offset + other.length() > this.length()</code>
311          * 
312          * @see Object#equals(Object)
313          */
314         public boolean equalsWithOffset(BitVector other, int offset)
315         {
316                 if (other == null)
317                         return false;
318                 return Arrays.equals(bits, offset, offset + other.length(), other.bits, 0, other.length());
319         }
320
321         /**
322          * All {@link Bit}s symbols concatenated together (MSB first)
323          * 
324          * @see #parse(String)
325          */
326         @Override
327         public String toString()
328         {
329                 StringBuilder sb = new StringBuilder(bits.length);
330                 for (Bit bit : bits)
331                         sb.append(bit);
332                 return sb.toString();
333         }
334
335         /**
336          * Parses a String containing solely {@link Bit} symbols (MSB first)
337          * 
338          * @see #toString()
339          */
340         public static BitVector parse(String s)
341         {
342                 Bit[] values = new Bit[s.length()];
343                 for (int i = 0; i < s.length(); i++)
344                 {
345                         values[i] = Bit.parse(s, i);
346                 }
347                 return new BitVector(values);
348         }
349
350         /**
351          * Iterate over the {@link Bit}s of the BitVector <b>from MSB to LSB</b> (left to right).
352          */
353         @Override
354         public Iterator<Bit> iterator()
355         {
356                 return new Iterator<>()
357                 {
358                         private int pos = 0;
359
360                         @Override
361                         public Bit next()
362                         {
363                                 if (!hasNext())
364                                         throw new NoSuchElementException();
365                                 return getMSBit(pos++);
366                         }
367
368                         @Override
369                         public boolean hasNext()
370                         {
371                                 return pos != length();
372                         }
373                 };
374         }
375 }