Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libdivsufsort/lib/sssort.c
39483 views
1
/*
2
* sssort.c for libdivsufsort
3
* Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.
4
*
5
* Permission is hereby granted, free of charge, to any person
6
* obtaining a copy of this software and associated documentation
7
* files (the "Software"), to deal in the Software without
8
* restriction, including without limitation the rights to use,
9
* copy, modify, merge, publish, distribute, sublicense, and/or sell
10
* copies of the Software, and to permit persons to whom the
11
* Software is furnished to do so, subject to the following
12
* conditions:
13
*
14
* The above copyright notice and this permission notice shall be
15
* included in all copies or substantial portions of the Software.
16
*
17
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
* OTHER DEALINGS IN THE SOFTWARE.
25
*/
26
27
#include "divsufsort_private.h"
28
29
30
/*- Private Functions -*/
31
32
static const saint_t lg_table[256]= {
33
-1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
34
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
35
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
36
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
37
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
38
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
39
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
40
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
41
};
42
43
#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE)
44
45
static INLINE
46
saint_t
47
ss_ilg(saidx_t n) {
48
#if SS_BLOCKSIZE == 0
49
# if defined(BUILD_DIVSUFSORT64)
50
return (n >> 32) ?
51
((n >> 48) ?
52
((n >> 56) ?
53
56 + lg_table[(n >> 56) & 0xff] :
54
48 + lg_table[(n >> 48) & 0xff]) :
55
((n >> 40) ?
56
40 + lg_table[(n >> 40) & 0xff] :
57
32 + lg_table[(n >> 32) & 0xff])) :
58
((n & 0xffff0000) ?
59
((n & 0xff000000) ?
60
24 + lg_table[(n >> 24) & 0xff] :
61
16 + lg_table[(n >> 16) & 0xff]) :
62
((n & 0x0000ff00) ?
63
8 + lg_table[(n >> 8) & 0xff] :
64
0 + lg_table[(n >> 0) & 0xff]));
65
# else
66
return (n & 0xffff0000) ?
67
((n & 0xff000000) ?
68
24 + lg_table[(n >> 24) & 0xff] :
69
16 + lg_table[(n >> 16) & 0xff]) :
70
((n & 0x0000ff00) ?
71
8 + lg_table[(n >> 8) & 0xff] :
72
0 + lg_table[(n >> 0) & 0xff]);
73
# endif
74
#elif SS_BLOCKSIZE < 256
75
return lg_table[n];
76
#else
77
return (n & 0xff00) ?
78
8 + lg_table[(n >> 8) & 0xff] :
79
0 + lg_table[(n >> 0) & 0xff];
80
#endif
81
}
82
83
#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */
84
85
#if SS_BLOCKSIZE != 0
86
87
static const saint_t sqq_table[256] = {
88
0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57, 59, 61,
89
64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83, 84, 86, 87, 89,
90
90, 91, 93, 94, 96, 97, 98, 99, 101, 102, 103, 104, 106, 107, 108, 109,
91
110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
92
128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
93
143, 144, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155,
94
156, 157, 158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168,
95
169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178, 179, 180,
96
181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 191,
97
192, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201,
98
202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211,
99
212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 221,
100
221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230,
101
230, 231, 231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238,
102
239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247,
103
247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255
104
};
105
106
static INLINE
107
saidx_t
108
ss_isqrt(saidx_t x) {
109
saidx_t y, e;
110
111
if(x >= (SS_BLOCKSIZE * SS_BLOCKSIZE)) { return SS_BLOCKSIZE; }
112
e = (x & 0xffff0000) ?
113
((x & 0xff000000) ?
114
24 + lg_table[(x >> 24) & 0xff] :
115
16 + lg_table[(x >> 16) & 0xff]) :
116
((x & 0x0000ff00) ?
117
8 + lg_table[(x >> 8) & 0xff] :
118
0 + lg_table[(x >> 0) & 0xff]);
119
120
if(e >= 16) {
121
y = sqq_table[x >> ((e - 6) - (e & 1))] << ((e >> 1) - 7);
122
if(e >= 24) { y = (y + 1 + x / y) >> 1; }
123
y = (y + 1 + x / y) >> 1;
124
} else if(e >= 8) {
125
y = (sqq_table[x >> ((e - 6) - (e & 1))] >> (7 - (e >> 1))) + 1;
126
} else {
127
return sqq_table[x] >> 4;
128
}
129
130
return (x < (y * y)) ? y - 1 : y;
131
}
132
133
#endif /* SS_BLOCKSIZE != 0 */
134
135
136
/*---------------------------------------------------------------------------*/
137
138
/* Compares two suffixes. */
139
static INLINE
140
saint_t
141
ss_compare(const sauchar_t *T,
142
const saidx_t *p1, const saidx_t *p2,
143
saidx_t depth) {
144
const sauchar_t *U1, *U2, *U1n, *U2n;
145
146
for(U1 = T + depth + *p1,
147
U2 = T + depth + *p2,
148
U1n = T + *(p1 + 1) + 2,
149
U2n = T + *(p2 + 1) + 2;
150
(U1 < U1n) && (U2 < U2n) && (*U1 == *U2);
151
++U1, ++U2) {
152
}
153
154
return U1 < U1n ?
155
(U2 < U2n ? *U1 - *U2 : 1) :
156
(U2 < U2n ? -1 : 0);
157
}
158
159
160
/*---------------------------------------------------------------------------*/
161
162
#if (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1)
163
164
/* Insertionsort for small size groups */
165
static
166
void
167
ss_insertionsort(const sauchar_t *T, const saidx_t *PA,
168
saidx_t *first, saidx_t *last, saidx_t depth) {
169
saidx_t *i, *j;
170
saidx_t t;
171
saint_t r;
172
173
for(i = last - 2; first <= i; --i) {
174
for(t = *i, j = i + 1; 0 < (r = ss_compare(T, PA + t, PA + *j, depth));) {
175
do { *(j - 1) = *j; } while((++j < last) && (*j < 0));
176
if(last <= j) { break; }
177
}
178
if(r == 0) { *j = ~*j; }
179
*(j - 1) = t;
180
}
181
}
182
183
#endif /* (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) */
184
185
186
/*---------------------------------------------------------------------------*/
187
188
#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE)
189
190
static INLINE
191
void
192
ss_fixdown(const sauchar_t *Td, const saidx_t *PA,
193
saidx_t *SA, saidx_t i, saidx_t size) {
194
saidx_t j, k;
195
saidx_t v;
196
saint_t c, d, e;
197
198
for(v = SA[i], c = Td[PA[v]]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) {
199
d = Td[PA[SA[k = j++]]];
200
if(d < (e = Td[PA[SA[j]]])) { k = j; d = e; }
201
if(d <= c) { break; }
202
}
203
SA[i] = v;
204
}
205
206
/* Simple top-down heapsort. */
207
static
208
void
209
ss_heapsort(const sauchar_t *Td, const saidx_t *PA, saidx_t *SA, saidx_t size) {
210
saidx_t i, m;
211
saidx_t t;
212
213
m = size;
214
if((size % 2) == 0) {
215
m--;
216
if(Td[PA[SA[m / 2]]] < Td[PA[SA[m]]]) { SWAP(SA[m], SA[m / 2]); }
217
}
218
219
for(i = m / 2 - 1; 0 <= i; --i) { ss_fixdown(Td, PA, SA, i, m); }
220
if((size % 2) == 0) { SWAP(SA[0], SA[m]); ss_fixdown(Td, PA, SA, 0, m); }
221
for(i = m - 1; 0 < i; --i) {
222
t = SA[0], SA[0] = SA[i];
223
ss_fixdown(Td, PA, SA, 0, i);
224
SA[i] = t;
225
}
226
}
227
228
229
/*---------------------------------------------------------------------------*/
230
231
/* Returns the median of three elements. */
232
static INLINE
233
saidx_t *
234
ss_median3(const sauchar_t *Td, const saidx_t *PA,
235
saidx_t *v1, saidx_t *v2, saidx_t *v3) {
236
saidx_t *t;
237
if(Td[PA[*v1]] > Td[PA[*v2]]) { SWAP(v1, v2); }
238
if(Td[PA[*v2]] > Td[PA[*v3]]) {
239
if(Td[PA[*v1]] > Td[PA[*v3]]) { return v1; }
240
else { return v3; }
241
}
242
return v2;
243
}
244
245
/* Returns the median of five elements. */
246
static INLINE
247
saidx_t *
248
ss_median5(const sauchar_t *Td, const saidx_t *PA,
249
saidx_t *v1, saidx_t *v2, saidx_t *v3, saidx_t *v4, saidx_t *v5) {
250
saidx_t *t;
251
if(Td[PA[*v2]] > Td[PA[*v3]]) { SWAP(v2, v3); }
252
if(Td[PA[*v4]] > Td[PA[*v5]]) { SWAP(v4, v5); }
253
if(Td[PA[*v2]] > Td[PA[*v4]]) { SWAP(v2, v4); SWAP(v3, v5); }
254
if(Td[PA[*v1]] > Td[PA[*v3]]) { SWAP(v1, v3); }
255
if(Td[PA[*v1]] > Td[PA[*v4]]) { SWAP(v1, v4); SWAP(v3, v5); }
256
if(Td[PA[*v3]] > Td[PA[*v4]]) { return v4; }
257
return v3;
258
}
259
260
/* Returns the pivot element. */
261
static INLINE
262
saidx_t *
263
ss_pivot(const sauchar_t *Td, const saidx_t *PA, saidx_t *first, saidx_t *last) {
264
saidx_t *middle;
265
saidx_t t;
266
267
t = last - first;
268
middle = first + t / 2;
269
270
if(t <= 512) {
271
if(t <= 32) {
272
return ss_median3(Td, PA, first, middle, last - 1);
273
} else {
274
t >>= 2;
275
return ss_median5(Td, PA, first, first + t, middle, last - 1 - t, last - 1);
276
}
277
}
278
t >>= 3;
279
first = ss_median3(Td, PA, first, first + t, first + (t << 1));
280
middle = ss_median3(Td, PA, middle - t, middle, middle + t);
281
last = ss_median3(Td, PA, last - 1 - (t << 1), last - 1 - t, last - 1);
282
return ss_median3(Td, PA, first, middle, last);
283
}
284
285
286
/*---------------------------------------------------------------------------*/
287
288
/* Binary partition for substrings. */
289
static INLINE
290
saidx_t *
291
ss_partition(const saidx_t *PA,
292
saidx_t *first, saidx_t *last, saidx_t depth) {
293
saidx_t *a, *b;
294
saidx_t t;
295
for(a = first - 1, b = last;;) {
296
for(; (++a < b) && ((PA[*a] + depth) >= (PA[*a + 1] + 1));) { *a = ~*a; }
297
for(; (a < --b) && ((PA[*b] + depth) < (PA[*b + 1] + 1));) { }
298
if(b <= a) { break; }
299
t = ~*b;
300
*b = *a;
301
*a = t;
302
}
303
if(first < a) { *first = ~*first; }
304
return a;
305
}
306
307
/* Multikey introsort for medium size groups. */
308
static
309
void
310
ss_mintrosort(const sauchar_t *T, const saidx_t *PA,
311
saidx_t *first, saidx_t *last,
312
saidx_t depth) {
313
#define STACK_SIZE SS_MISORT_STACKSIZE
314
struct { saidx_t *a, *b, c; saint_t d; } stack[STACK_SIZE];
315
const sauchar_t *Td;
316
saidx_t *a, *b, *c, *d, *e, *f;
317
saidx_t s, t;
318
saint_t ssize;
319
saint_t limit;
320
saint_t v, x = 0;
321
322
for(ssize = 0, limit = ss_ilg(last - first);;) {
323
324
if((last - first) <= SS_INSERTIONSORT_THRESHOLD) {
325
#if 1 < SS_INSERTIONSORT_THRESHOLD
326
if(1 < (last - first)) { ss_insertionsort(T, PA, first, last, depth); }
327
#endif
328
STACK_POP(first, last, depth, limit);
329
continue;
330
}
331
332
Td = T + depth;
333
if(limit-- == 0) { ss_heapsort(Td, PA, first, last - first); }
334
if(limit < 0) {
335
for(a = first + 1, v = Td[PA[*first]]; a < last; ++a) {
336
if((x = Td[PA[*a]]) != v) {
337
if(1 < (a - first)) { break; }
338
v = x;
339
first = a;
340
}
341
}
342
if(Td[PA[*first] - 1] < v) {
343
first = ss_partition(PA, first, a, depth);
344
}
345
if((a - first) <= (last - a)) {
346
if(1 < (a - first)) {
347
STACK_PUSH(a, last, depth, -1);
348
last = a, depth += 1, limit = ss_ilg(a - first);
349
} else {
350
first = a, limit = -1;
351
}
352
} else {
353
if(1 < (last - a)) {
354
STACK_PUSH(first, a, depth + 1, ss_ilg(a - first));
355
first = a, limit = -1;
356
} else {
357
last = a, depth += 1, limit = ss_ilg(a - first);
358
}
359
}
360
continue;
361
}
362
363
/* choose pivot */
364
a = ss_pivot(Td, PA, first, last);
365
v = Td[PA[*a]];
366
SWAP(*first, *a);
367
368
/* partition */
369
for(b = first; (++b < last) && ((x = Td[PA[*b]]) == v);) { }
370
if(((a = b) < last) && (x < v)) {
371
for(; (++b < last) && ((x = Td[PA[*b]]) <= v);) {
372
if(x == v) { SWAP(*b, *a); ++a; }
373
}
374
}
375
for(c = last; (b < --c) && ((x = Td[PA[*c]]) == v);) { }
376
if((b < (d = c)) && (x > v)) {
377
for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) {
378
if(x == v) { SWAP(*c, *d); --d; }
379
}
380
}
381
for(; b < c;) {
382
SWAP(*b, *c);
383
for(; (++b < c) && ((x = Td[PA[*b]]) <= v);) {
384
if(x == v) { SWAP(*b, *a); ++a; }
385
}
386
for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) {
387
if(x == v) { SWAP(*c, *d); --d; }
388
}
389
}
390
391
if(a <= d) {
392
c = b - 1;
393
394
if((s = a - first) > (t = b - a)) { s = t; }
395
for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }
396
if((s = d - c) > (t = last - d - 1)) { s = t; }
397
for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }
398
399
a = first + (b - a), c = last - (d - c);
400
b = (v <= Td[PA[*a] - 1]) ? a : ss_partition(PA, a, c, depth);
401
402
if((a - first) <= (last - c)) {
403
if((last - c) <= (c - b)) {
404
STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));
405
STACK_PUSH(c, last, depth, limit);
406
last = a;
407
} else if((a - first) <= (c - b)) {
408
STACK_PUSH(c, last, depth, limit);
409
STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));
410
last = a;
411
} else {
412
STACK_PUSH(c, last, depth, limit);
413
STACK_PUSH(first, a, depth, limit);
414
first = b, last = c, depth += 1, limit = ss_ilg(c - b);
415
}
416
} else {
417
if((a - first) <= (c - b)) {
418
STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));
419
STACK_PUSH(first, a, depth, limit);
420
first = c;
421
} else if((last - c) <= (c - b)) {
422
STACK_PUSH(first, a, depth, limit);
423
STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));
424
first = c;
425
} else {
426
STACK_PUSH(first, a, depth, limit);
427
STACK_PUSH(c, last, depth, limit);
428
first = b, last = c, depth += 1, limit = ss_ilg(c - b);
429
}
430
}
431
} else {
432
limit += 1;
433
if(Td[PA[*first] - 1] < v) {
434
first = ss_partition(PA, first, last, depth);
435
limit = ss_ilg(last - first);
436
}
437
depth += 1;
438
}
439
}
440
#undef STACK_SIZE
441
}
442
443
#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */
444
445
446
/*---------------------------------------------------------------------------*/
447
448
#if SS_BLOCKSIZE != 0
449
450
static INLINE
451
void
452
ss_blockswap(saidx_t *a, saidx_t *b, saidx_t n) {
453
saidx_t t;
454
for(; 0 < n; --n, ++a, ++b) {
455
t = *a, *a = *b, *b = t;
456
}
457
}
458
459
static INLINE
460
void
461
ss_rotate(saidx_t *first, saidx_t *middle, saidx_t *last) {
462
saidx_t *a, *b, t;
463
saidx_t l, r;
464
l = middle - first, r = last - middle;
465
for(; (0 < l) && (0 < r);) {
466
if(l == r) { ss_blockswap(first, middle, l); break; }
467
if(l < r) {
468
a = last - 1, b = middle - 1;
469
t = *a;
470
do {
471
*a-- = *b, *b-- = *a;
472
if(b < first) {
473
*a = t;
474
last = a;
475
if((r -= l + 1) <= l) { break; }
476
a -= 1, b = middle - 1;
477
t = *a;
478
}
479
} while(1);
480
} else {
481
a = first, b = middle;
482
t = *a;
483
do {
484
*a++ = *b, *b++ = *a;
485
if(last <= b) {
486
*a = t;
487
first = a + 1;
488
if((l -= r + 1) <= r) { break; }
489
a += 1, b = middle;
490
t = *a;
491
}
492
} while(1);
493
}
494
}
495
}
496
497
498
/*---------------------------------------------------------------------------*/
499
500
static
501
void
502
ss_inplacemerge(const sauchar_t *T, const saidx_t *PA,
503
saidx_t *first, saidx_t *middle, saidx_t *last,
504
saidx_t depth) {
505
const saidx_t *p;
506
saidx_t *a, *b;
507
saidx_t len, half;
508
saint_t q, r;
509
saint_t x;
510
511
for(;;) {
512
if(*(last - 1) < 0) { x = 1; p = PA + ~*(last - 1); }
513
else { x = 0; p = PA + *(last - 1); }
514
for(a = first, len = middle - first, half = len >> 1, r = -1;
515
0 < len;
516
len = half, half >>= 1) {
517
b = a + half;
518
q = ss_compare(T, PA + ((0 <= *b) ? *b : ~*b), p, depth);
519
if(q < 0) {
520
a = b + 1;
521
half -= (len & 1) ^ 1;
522
} else {
523
r = q;
524
}
525
}
526
if(a < middle) {
527
if(r == 0) { *a = ~*a; }
528
ss_rotate(a, middle, last);
529
last -= middle - a;
530
middle = a;
531
if(first == middle) { break; }
532
}
533
--last;
534
if(x != 0) { while(*--last < 0) { } }
535
if(middle == last) { break; }
536
}
537
}
538
539
540
/*---------------------------------------------------------------------------*/
541
542
/* Merge-forward with internal buffer. */
543
static
544
void
545
ss_mergeforward(const sauchar_t *T, const saidx_t *PA,
546
saidx_t *first, saidx_t *middle, saidx_t *last,
547
saidx_t *buf, saidx_t depth) {
548
saidx_t *a, *b, *c, *bufend;
549
saidx_t t;
550
saint_t r;
551
552
bufend = buf + (middle - first) - 1;
553
ss_blockswap(buf, first, middle - first);
554
555
for(t = *(a = first), b = buf, c = middle;;) {
556
r = ss_compare(T, PA + *b, PA + *c, depth);
557
if(r < 0) {
558
do {
559
*a++ = *b;
560
if(bufend <= b) { *bufend = t; return; }
561
*b++ = *a;
562
} while(*b < 0);
563
} else if(r > 0) {
564
do {
565
*a++ = *c, *c++ = *a;
566
if(last <= c) {
567
while(b < bufend) { *a++ = *b, *b++ = *a; }
568
*a = *b, *b = t;
569
return;
570
}
571
} while(*c < 0);
572
} else {
573
*c = ~*c;
574
do {
575
*a++ = *b;
576
if(bufend <= b) { *bufend = t; return; }
577
*b++ = *a;
578
} while(*b < 0);
579
580
do {
581
*a++ = *c, *c++ = *a;
582
if(last <= c) {
583
while(b < bufend) { *a++ = *b, *b++ = *a; }
584
*a = *b, *b = t;
585
return;
586
}
587
} while(*c < 0);
588
}
589
}
590
}
591
592
/* Merge-backward with internal buffer. */
593
static
594
void
595
ss_mergebackward(const sauchar_t *T, const saidx_t *PA,
596
saidx_t *first, saidx_t *middle, saidx_t *last,
597
saidx_t *buf, saidx_t depth) {
598
const saidx_t *p1, *p2;
599
saidx_t *a, *b, *c, *bufend;
600
saidx_t t;
601
saint_t r;
602
saint_t x;
603
604
bufend = buf + (last - middle) - 1;
605
ss_blockswap(buf, middle, last - middle);
606
607
x = 0;
608
if(*bufend < 0) { p1 = PA + ~*bufend; x |= 1; }
609
else { p1 = PA + *bufend; }
610
if(*(middle - 1) < 0) { p2 = PA + ~*(middle - 1); x |= 2; }
611
else { p2 = PA + *(middle - 1); }
612
for(t = *(a = last - 1), b = bufend, c = middle - 1;;) {
613
r = ss_compare(T, p1, p2, depth);
614
if(0 < r) {
615
if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; }
616
*a-- = *b;
617
if(b <= buf) { *buf = t; break; }
618
*b-- = *a;
619
if(*b < 0) { p1 = PA + ~*b; x |= 1; }
620
else { p1 = PA + *b; }
621
} else if(r < 0) {
622
if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; }
623
*a-- = *c, *c-- = *a;
624
if(c < first) {
625
while(buf < b) { *a-- = *b, *b-- = *a; }
626
*a = *b, *b = t;
627
break;
628
}
629
if(*c < 0) { p2 = PA + ~*c; x |= 2; }
630
else { p2 = PA + *c; }
631
} else {
632
if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; }
633
*a-- = ~*b;
634
if(b <= buf) { *buf = t; break; }
635
*b-- = *a;
636
if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; }
637
*a-- = *c, *c-- = *a;
638
if(c < first) {
639
while(buf < b) { *a-- = *b, *b-- = *a; }
640
*a = *b, *b = t;
641
break;
642
}
643
if(*b < 0) { p1 = PA + ~*b; x |= 1; }
644
else { p1 = PA + *b; }
645
if(*c < 0) { p2 = PA + ~*c; x |= 2; }
646
else { p2 = PA + *c; }
647
}
648
}
649
}
650
651
/* D&C based merge. */
652
static
653
void
654
ss_swapmerge(const sauchar_t *T, const saidx_t *PA,
655
saidx_t *first, saidx_t *middle, saidx_t *last,
656
saidx_t *buf, saidx_t bufsize, saidx_t depth) {
657
#define STACK_SIZE SS_SMERGE_STACKSIZE
658
#define GETIDX(a) ((0 <= (a)) ? (a) : (~(a)))
659
#define MERGE_CHECK(a, b, c)\
660
do {\
661
if(((c) & 1) ||\
662
(((c) & 2) && (ss_compare(T, PA + GETIDX(*((a) - 1)), PA + *(a), depth) == 0))) {\
663
*(a) = ~*(a);\
664
}\
665
if(((c) & 4) && ((ss_compare(T, PA + GETIDX(*((b) - 1)), PA + *(b), depth) == 0))) {\
666
*(b) = ~*(b);\
667
}\
668
} while(0)
669
struct { saidx_t *a, *b, *c; saint_t d; } stack[STACK_SIZE];
670
saidx_t *l, *r, *lm, *rm;
671
saidx_t m, len, half;
672
saint_t ssize;
673
saint_t check, next;
674
675
for(check = 0, ssize = 0;;) {
676
if((last - middle) <= bufsize) {
677
if((first < middle) && (middle < last)) {
678
ss_mergebackward(T, PA, first, middle, last, buf, depth);
679
}
680
MERGE_CHECK(first, last, check);
681
STACK_POP(first, middle, last, check);
682
continue;
683
}
684
685
if((middle - first) <= bufsize) {
686
if(first < middle) {
687
ss_mergeforward(T, PA, first, middle, last, buf, depth);
688
}
689
MERGE_CHECK(first, last, check);
690
STACK_POP(first, middle, last, check);
691
continue;
692
}
693
694
for(m = 0, len = MIN(middle - first, last - middle), half = len >> 1;
695
0 < len;
696
len = half, half >>= 1) {
697
if(ss_compare(T, PA + GETIDX(*(middle + m + half)),
698
PA + GETIDX(*(middle - m - half - 1)), depth) < 0) {
699
m += half + 1;
700
half -= (len & 1) ^ 1;
701
}
702
}
703
704
if(0 < m) {
705
lm = middle - m, rm = middle + m;
706
ss_blockswap(lm, middle, m);
707
l = r = middle, next = 0;
708
if(rm < last) {
709
if(*rm < 0) {
710
*rm = ~*rm;
711
if(first < lm) { for(; *--l < 0;) { } next |= 4; }
712
next |= 1;
713
} else if(first < lm) {
714
for(; *r < 0; ++r) { }
715
next |= 2;
716
}
717
}
718
719
if((l - first) <= (last - r)) {
720
STACK_PUSH(r, rm, last, (next & 3) | (check & 4));
721
middle = lm, last = l, check = (check & 3) | (next & 4);
722
} else {
723
if((next & 2) && (r == middle)) { next ^= 6; }
724
STACK_PUSH(first, lm, l, (check & 3) | (next & 4));
725
first = r, middle = rm, check = (next & 3) | (check & 4);
726
}
727
} else {
728
if(ss_compare(T, PA + GETIDX(*(middle - 1)), PA + *middle, depth) == 0) {
729
*middle = ~*middle;
730
}
731
MERGE_CHECK(first, last, check);
732
STACK_POP(first, middle, last, check);
733
}
734
}
735
#undef STACK_SIZE
736
}
737
738
#endif /* SS_BLOCKSIZE != 0 */
739
740
741
/*---------------------------------------------------------------------------*/
742
743
/*- Function -*/
744
745
/* Substring sort */
746
void
747
sssort(const sauchar_t *T, const saidx_t *PA,
748
saidx_t *first, saidx_t *last,
749
saidx_t *buf, saidx_t bufsize,
750
saidx_t depth, saidx_t n, saint_t lastsuffix) {
751
saidx_t *a;
752
#if SS_BLOCKSIZE != 0
753
saidx_t *b, *middle, *curbuf;
754
saidx_t j, k, curbufsize, limit;
755
#endif
756
saidx_t i;
757
758
if(lastsuffix != 0) { ++first; }
759
760
#if SS_BLOCKSIZE == 0
761
ss_mintrosort(T, PA, first, last, depth);
762
#else
763
if((bufsize < SS_BLOCKSIZE) &&
764
(bufsize < (last - first)) &&
765
(bufsize < (limit = ss_isqrt(last - first)))) {
766
if(SS_BLOCKSIZE < limit) { limit = SS_BLOCKSIZE; }
767
buf = middle = last - limit, bufsize = limit;
768
} else {
769
middle = last, limit = 0;
770
}
771
for(a = first, i = 0; SS_BLOCKSIZE < (middle - a); a += SS_BLOCKSIZE, ++i) {
772
#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE
773
ss_mintrosort(T, PA, a, a + SS_BLOCKSIZE, depth);
774
#elif 1 < SS_BLOCKSIZE
775
ss_insertionsort(T, PA, a, a + SS_BLOCKSIZE, depth);
776
#endif
777
curbufsize = last - (a + SS_BLOCKSIZE);
778
curbuf = a + SS_BLOCKSIZE;
779
if(curbufsize <= bufsize) { curbufsize = bufsize, curbuf = buf; }
780
for(b = a, k = SS_BLOCKSIZE, j = i; j & 1; b -= k, k <<= 1, j >>= 1) {
781
ss_swapmerge(T, PA, b - k, b, b + k, curbuf, curbufsize, depth);
782
}
783
}
784
#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE
785
ss_mintrosort(T, PA, a, middle, depth);
786
#elif 1 < SS_BLOCKSIZE
787
ss_insertionsort(T, PA, a, middle, depth);
788
#endif
789
for(k = SS_BLOCKSIZE; i != 0; k <<= 1, i >>= 1) {
790
if(i & 1) {
791
ss_swapmerge(T, PA, a - k, a, middle, buf, bufsize, depth);
792
a -= k;
793
}
794
}
795
if(limit != 0) {
796
#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE
797
ss_mintrosort(T, PA, middle, last, depth);
798
#elif 1 < SS_BLOCKSIZE
799
ss_insertionsort(T, PA, middle, last, depth);
800
#endif
801
ss_inplacemerge(T, PA, first, middle, last, depth);
802
}
803
#endif
804
805
if(lastsuffix != 0) {
806
/* Insert last type B* suffix. */
807
saidx_t PAi[2]; PAi[0] = PA[*(first - 1)], PAi[1] = n - 2;
808
for(a = first, i = *(first - 1);
809
(a < last) && ((*a < 0) || (0 < ss_compare(T, &(PAi[0]), PA + *a, depth)));
810
++a) {
811
*(a - 1) = *a;
812
}
813
*(a - 1) = i;
814
}
815
}
816
817