Path: blob/main/contrib/libdivsufsort/lib/sssort.c
39483 views
/*1* sssort.c for libdivsufsort2* Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.3*4* Permission is hereby granted, free of charge, to any person5* obtaining a copy of this software and associated documentation6* files (the "Software"), to deal in the Software without7* restriction, including without limitation the rights to use,8* copy, modify, merge, publish, distribute, sublicense, and/or sell9* copies of the Software, and to permit persons to whom the10* Software is furnished to do so, subject to the following11* conditions:12*13* The above copyright notice and this permission notice shall be14* included in all copies or substantial portions of the Software.15*16* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,17* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES18* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND19* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT20* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,21* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING22* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR23* OTHER DEALINGS IN THE SOFTWARE.24*/2526#include "divsufsort_private.h"272829/*- Private Functions -*/3031static const saint_t lg_table[256]= {32-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,335,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,346,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,356,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,367,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,377,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,387,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,397,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,740};4142#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE)4344static INLINE45saint_t46ss_ilg(saidx_t n) {47#if SS_BLOCKSIZE == 048# if defined(BUILD_DIVSUFSORT64)49return (n >> 32) ?50((n >> 48) ?51((n >> 56) ?5256 + lg_table[(n >> 56) & 0xff] :5348 + lg_table[(n >> 48) & 0xff]) :54((n >> 40) ?5540 + lg_table[(n >> 40) & 0xff] :5632 + lg_table[(n >> 32) & 0xff])) :57((n & 0xffff0000) ?58((n & 0xff000000) ?5924 + lg_table[(n >> 24) & 0xff] :6016 + lg_table[(n >> 16) & 0xff]) :61((n & 0x0000ff00) ?628 + lg_table[(n >> 8) & 0xff] :630 + lg_table[(n >> 0) & 0xff]));64# else65return (n & 0xffff0000) ?66((n & 0xff000000) ?6724 + lg_table[(n >> 24) & 0xff] :6816 + lg_table[(n >> 16) & 0xff]) :69((n & 0x0000ff00) ?708 + lg_table[(n >> 8) & 0xff] :710 + lg_table[(n >> 0) & 0xff]);72# endif73#elif SS_BLOCKSIZE < 25674return lg_table[n];75#else76return (n & 0xff00) ?778 + lg_table[(n >> 8) & 0xff] :780 + lg_table[(n >> 0) & 0xff];79#endif80}8182#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */8384#if SS_BLOCKSIZE != 08586static const saint_t sqq_table[256] = {870, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57, 59, 61,8864, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83, 84, 86, 87, 89,8990, 91, 93, 94, 96, 97, 98, 99, 101, 102, 103, 104, 106, 107, 108, 109,90110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,91128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,92143, 144, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155,93156, 157, 158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168,94169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178, 179, 180,95181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 191,96192, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201,97202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211,98212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 221,99221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230,100230, 231, 231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238,101239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247,102247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255103};104105static INLINE106saidx_t107ss_isqrt(saidx_t x) {108saidx_t y, e;109110if(x >= (SS_BLOCKSIZE * SS_BLOCKSIZE)) { return SS_BLOCKSIZE; }111e = (x & 0xffff0000) ?112((x & 0xff000000) ?11324 + lg_table[(x >> 24) & 0xff] :11416 + lg_table[(x >> 16) & 0xff]) :115((x & 0x0000ff00) ?1168 + lg_table[(x >> 8) & 0xff] :1170 + lg_table[(x >> 0) & 0xff]);118119if(e >= 16) {120y = sqq_table[x >> ((e - 6) - (e & 1))] << ((e >> 1) - 7);121if(e >= 24) { y = (y + 1 + x / y) >> 1; }122y = (y + 1 + x / y) >> 1;123} else if(e >= 8) {124y = (sqq_table[x >> ((e - 6) - (e & 1))] >> (7 - (e >> 1))) + 1;125} else {126return sqq_table[x] >> 4;127}128129return (x < (y * y)) ? y - 1 : y;130}131132#endif /* SS_BLOCKSIZE != 0 */133134135/*---------------------------------------------------------------------------*/136137/* Compares two suffixes. */138static INLINE139saint_t140ss_compare(const sauchar_t *T,141const saidx_t *p1, const saidx_t *p2,142saidx_t depth) {143const sauchar_t *U1, *U2, *U1n, *U2n;144145for(U1 = T + depth + *p1,146U2 = T + depth + *p2,147U1n = T + *(p1 + 1) + 2,148U2n = T + *(p2 + 1) + 2;149(U1 < U1n) && (U2 < U2n) && (*U1 == *U2);150++U1, ++U2) {151}152153return U1 < U1n ?154(U2 < U2n ? *U1 - *U2 : 1) :155(U2 < U2n ? -1 : 0);156}157158159/*---------------------------------------------------------------------------*/160161#if (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1)162163/* Insertionsort for small size groups */164static165void166ss_insertionsort(const sauchar_t *T, const saidx_t *PA,167saidx_t *first, saidx_t *last, saidx_t depth) {168saidx_t *i, *j;169saidx_t t;170saint_t r;171172for(i = last - 2; first <= i; --i) {173for(t = *i, j = i + 1; 0 < (r = ss_compare(T, PA + t, PA + *j, depth));) {174do { *(j - 1) = *j; } while((++j < last) && (*j < 0));175if(last <= j) { break; }176}177if(r == 0) { *j = ~*j; }178*(j - 1) = t;179}180}181182#endif /* (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) */183184185/*---------------------------------------------------------------------------*/186187#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE)188189static INLINE190void191ss_fixdown(const sauchar_t *Td, const saidx_t *PA,192saidx_t *SA, saidx_t i, saidx_t size) {193saidx_t j, k;194saidx_t v;195saint_t c, d, e;196197for(v = SA[i], c = Td[PA[v]]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) {198d = Td[PA[SA[k = j++]]];199if(d < (e = Td[PA[SA[j]]])) { k = j; d = e; }200if(d <= c) { break; }201}202SA[i] = v;203}204205/* Simple top-down heapsort. */206static207void208ss_heapsort(const sauchar_t *Td, const saidx_t *PA, saidx_t *SA, saidx_t size) {209saidx_t i, m;210saidx_t t;211212m = size;213if((size % 2) == 0) {214m--;215if(Td[PA[SA[m / 2]]] < Td[PA[SA[m]]]) { SWAP(SA[m], SA[m / 2]); }216}217218for(i = m / 2 - 1; 0 <= i; --i) { ss_fixdown(Td, PA, SA, i, m); }219if((size % 2) == 0) { SWAP(SA[0], SA[m]); ss_fixdown(Td, PA, SA, 0, m); }220for(i = m - 1; 0 < i; --i) {221t = SA[0], SA[0] = SA[i];222ss_fixdown(Td, PA, SA, 0, i);223SA[i] = t;224}225}226227228/*---------------------------------------------------------------------------*/229230/* Returns the median of three elements. */231static INLINE232saidx_t *233ss_median3(const sauchar_t *Td, const saidx_t *PA,234saidx_t *v1, saidx_t *v2, saidx_t *v3) {235saidx_t *t;236if(Td[PA[*v1]] > Td[PA[*v2]]) { SWAP(v1, v2); }237if(Td[PA[*v2]] > Td[PA[*v3]]) {238if(Td[PA[*v1]] > Td[PA[*v3]]) { return v1; }239else { return v3; }240}241return v2;242}243244/* Returns the median of five elements. */245static INLINE246saidx_t *247ss_median5(const sauchar_t *Td, const saidx_t *PA,248saidx_t *v1, saidx_t *v2, saidx_t *v3, saidx_t *v4, saidx_t *v5) {249saidx_t *t;250if(Td[PA[*v2]] > Td[PA[*v3]]) { SWAP(v2, v3); }251if(Td[PA[*v4]] > Td[PA[*v5]]) { SWAP(v4, v5); }252if(Td[PA[*v2]] > Td[PA[*v4]]) { SWAP(v2, v4); SWAP(v3, v5); }253if(Td[PA[*v1]] > Td[PA[*v3]]) { SWAP(v1, v3); }254if(Td[PA[*v1]] > Td[PA[*v4]]) { SWAP(v1, v4); SWAP(v3, v5); }255if(Td[PA[*v3]] > Td[PA[*v4]]) { return v4; }256return v3;257}258259/* Returns the pivot element. */260static INLINE261saidx_t *262ss_pivot(const sauchar_t *Td, const saidx_t *PA, saidx_t *first, saidx_t *last) {263saidx_t *middle;264saidx_t t;265266t = last - first;267middle = first + t / 2;268269if(t <= 512) {270if(t <= 32) {271return ss_median3(Td, PA, first, middle, last - 1);272} else {273t >>= 2;274return ss_median5(Td, PA, first, first + t, middle, last - 1 - t, last - 1);275}276}277t >>= 3;278first = ss_median3(Td, PA, first, first + t, first + (t << 1));279middle = ss_median3(Td, PA, middle - t, middle, middle + t);280last = ss_median3(Td, PA, last - 1 - (t << 1), last - 1 - t, last - 1);281return ss_median3(Td, PA, first, middle, last);282}283284285/*---------------------------------------------------------------------------*/286287/* Binary partition for substrings. */288static INLINE289saidx_t *290ss_partition(const saidx_t *PA,291saidx_t *first, saidx_t *last, saidx_t depth) {292saidx_t *a, *b;293saidx_t t;294for(a = first - 1, b = last;;) {295for(; (++a < b) && ((PA[*a] + depth) >= (PA[*a + 1] + 1));) { *a = ~*a; }296for(; (a < --b) && ((PA[*b] + depth) < (PA[*b + 1] + 1));) { }297if(b <= a) { break; }298t = ~*b;299*b = *a;300*a = t;301}302if(first < a) { *first = ~*first; }303return a;304}305306/* Multikey introsort for medium size groups. */307static308void309ss_mintrosort(const sauchar_t *T, const saidx_t *PA,310saidx_t *first, saidx_t *last,311saidx_t depth) {312#define STACK_SIZE SS_MISORT_STACKSIZE313struct { saidx_t *a, *b, c; saint_t d; } stack[STACK_SIZE];314const sauchar_t *Td;315saidx_t *a, *b, *c, *d, *e, *f;316saidx_t s, t;317saint_t ssize;318saint_t limit;319saint_t v, x = 0;320321for(ssize = 0, limit = ss_ilg(last - first);;) {322323if((last - first) <= SS_INSERTIONSORT_THRESHOLD) {324#if 1 < SS_INSERTIONSORT_THRESHOLD325if(1 < (last - first)) { ss_insertionsort(T, PA, first, last, depth); }326#endif327STACK_POP(first, last, depth, limit);328continue;329}330331Td = T + depth;332if(limit-- == 0) { ss_heapsort(Td, PA, first, last - first); }333if(limit < 0) {334for(a = first + 1, v = Td[PA[*first]]; a < last; ++a) {335if((x = Td[PA[*a]]) != v) {336if(1 < (a - first)) { break; }337v = x;338first = a;339}340}341if(Td[PA[*first] - 1] < v) {342first = ss_partition(PA, first, a, depth);343}344if((a - first) <= (last - a)) {345if(1 < (a - first)) {346STACK_PUSH(a, last, depth, -1);347last = a, depth += 1, limit = ss_ilg(a - first);348} else {349first = a, limit = -1;350}351} else {352if(1 < (last - a)) {353STACK_PUSH(first, a, depth + 1, ss_ilg(a - first));354first = a, limit = -1;355} else {356last = a, depth += 1, limit = ss_ilg(a - first);357}358}359continue;360}361362/* choose pivot */363a = ss_pivot(Td, PA, first, last);364v = Td[PA[*a]];365SWAP(*first, *a);366367/* partition */368for(b = first; (++b < last) && ((x = Td[PA[*b]]) == v);) { }369if(((a = b) < last) && (x < v)) {370for(; (++b < last) && ((x = Td[PA[*b]]) <= v);) {371if(x == v) { SWAP(*b, *a); ++a; }372}373}374for(c = last; (b < --c) && ((x = Td[PA[*c]]) == v);) { }375if((b < (d = c)) && (x > v)) {376for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) {377if(x == v) { SWAP(*c, *d); --d; }378}379}380for(; b < c;) {381SWAP(*b, *c);382for(; (++b < c) && ((x = Td[PA[*b]]) <= v);) {383if(x == v) { SWAP(*b, *a); ++a; }384}385for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) {386if(x == v) { SWAP(*c, *d); --d; }387}388}389390if(a <= d) {391c = b - 1;392393if((s = a - first) > (t = b - a)) { s = t; }394for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }395if((s = d - c) > (t = last - d - 1)) { s = t; }396for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }397398a = first + (b - a), c = last - (d - c);399b = (v <= Td[PA[*a] - 1]) ? a : ss_partition(PA, a, c, depth);400401if((a - first) <= (last - c)) {402if((last - c) <= (c - b)) {403STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));404STACK_PUSH(c, last, depth, limit);405last = a;406} else if((a - first) <= (c - b)) {407STACK_PUSH(c, last, depth, limit);408STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));409last = a;410} else {411STACK_PUSH(c, last, depth, limit);412STACK_PUSH(first, a, depth, limit);413first = b, last = c, depth += 1, limit = ss_ilg(c - b);414}415} else {416if((a - first) <= (c - b)) {417STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));418STACK_PUSH(first, a, depth, limit);419first = c;420} else if((last - c) <= (c - b)) {421STACK_PUSH(first, a, depth, limit);422STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));423first = c;424} else {425STACK_PUSH(first, a, depth, limit);426STACK_PUSH(c, last, depth, limit);427first = b, last = c, depth += 1, limit = ss_ilg(c - b);428}429}430} else {431limit += 1;432if(Td[PA[*first] - 1] < v) {433first = ss_partition(PA, first, last, depth);434limit = ss_ilg(last - first);435}436depth += 1;437}438}439#undef STACK_SIZE440}441442#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */443444445/*---------------------------------------------------------------------------*/446447#if SS_BLOCKSIZE != 0448449static INLINE450void451ss_blockswap(saidx_t *a, saidx_t *b, saidx_t n) {452saidx_t t;453for(; 0 < n; --n, ++a, ++b) {454t = *a, *a = *b, *b = t;455}456}457458static INLINE459void460ss_rotate(saidx_t *first, saidx_t *middle, saidx_t *last) {461saidx_t *a, *b, t;462saidx_t l, r;463l = middle - first, r = last - middle;464for(; (0 < l) && (0 < r);) {465if(l == r) { ss_blockswap(first, middle, l); break; }466if(l < r) {467a = last - 1, b = middle - 1;468t = *a;469do {470*a-- = *b, *b-- = *a;471if(b < first) {472*a = t;473last = a;474if((r -= l + 1) <= l) { break; }475a -= 1, b = middle - 1;476t = *a;477}478} while(1);479} else {480a = first, b = middle;481t = *a;482do {483*a++ = *b, *b++ = *a;484if(last <= b) {485*a = t;486first = a + 1;487if((l -= r + 1) <= r) { break; }488a += 1, b = middle;489t = *a;490}491} while(1);492}493}494}495496497/*---------------------------------------------------------------------------*/498499static500void501ss_inplacemerge(const sauchar_t *T, const saidx_t *PA,502saidx_t *first, saidx_t *middle, saidx_t *last,503saidx_t depth) {504const saidx_t *p;505saidx_t *a, *b;506saidx_t len, half;507saint_t q, r;508saint_t x;509510for(;;) {511if(*(last - 1) < 0) { x = 1; p = PA + ~*(last - 1); }512else { x = 0; p = PA + *(last - 1); }513for(a = first, len = middle - first, half = len >> 1, r = -1;5140 < len;515len = half, half >>= 1) {516b = a + half;517q = ss_compare(T, PA + ((0 <= *b) ? *b : ~*b), p, depth);518if(q < 0) {519a = b + 1;520half -= (len & 1) ^ 1;521} else {522r = q;523}524}525if(a < middle) {526if(r == 0) { *a = ~*a; }527ss_rotate(a, middle, last);528last -= middle - a;529middle = a;530if(first == middle) { break; }531}532--last;533if(x != 0) { while(*--last < 0) { } }534if(middle == last) { break; }535}536}537538539/*---------------------------------------------------------------------------*/540541/* Merge-forward with internal buffer. */542static543void544ss_mergeforward(const sauchar_t *T, const saidx_t *PA,545saidx_t *first, saidx_t *middle, saidx_t *last,546saidx_t *buf, saidx_t depth) {547saidx_t *a, *b, *c, *bufend;548saidx_t t;549saint_t r;550551bufend = buf + (middle - first) - 1;552ss_blockswap(buf, first, middle - first);553554for(t = *(a = first), b = buf, c = middle;;) {555r = ss_compare(T, PA + *b, PA + *c, depth);556if(r < 0) {557do {558*a++ = *b;559if(bufend <= b) { *bufend = t; return; }560*b++ = *a;561} while(*b < 0);562} else if(r > 0) {563do {564*a++ = *c, *c++ = *a;565if(last <= c) {566while(b < bufend) { *a++ = *b, *b++ = *a; }567*a = *b, *b = t;568return;569}570} while(*c < 0);571} else {572*c = ~*c;573do {574*a++ = *b;575if(bufend <= b) { *bufend = t; return; }576*b++ = *a;577} while(*b < 0);578579do {580*a++ = *c, *c++ = *a;581if(last <= c) {582while(b < bufend) { *a++ = *b, *b++ = *a; }583*a = *b, *b = t;584return;585}586} while(*c < 0);587}588}589}590591/* Merge-backward with internal buffer. */592static593void594ss_mergebackward(const sauchar_t *T, const saidx_t *PA,595saidx_t *first, saidx_t *middle, saidx_t *last,596saidx_t *buf, saidx_t depth) {597const saidx_t *p1, *p2;598saidx_t *a, *b, *c, *bufend;599saidx_t t;600saint_t r;601saint_t x;602603bufend = buf + (last - middle) - 1;604ss_blockswap(buf, middle, last - middle);605606x = 0;607if(*bufend < 0) { p1 = PA + ~*bufend; x |= 1; }608else { p1 = PA + *bufend; }609if(*(middle - 1) < 0) { p2 = PA + ~*(middle - 1); x |= 2; }610else { p2 = PA + *(middle - 1); }611for(t = *(a = last - 1), b = bufend, c = middle - 1;;) {612r = ss_compare(T, p1, p2, depth);613if(0 < r) {614if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; }615*a-- = *b;616if(b <= buf) { *buf = t; break; }617*b-- = *a;618if(*b < 0) { p1 = PA + ~*b; x |= 1; }619else { p1 = PA + *b; }620} else if(r < 0) {621if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; }622*a-- = *c, *c-- = *a;623if(c < first) {624while(buf < b) { *a-- = *b, *b-- = *a; }625*a = *b, *b = t;626break;627}628if(*c < 0) { p2 = PA + ~*c; x |= 2; }629else { p2 = PA + *c; }630} else {631if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; }632*a-- = ~*b;633if(b <= buf) { *buf = t; break; }634*b-- = *a;635if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; }636*a-- = *c, *c-- = *a;637if(c < first) {638while(buf < b) { *a-- = *b, *b-- = *a; }639*a = *b, *b = t;640break;641}642if(*b < 0) { p1 = PA + ~*b; x |= 1; }643else { p1 = PA + *b; }644if(*c < 0) { p2 = PA + ~*c; x |= 2; }645else { p2 = PA + *c; }646}647}648}649650/* D&C based merge. */651static652void653ss_swapmerge(const sauchar_t *T, const saidx_t *PA,654saidx_t *first, saidx_t *middle, saidx_t *last,655saidx_t *buf, saidx_t bufsize, saidx_t depth) {656#define STACK_SIZE SS_SMERGE_STACKSIZE657#define GETIDX(a) ((0 <= (a)) ? (a) : (~(a)))658#define MERGE_CHECK(a, b, c)\659do {\660if(((c) & 1) ||\661(((c) & 2) && (ss_compare(T, PA + GETIDX(*((a) - 1)), PA + *(a), depth) == 0))) {\662*(a) = ~*(a);\663}\664if(((c) & 4) && ((ss_compare(T, PA + GETIDX(*((b) - 1)), PA + *(b), depth) == 0))) {\665*(b) = ~*(b);\666}\667} while(0)668struct { saidx_t *a, *b, *c; saint_t d; } stack[STACK_SIZE];669saidx_t *l, *r, *lm, *rm;670saidx_t m, len, half;671saint_t ssize;672saint_t check, next;673674for(check = 0, ssize = 0;;) {675if((last - middle) <= bufsize) {676if((first < middle) && (middle < last)) {677ss_mergebackward(T, PA, first, middle, last, buf, depth);678}679MERGE_CHECK(first, last, check);680STACK_POP(first, middle, last, check);681continue;682}683684if((middle - first) <= bufsize) {685if(first < middle) {686ss_mergeforward(T, PA, first, middle, last, buf, depth);687}688MERGE_CHECK(first, last, check);689STACK_POP(first, middle, last, check);690continue;691}692693for(m = 0, len = MIN(middle - first, last - middle), half = len >> 1;6940 < len;695len = half, half >>= 1) {696if(ss_compare(T, PA + GETIDX(*(middle + m + half)),697PA + GETIDX(*(middle - m - half - 1)), depth) < 0) {698m += half + 1;699half -= (len & 1) ^ 1;700}701}702703if(0 < m) {704lm = middle - m, rm = middle + m;705ss_blockswap(lm, middle, m);706l = r = middle, next = 0;707if(rm < last) {708if(*rm < 0) {709*rm = ~*rm;710if(first < lm) { for(; *--l < 0;) { } next |= 4; }711next |= 1;712} else if(first < lm) {713for(; *r < 0; ++r) { }714next |= 2;715}716}717718if((l - first) <= (last - r)) {719STACK_PUSH(r, rm, last, (next & 3) | (check & 4));720middle = lm, last = l, check = (check & 3) | (next & 4);721} else {722if((next & 2) && (r == middle)) { next ^= 6; }723STACK_PUSH(first, lm, l, (check & 3) | (next & 4));724first = r, middle = rm, check = (next & 3) | (check & 4);725}726} else {727if(ss_compare(T, PA + GETIDX(*(middle - 1)), PA + *middle, depth) == 0) {728*middle = ~*middle;729}730MERGE_CHECK(first, last, check);731STACK_POP(first, middle, last, check);732}733}734#undef STACK_SIZE735}736737#endif /* SS_BLOCKSIZE != 0 */738739740/*---------------------------------------------------------------------------*/741742/*- Function -*/743744/* Substring sort */745void746sssort(const sauchar_t *T, const saidx_t *PA,747saidx_t *first, saidx_t *last,748saidx_t *buf, saidx_t bufsize,749saidx_t depth, saidx_t n, saint_t lastsuffix) {750saidx_t *a;751#if SS_BLOCKSIZE != 0752saidx_t *b, *middle, *curbuf;753saidx_t j, k, curbufsize, limit;754#endif755saidx_t i;756757if(lastsuffix != 0) { ++first; }758759#if SS_BLOCKSIZE == 0760ss_mintrosort(T, PA, first, last, depth);761#else762if((bufsize < SS_BLOCKSIZE) &&763(bufsize < (last - first)) &&764(bufsize < (limit = ss_isqrt(last - first)))) {765if(SS_BLOCKSIZE < limit) { limit = SS_BLOCKSIZE; }766buf = middle = last - limit, bufsize = limit;767} else {768middle = last, limit = 0;769}770for(a = first, i = 0; SS_BLOCKSIZE < (middle - a); a += SS_BLOCKSIZE, ++i) {771#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE772ss_mintrosort(T, PA, a, a + SS_BLOCKSIZE, depth);773#elif 1 < SS_BLOCKSIZE774ss_insertionsort(T, PA, a, a + SS_BLOCKSIZE, depth);775#endif776curbufsize = last - (a + SS_BLOCKSIZE);777curbuf = a + SS_BLOCKSIZE;778if(curbufsize <= bufsize) { curbufsize = bufsize, curbuf = buf; }779for(b = a, k = SS_BLOCKSIZE, j = i; j & 1; b -= k, k <<= 1, j >>= 1) {780ss_swapmerge(T, PA, b - k, b, b + k, curbuf, curbufsize, depth);781}782}783#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE784ss_mintrosort(T, PA, a, middle, depth);785#elif 1 < SS_BLOCKSIZE786ss_insertionsort(T, PA, a, middle, depth);787#endif788for(k = SS_BLOCKSIZE; i != 0; k <<= 1, i >>= 1) {789if(i & 1) {790ss_swapmerge(T, PA, a - k, a, middle, buf, bufsize, depth);791a -= k;792}793}794if(limit != 0) {795#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE796ss_mintrosort(T, PA, middle, last, depth);797#elif 1 < SS_BLOCKSIZE798ss_insertionsort(T, PA, middle, last, depth);799#endif800ss_inplacemerge(T, PA, first, middle, last, depth);801}802#endif803804if(lastsuffix != 0) {805/* Insert last type B* suffix. */806saidx_t PAi[2]; PAi[0] = PA[*(first - 1)], PAi[1] = n - 2;807for(a = first, i = *(first - 1);808(a < last) && ((*a < 0) || (0 < ss_compare(T, &(PAi[0]), PA + *a, depth)));809++a) {810*(a - 1) = *a;811}812*(a - 1) = i;813}814}815816817