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