1
2
3
4
5
6 package io.github.olyutorskii.aletojio.emergence;
7
8 import java.util.Arrays;
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 public class EfMsSeq {
28
29 private static final int PRIMLEN = Long.SIZE;
30 private static final int INIT_VECLEN = 2;
31 private static final int GROWTH_RATE = 2;
32
33
34 private long[] vec;
35 private int capacity;
36
37 private int bitLength;
38
39
40
41
42
43
44
45 public EfMsSeq() {
46 super();
47
48 this.vec = new long[INIT_VECLEN];
49 this.capacity = PRIMLEN * this.vec.length;
50 this.bitLength = 0;
51
52 return;
53 }
54
55
56
57
58
59
60 public int length() {
61 return this.bitLength;
62 }
63
64
65
66
67
68
69 private void ensureCapacity(int minCapacity) {
70 if (minCapacity <= this.capacity) {
71 return;
72 }
73
74 int newArraySize = this.vec.length * GROWTH_RATE;
75 while (PRIMLEN * newArraySize < minCapacity) {
76 newArraySize *= GROWTH_RATE;
77 }
78
79 this.vec = Arrays.copyOf(this.vec, newArraySize);
80
81 this.capacity = PRIMLEN * this.vec.length;
82
83 return;
84 }
85
86
87
88
89
90
91 public void append(int iVal) {
92 int newLength = this.bitLength + 1;
93 ensureCapacity(newLength);
94
95 if (iVal != 0) {
96 int vecIdx = this.bitLength / PRIMLEN;
97 int bitPos = this.bitLength % PRIMLEN;
98 this.vec[vecIdx] |= 1L << bitPos;
99 }
100
101 this.bitLength = newLength;
102
103 return;
104 }
105
106
107
108
109
110
111 public void append(int... iVals) {
112 ensureCapacity(this.bitLength + iVals.length);
113
114 for (int iVal : iVals) {
115 append(iVal);
116 }
117
118 return;
119 }
120
121
122
123
124
125
126
127
128
129
130
131 public int get(int idx) throws IndexOutOfBoundsException {
132 if (idx >= this.bitLength || idx < 0) {
133 throw new IndexOutOfBoundsException();
134 }
135
136 int vecIdx = idx / PRIMLEN;
137 int bitPos = idx % PRIMLEN;
138
139 long lVal = this.vec[vecIdx];
140 lVal = (lVal >> bitPos) & 1L;
141
142 return (int) lVal;
143 }
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161 public int lastIdxSuffix(int suffixIdx) throws IndexOutOfBoundsException {
162 if (suffixIdx <= 0) throw new IndexOutOfBoundsException();
163 if (suffixIdx >= this.bitLength) throw new IndexOutOfBoundsException();
164
165 int suffixLen = this.bitLength - suffixIdx;
166 int revStart = this.bitLength - suffixLen - 1;
167
168 assert suffixLen > 0;
169 assert revStart >= 0;
170 assert revStart < this.bitLength - 1;
171
172 int lastIdx = -1;
173
174 for (int seqRevIdx = revStart; seqRevIdx >= 0; seqRevIdx--) {
175 boolean suffixMatched = true;
176
177 for (int offset = 0; offset < suffixLen; offset++) {
178 int bitSeq = get(seqRevIdx + offset);
179 int bitSfx = get(suffixIdx + offset);
180 if (bitSeq != bitSfx) {
181 suffixMatched = false;
182 break;
183 }
184 }
185
186 if (suffixMatched) {
187 lastIdx = seqRevIdx;
188 break;
189 }
190 }
191
192 return lastIdx;
193 }
194
195
196
197
198
199
200
201 public int nextBool()
202 throws NullPointerException {
203 int targetLen = length();
204 if (targetLen <= 0) return 0;
205
206 int suffixNext = -1;
207
208 for (int suffixIdx = 1; suffixIdx < targetLen; suffixIdx++) {
209 int matchedPos = lastIdxSuffix(suffixIdx);
210 if (matchedPos >= 0) {
211 int suffixLen = targetLen - suffixIdx;
212 suffixNext = matchedPos + suffixLen;
213 break;
214 }
215 }
216
217 int resultPos;
218 if (suffixNext >= 0) resultPos = suffixNext;
219 else resultPos = length() - 1;
220
221 int resultNeg;
222 if (get(resultPos) == 0) resultNeg = 1;
223 else resultNeg = 0;
224
225 return resultNeg;
226 }
227
228
229
230
231
232
233 @Override
234 public int hashCode() {
235 long lVal1st = 0xdeadbeefaa554321L;
236 long lValLast = 0x1234aa55cafebabeL;
237 if (this.bitLength >= 1) {
238 int vecs = (this.bitLength - 1) / PRIMLEN + 1;
239 lVal1st ^= this.vec[0] * 23;
240 lValLast ^= this.vec[vecs - 1] * 29;
241 }
242 long lVal = lVal1st ^ lValLast;
243
244 int result = 0;
245 result ^= (int) lVal;
246 result ^= (int) (lVal >>> 32);
247
248 return result;
249 }
250
251
252
253
254
255
256
257 @Override
258 public boolean equals(Object obj) {
259 if (this == obj) {
260 return true;
261 }
262
263 if (!(obj instanceof EfMsSeq)) {
264 return false;
265 }
266 EfMsSeq other = (EfMsSeq) obj;
267
268 if (this.bitLength != other.bitLength) {
269 return false;
270 }
271
272 boolean result = Arrays.equals(this.vec, other.vec);
273 return result;
274 }
275
276
277
278
279
280
281
282
283 @Override
284 public String toString() {
285 if (this.bitLength <= 0) return "nil";
286
287 StringBuilder result = new StringBuilder();
288 result.ensureCapacity(this.bitLength);
289
290 for (int bitIdx = 0; bitIdx < this.bitLength; bitIdx++) {
291 char ch;
292 if (get(bitIdx) == 0) ch = '0';
293 else ch = '1';
294 result.append(ch);
295 }
296
297 return result.toString();
298 }
299
300 }