Renamed project folders to match the respective project name
[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         @SuppressWarnings("synthetic-access")
144         public static final class BitVectorMutator implements LogicType<BitVectorMutator, BitVector>
145         {
146                 private Bit[] bits;
147
148                 private BitVectorMutator(Bit[] bits)
149                 {
150                         this.bits = bits;
151                 }
152
153                 static BitVectorMutator of(BitVector bv)
154                 {
155                         return new BitVectorMutator(bv.getBits());
156                 }
157
158                 /**
159                  * Returns an empty mutator which has no bits set and will simply copy the values from the first binary operation performed.
160                  * 
161                  */
162                 public static BitVectorMutator empty()
163                 {
164                         return new BitVectorMutator(null);
165                 }
166
167                 /**
168                  * Produces the resulting, immutable {@link BitVector}<br>
169                  * 
170                  * @throws IllegalStateException if the mutator is (still) empty
171                  */
172                 public BitVector get()
173                 {
174                         if (bits == null)
175                                 throw new IllegalStateException("cannot create a BitVector from an empty mutator");
176                         return new BitVector(bits);
177                 }
178
179                 @Override
180                 public BitVectorMutator join(BitVector t)
181                 {
182                         checkCompatibility(t);
183                         bits = binOp(bits, t.bits, Bit::join);
184                         return this;
185                 }
186
187                 @Override
188                 public BitVectorMutator and(BitVector t)
189                 {
190                         checkCompatibility(t);
191                         bits = binOp(bits, t.bits, Bit::and);
192                         return this;
193                 }
194
195                 @Override
196                 public BitVectorMutator or(BitVector t)
197                 {
198                         checkCompatibility(t);
199                         bits = binOp(bits, t.bits, Bit::or);
200                         return this;
201                 }
202
203                 @Override
204                 public BitVectorMutator xor(BitVector t)
205                 {
206                         checkCompatibility(t);
207                         bits = binOp(bits, t.bits, Bit::xor);
208                         return this;
209                 }
210
211                 @Override
212                 public BitVectorMutator not()
213                 {
214                         unOp(bits, Bit::not);
215                         return this;
216                 }
217
218                 private void checkCompatibility(BitVector bv)
219                 {
220                         if (bits != null && bits.length != bv.length())
221                                 throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", bits.length, bv.length()));
222                 }
223         }
224
225         /**
226          * @see Arrays#hashCode(Object[])
227          */
228         @Override
229         public int hashCode()
230         {
231                 return Arrays.hashCode(bits);
232         }
233
234         /**
235          * Does test for equality of values/content
236          * 
237          * @see Object#equals(Object)
238          */
239         @Override
240         public boolean equals(Object obj)
241         {
242                 if (this == obj)
243                         return true;
244                 if (!(obj instanceof BitVector))
245                         return false;
246                 BitVector other = (BitVector) obj;
247                 return Arrays.equals(bits, other.bits);
248         }
249
250         /**
251          * Does test for equality of values/content, shifting the other BitVector by <code>offset</code> to the right.<br>
252          * Therefore <code>offset + other.length() <= this.length()</code> needs to be true.
253          * 
254          * @throws ArrayIndexOutOfBoundsException if <code>offset + other.length() > this.length()</code>
255          * 
256          * @see Object#equals(Object)
257          */
258         public boolean equalsWithOffset(BitVector other, int offset)
259         {
260                 if (other == null)
261                         return false;
262                 return Arrays.equals(bits, offset, offset + other.length(), other.bits, 0, other.length());
263         }
264
265         /**
266          * All {@link Bit}s symbols concatenated together
267          * 
268          * @see #parse(String)
269          */
270         @Override
271         public String toString()
272         {
273                 StringBuilder sb = new StringBuilder(bits.length);
274                 for (Bit bit : bits)
275                         sb.append(bit);
276                 return sb.toString();
277         }
278
279         /**
280          * Parses a String containing solely {@link Bit} symbols
281          * 
282          * @see #toString()
283          */
284         public static BitVector parse(String s)
285         {
286                 Bit[] values = new Bit[s.length()];
287                 for (int i = 0; i < s.length(); i++)
288                 {
289                         values[i] = Bit.parse(s, i);
290                 }
291                 return new BitVector(values);
292         }
293
294         @Override
295         public Iterator<Bit> iterator()
296         {
297                 return new Iterator<>()
298                 {
299                         private int pos = 0;
300
301                         @Override
302                         public Bit next()
303                         {
304                                 if (!hasNext())
305                                         throw new NoSuchElementException();
306                                 return getBit(pos++);
307                         }
308
309                         @Override
310                         public boolean hasNext()
311                         {
312                                 return pos != length();
313                         }
314                 };
315         }
316 }