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