base-stemmer.js - sphere - GPU-based 3D discrete element method algorithm with optional fluid coupling
HTML git clone git://src.adamsgaard.dk/sphere
DIR Log
DIR Files
DIR Refs
DIR LICENSE
---
base-stemmer.js (12250B)
---
1 // @ts-check
2
3 /**@constructor*/
4 BaseStemmer = function() {
5 /** @protected */
6 this.current = '';
7 this.cursor = 0;
8 this.limit = 0;
9 this.limit_backward = 0;
10 this.bra = 0;
11 this.ket = 0;
12
13 /**
14 * @param {string} value
15 */
16 this.setCurrent = function(value) {
17 this.current = value;
18 this.cursor = 0;
19 this.limit = this.current.length;
20 this.limit_backward = 0;
21 this.bra = this.cursor;
22 this.ket = this.limit;
23 };
24
25 /**
26 * @return {string}
27 */
28 this.getCurrent = function() {
29 return this.current;
30 };
31
32 /**
33 * @param {BaseStemmer} other
34 */
35 this.copy_from = function(other) {
36 /** @protected */
37 this.current = other.current;
38 this.cursor = other.cursor;
39 this.limit = other.limit;
40 this.limit_backward = other.limit_backward;
41 this.bra = other.bra;
42 this.ket = other.ket;
43 };
44
45 /**
46 * @param {number[]} s
47 * @param {number} min
48 * @param {number} max
49 * @return {boolean}
50 */
51 this.in_grouping = function(s, min, max) {
52 /** @protected */
53 if (this.cursor >= this.limit) return false;
54 var ch = this.current.charCodeAt(this.cursor);
55 if (ch > max || ch < min) return false;
56 ch -= min;
57 if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) == 0) return false;
58 this.cursor++;
59 return true;
60 };
61
62 /**
63 * @param {number[]} s
64 * @param {number} min
65 * @param {number} max
66 * @return {boolean}
67 */
68 this.go_in_grouping = function(s, min, max) {
69 /** @protected */
70 while (this.cursor < this.limit) {
71 var ch = this.current.charCodeAt(this.cursor);
72 if (ch > max || ch < min)
73 return true;
74 ch -= min;
75 if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) == 0)
76 return true;
77 this.cursor++;
78 }
79 return false;
80 };
81
82 /**
83 * @param {number[]} s
84 * @param {number} min
85 * @param {number} max
86 * @return {boolean}
87 */
88 this.in_grouping_b = function(s, min, max) {
89 /** @protected */
90 if (this.cursor <= this.limit_backward) return false;
91 var ch = this.current.charCodeAt(this.cursor - 1);
92 if (ch > max || ch < min) return false;
93 ch -= min;
94 if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) == 0) return false;
95 this.cursor--;
96 return true;
97 };
98
99 /**
100 * @param {number[]} s
101 * @param {number} min
102 * @param {number} max
103 * @return {boolean}
104 */
105 this.go_in_grouping_b = function(s, min, max) {
106 /** @protected */
107 while (this.cursor > this.limit_backward) {
108 var ch = this.current.charCodeAt(this.cursor - 1);
109 if (ch > max || ch < min) return true;
110 ch -= min;
111 if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) == 0) return true;
112 this.cursor--;
113 }
114 return false;
115 };
116
117 /**
118 * @param {number[]} s
119 * @param {number} min
120 * @param {number} max
121 * @return {boolean}
122 */
123 this.out_grouping = function(s, min, max) {
124 /** @protected */
125 if (this.cursor >= this.limit) return false;
126 var ch = this.current.charCodeAt(this.cursor);
127 if (ch > max || ch < min) {
128 this.cursor++;
129 return true;
130 }
131 ch -= min;
132 if ((s[ch >>> 3] & (0X1 << (ch & 0x7))) == 0) {
133 this.cursor++;
134 return true;
135 }
136 return false;
137 };
138
139 /**
140 * @param {number[]} s
141 * @param {number} min
142 * @param {number} max
143 * @return {boolean}
144 */
145 this.go_out_grouping = function(s, min, max) {
146 /** @protected */
147 while (this.cursor < this.limit) {
148 var ch = this.current.charCodeAt(this.cursor);
149 if (ch <= max && ch >= min) {
150 ch -= min;
151 if ((s[ch >>> 3] & (0X1 << (ch & 0x7))) != 0) {
152 return true;
153 }
154 }
155 this.cursor++;
156 }
157 return false;
158 };
159
160 /**
161 * @param {number[]} s
162 * @param {number} min
163 * @param {number} max
164 * @return {boolean}
165 */
166 this.out_grouping_b = function(s, min, max) {
167 /** @protected */
168 if (this.cursor <= this.limit_backward) return false;
169 var ch = this.current.charCodeAt(this.cursor - 1);
170 if (ch > max || ch < min) {
171 this.cursor--;
172 return true;
173 }
174 ch -= min;
175 if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) == 0) {
176 this.cursor--;
177 return true;
178 }
179 return false;
180 };
181
182 /**
183 * @param {number[]} s
184 * @param {number} min
185 * @param {number} max
186 * @return {boolean}
187 */
188 this.go_out_grouping_b = function(s, min, max) {
189 /** @protected */
190 while (this.cursor > this.limit_backward) {
191 var ch = this.current.charCodeAt(this.cursor - 1);
192 if (ch <= max && ch >= min) {
193 ch -= min;
194 if ((s[ch >>> 3] & (0x1 << (ch & 0x7))) != 0) {
195 return true;
196 }
197 }
198 this.cursor--;
199 }
200 return false;
201 };
202
203 /**
204 * @param {string} s
205 * @return {boolean}
206 */
207 this.eq_s = function(s)
208 {
209 /** @protected */
210 if (this.limit - this.cursor < s.length) return false;
211 if (this.current.slice(this.cursor, this.cursor + s.length) != s)
212 {
213 return false;
214 }
215 this.cursor += s.length;
216 return true;
217 };
218
219 /**
220 * @param {string} s
221 * @return {boolean}
222 */
223 this.eq_s_b = function(s)
224 {
225 /** @protected */
226 if (this.cursor - this.limit_backward < s.length) return false;
227 if (this.current.slice(this.cursor - s.length, this.cursor) != s)
228 {
229 return false;
230 }
231 this.cursor -= s.length;
232 return true;
233 };
234
235 /**
236 * @param {Among[]} v
237 * @return {number}
238 */
239 this.find_among = function(v)
240 {
241 /** @protected */
242 var i = 0;
243 var j = v.length;
244
245 var c = this.cursor;
246 var l = this.limit;
247
248 var common_i = 0;
249 var common_j = 0;
250
251 var first_key_inspected = false;
252
253 while (true)
254 {
255 var k = i + ((j - i) >>> 1);
256 var diff = 0;
257 var common = common_i < common_j ? common_i : common_j; // smaller
258 // w[0]: string, w[1]: substring_i, w[2]: result, w[3]: function (optional)
259 var w = v[k];
260 var i2;
261 for (i2 = common; i2 < w[0].length; i2++)
262 {
263 if (c + common == l)
264 {
265 diff = -1;
266 break;
267 }
268 diff = this.current.charCodeAt(c + common) - w[0].charCodeAt(i2);
269 if (diff != 0) break;
270 common++;
271 }
272 if (diff < 0)
273 {
274 j = k;
275 common_j = common;
276 }
277 else
278 {
279 i = k;
280 common_i = common;
281 }
282 if (j - i <= 1)
283 {
284 if (i > 0) break; // v->s has been inspected
285 if (j == i) break; // only one item in v
286
287 // - but now we need to go round once more to get
288 // v->s inspected. This looks messy, but is actually
289 // the optimal approach.
290
291 if (first_key_inspected) break;
292 first_key_inspected = true;
293 }
294 }
295 do {
296 var w = v[i];
297 if (common_i >= w[0].length)
298 {
299 this.cursor = c + w[0].length;
300 if (w.length < 4) return w[2];
301 var res = w[3](this);
302 this.cursor = c + w[0].length;
303 if (res) return w[2];
304 }
305 i = w[1];
306 } while (i >= 0);
307 return 0;
308 };
309
310 // find_among_b is for backwards processing. Same comments apply
311 /**
312 * @param {Among[]} v
313 * @return {number}
314 */
315 this.find_among_b = function(v)
316 {
317 /** @protected */
318 var i = 0;
319 var j = v.length
320
321 var c = this.cursor;
322 var lb = this.limit_backward;
323
324 var common_i = 0;
325 var common_j = 0;
326
327 var first_key_inspected = false;
328
329 while (true)
330 {
331 var k = i + ((j - i) >> 1);
332 var diff = 0;
333 var common = common_i < common_j ? common_i : common_j;
334 var w = v[k];
335 var i2;
336 for (i2 = w[0].length - 1 - common; i2 >= 0; i2--)
337 {
338 if (c - common == lb)
339 {
340 diff = -1;
341 break;
342 }
343 diff = this.current.charCodeAt(c - 1 - common) - w[0].charCodeAt(i2);
344 if (diff != 0) break;
345 common++;
346 }
347 if (diff < 0)
348 {
349 j = k;
350 common_j = common;
351 }
352 else
353 {
354 i = k;
355 common_i = common;
356 }
357 if (j - i <= 1)
358 {
359 if (i > 0) break;
360 if (j == i) break;
361 if (first_key_inspected) break;
362 first_key_inspected = true;
363 }
364 }
365 do {
366 var w = v[i];
367 if (common_i >= w[0].length)
368 {
369 this.cursor = c - w[0].length;
370 if (w.length < 4) return w[2];
371 var res = w[3](this);
372 this.cursor = c - w[0].length;
373 if (res) return w[2];
374 }
375 i = w[1];
376 } while (i >= 0);
377 return 0;
378 };
379
380 /* to replace chars between c_bra and c_ket in this.current by the
381 * chars in s.
382 */
383 /**
384 * @param {number} c_bra
385 * @param {number} c_ket
386 * @param {string} s
387 * @return {number}
388 */
389 this.replace_s = function(c_bra, c_ket, s)
390 {
391 /** @protected */
392 var adjustment = s.length - (c_ket - c_bra);
393 this.current = this.current.slice(0, c_bra) + s + this.current.slice(c_ket);
394 this.limit += adjustment;
395 if (this.cursor >= c_ket) this.cursor += adjustment;
396 else if (this.cursor > c_bra) this.cursor = c_bra;
397 return adjustment;
398 };
399
400 /**
401 * @return {boolean}
402 */
403 this.slice_check = function()
404 {
405 /** @protected */
406 if (this.bra < 0 ||
407 this.bra > this.ket ||
408 this.ket > this.limit ||
409 this.limit > this.current.length)
410 {
411 return false;
412 }
413 return true;
414 };
415
416 /**
417 * @param {number} c_bra
418 * @return {boolean}
419 */
420 this.slice_from = function(s)
421 {
422 /** @protected */
423 var result = false;
424 if (this.slice_check())
425 {
426 this.replace_s(this.bra, this.ket, s);
427 result = true;
428 }
429 return result;
430 };
431
432 /**
433 * @return {boolean}
434 */
435 this.slice_del = function()
436 {
437 /** @protected */
438 return this.slice_from("");
439 };
440
441 /**
442 * @param {number} c_bra
443 * @param {number} c_ket
444 * @param {string} s
445 */
446 this.insert = function(c_bra, c_ket, s)
447 {
448 /** @protected */
449 var adjustment = this.replace_s(c_bra, c_ket, s);
450 if (c_bra <= this.bra) this.bra += adjustment;
451 if (c_bra <= this.ket) this.ket += adjustment;
452 };
453
454 /**
455 * @return {string}
456 */
457 this.slice_to = function()
458 {
459 /** @protected */
460 var result = '';
461 if (this.slice_check())
462 {
463 result = this.current.slice(this.bra, this.ket);
464 }
465 return result;
466 };
467
468 /**
469 * @return {string}
470 */
471 this.assign_to = function()
472 {
473 /** @protected */
474 return this.current.slice(0, this.limit);
475 };
476 };