divsufsort 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Binary file
@@ -0,0 +1,18 @@
1
+ require 'mkmf'
2
+ require 'fileutils'
3
+
4
+ root = File.dirname(File.expand_path(File.join(__FILE__, '..')))
5
+ libdivsufsort = Dir.glob(File.join(root, 'libdivsufsort', '{*.c,*.h}'))
6
+ FileUtils.cp(libdivsufsort, File.join(root, 'ext'))
7
+
8
+ %w(
9
+ dlfcn.h fcntl.h inttypes.h io.h memory.h
10
+ stddef.h stdint.h stdlib.h strings.h
11
+ string.h sys/stat.h sys/types.h unistd.h
12
+ ).each {|i| have_header(i) }
13
+
14
+ %w(
15
+ fopen_s malloc setmode _fileno _setmode
16
+ ).each {|i| have_func(i) }
17
+
18
+ create_makefile('divsufsort')
@@ -0,0 +1,56 @@
1
+ /*
2
+ * lfs.h 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
+ #ifndef _LFS_H
28
+ #define _LFS_H 1
29
+
30
+ #ifdef __cplusplus
31
+ extern "C" {
32
+ #endif /* __cplusplus */
33
+
34
+ #ifndef __STRICT_ANSI__
35
+ # define LFS_OFF_T long
36
+ # define LFS_FOPEN fopen
37
+ # define LFS_FTELL ftell
38
+ # define LFS_FSEEK fseek
39
+ # define LFS_PRId "ld"
40
+ #else
41
+ # define LFS_OFF_T long
42
+ # define LFS_FOPEN fopen
43
+ # define LFS_FTELL ftell
44
+ # define LFS_FSEEK fseek
45
+ # define LFS_PRId "ld"
46
+ #endif
47
+ #ifndef PRIdOFF_T
48
+ # define PRIdOFF_T LFS_PRId
49
+ #endif
50
+
51
+
52
+ #ifdef __cplusplus
53
+ } /* extern "C" */
54
+ #endif /* __cplusplus */
55
+
56
+ #endif /* _LFS_H */
@@ -0,0 +1,266 @@
1
+ have_header: checking for dlfcn.h... -------------------- yes
2
+
3
+ "cc -E -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -o conftest.i"
4
+ checked program was:
5
+ /* begin */
6
+ 1: #include <dlfcn.h>
7
+ /* end */
8
+
9
+ --------------------
10
+
11
+ have_header: checking for fcntl.h... -------------------- yes
12
+
13
+ "cc -E -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -o conftest.i"
14
+ checked program was:
15
+ /* begin */
16
+ 1: #include <fcntl.h>
17
+ /* end */
18
+
19
+ --------------------
20
+
21
+ have_header: checking for inttypes.h... -------------------- yes
22
+
23
+ "cc -E -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -o conftest.i"
24
+ checked program was:
25
+ /* begin */
26
+ 1: #include <inttypes.h>
27
+ /* end */
28
+
29
+ --------------------
30
+
31
+ have_header: checking for io.h... -------------------- no
32
+
33
+ "cc -E -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -o conftest.i"
34
+ conftest.c:1:16: error: io.h: No such file or directory
35
+ checked program was:
36
+ /* begin */
37
+ 1: #include <io.h>
38
+ /* end */
39
+
40
+ --------------------
41
+
42
+ have_header: checking for memory.h... -------------------- yes
43
+
44
+ "cc -E -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -o conftest.i"
45
+ checked program was:
46
+ /* begin */
47
+ 1: #include <memory.h>
48
+ /* end */
49
+
50
+ --------------------
51
+
52
+ have_header: checking for stddef.h... -------------------- yes
53
+
54
+ "cc -E -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -o conftest.i"
55
+ checked program was:
56
+ /* begin */
57
+ 1: #include <stddef.h>
58
+ /* end */
59
+
60
+ --------------------
61
+
62
+ have_header: checking for stdint.h... -------------------- yes
63
+
64
+ "cc -E -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -o conftest.i"
65
+ checked program was:
66
+ /* begin */
67
+ 1: #include <stdint.h>
68
+ /* end */
69
+
70
+ --------------------
71
+
72
+ have_header: checking for stdlib.h... -------------------- yes
73
+
74
+ "cc -E -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -o conftest.i"
75
+ checked program was:
76
+ /* begin */
77
+ 1: #include <stdlib.h>
78
+ /* end */
79
+
80
+ --------------------
81
+
82
+ have_header: checking for strings.h... -------------------- yes
83
+
84
+ "cc -E -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -o conftest.i"
85
+ checked program was:
86
+ /* begin */
87
+ 1: #include <strings.h>
88
+ /* end */
89
+
90
+ --------------------
91
+
92
+ have_header: checking for string.h... -------------------- yes
93
+
94
+ "cc -E -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -o conftest.i"
95
+ checked program was:
96
+ /* begin */
97
+ 1: #include <string.h>
98
+ /* end */
99
+
100
+ --------------------
101
+
102
+ have_header: checking for sys/stat.h... -------------------- yes
103
+
104
+ "cc -E -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -o conftest.i"
105
+ checked program was:
106
+ /* begin */
107
+ 1: #include <sys/stat.h>
108
+ /* end */
109
+
110
+ --------------------
111
+
112
+ have_header: checking for sys/types.h... -------------------- yes
113
+
114
+ "cc -E -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -o conftest.i"
115
+ checked program was:
116
+ /* begin */
117
+ 1: #include <sys/types.h>
118
+ /* end */
119
+
120
+ --------------------
121
+
122
+ have_header: checking for unistd.h... -------------------- yes
123
+
124
+ "cc -E -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -o conftest.i"
125
+ checked program was:
126
+ /* begin */
127
+ 1: #include <unistd.h>
128
+ /* end */
129
+
130
+ --------------------
131
+
132
+ have_func: checking for fopen_s()... -------------------- no
133
+
134
+ "cc -o conftest -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -L"." -L"/usr/lib" -L. -rdynamic -Wl,-export-dynamic -lruby1.8-static -lpthread -ldl -lcrypt -lm -lc"
135
+ conftest.c: In function 't':
136
+ conftest.c:3: error: 'fopen_s' undeclared (first use in this function)
137
+ conftest.c:3: error: (Each undeclared identifier is reported only once
138
+ conftest.c:3: error: for each function it appears in.)
139
+ checked program was:
140
+ /* begin */
141
+ 1: /*top*/
142
+ 2: int main() { return 0; }
143
+ 3: int t() { void ((*volatile p)()); p = (void ((*)()))fopen_s; return 0; }
144
+ /* end */
145
+
146
+ "cc -o conftest -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -L"." -L"/usr/lib" -L. -rdynamic -Wl,-export-dynamic -lruby1.8-static -lpthread -ldl -lcrypt -lm -lc"
147
+ /tmp/cc2cfDfe.o: In function `t':
148
+ /root/vcprojs/divsufsort/ext/conftest.c:3: undefined reference to `fopen_s'
149
+ collect2: ld returned 1 exit status
150
+ checked program was:
151
+ /* begin */
152
+ 1: /*top*/
153
+ 2: int main() { return 0; }
154
+ 3: int t() { fopen_s(); return 0; }
155
+ /* end */
156
+
157
+ --------------------
158
+
159
+ have_func: checking for malloc()... -------------------- no
160
+
161
+ "cc -o conftest -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -L"." -L"/usr/lib" -L. -rdynamic -Wl,-export-dynamic -lruby1.8-static -lpthread -ldl -lcrypt -lm -lc"
162
+ conftest.c: In function 't':
163
+ conftest.c:3: error: 'malloc' undeclared (first use in this function)
164
+ conftest.c:3: error: (Each undeclared identifier is reported only once
165
+ conftest.c:3: error: for each function it appears in.)
166
+ checked program was:
167
+ /* begin */
168
+ 1: /*top*/
169
+ 2: int main() { return 0; }
170
+ 3: int t() { void ((*volatile p)()); p = (void ((*)()))malloc; return 0; }
171
+ /* end */
172
+
173
+ "cc -o conftest -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -L"." -L"/usr/lib" -L. -rdynamic -Wl,-export-dynamic -lruby1.8-static -lpthread -ldl -lcrypt -lm -lc"
174
+ conftest.c: In function 't':
175
+ conftest.c:3: warning: incompatible implicit declaration of built-in function 'malloc'
176
+ conftest.c:3: error: too few arguments to function 'malloc'
177
+ checked program was:
178
+ /* begin */
179
+ 1: /*top*/
180
+ 2: int main() { return 0; }
181
+ 3: int t() { malloc(); return 0; }
182
+ /* end */
183
+
184
+ --------------------
185
+
186
+ have_func: checking for setmode()... -------------------- no
187
+
188
+ "cc -o conftest -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -L"." -L"/usr/lib" -L. -rdynamic -Wl,-export-dynamic -lruby1.8-static -lpthread -ldl -lcrypt -lm -lc"
189
+ conftest.c: In function 't':
190
+ conftest.c:3: error: 'setmode' undeclared (first use in this function)
191
+ conftest.c:3: error: (Each undeclared identifier is reported only once
192
+ conftest.c:3: error: for each function it appears in.)
193
+ checked program was:
194
+ /* begin */
195
+ 1: /*top*/
196
+ 2: int main() { return 0; }
197
+ 3: int t() { void ((*volatile p)()); p = (void ((*)()))setmode; return 0; }
198
+ /* end */
199
+
200
+ "cc -o conftest -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -L"." -L"/usr/lib" -L. -rdynamic -Wl,-export-dynamic -lruby1.8-static -lpthread -ldl -lcrypt -lm -lc"
201
+ /tmp/ccqnIFrj.o: In function `t':
202
+ /root/vcprojs/divsufsort/ext/conftest.c:3: undefined reference to `setmode'
203
+ collect2: ld returned 1 exit status
204
+ checked program was:
205
+ /* begin */
206
+ 1: /*top*/
207
+ 2: int main() { return 0; }
208
+ 3: int t() { setmode(); return 0; }
209
+ /* end */
210
+
211
+ --------------------
212
+
213
+ have_func: checking for _fileno()... -------------------- no
214
+
215
+ "cc -o conftest -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -L"." -L"/usr/lib" -L. -rdynamic -Wl,-export-dynamic -lruby1.8-static -lpthread -ldl -lcrypt -lm -lc"
216
+ conftest.c: In function 't':
217
+ conftest.c:3: error: '_fileno' undeclared (first use in this function)
218
+ conftest.c:3: error: (Each undeclared identifier is reported only once
219
+ conftest.c:3: error: for each function it appears in.)
220
+ checked program was:
221
+ /* begin */
222
+ 1: /*top*/
223
+ 2: int main() { return 0; }
224
+ 3: int t() { void ((*volatile p)()); p = (void ((*)()))_fileno; return 0; }
225
+ /* end */
226
+
227
+ "cc -o conftest -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -L"." -L"/usr/lib" -L. -rdynamic -Wl,-export-dynamic -lruby1.8-static -lpthread -ldl -lcrypt -lm -lc"
228
+ /tmp/ccQUsoeR.o: In function `t':
229
+ /root/vcprojs/divsufsort/ext/conftest.c:3: undefined reference to `_fileno'
230
+ collect2: ld returned 1 exit status
231
+ checked program was:
232
+ /* begin */
233
+ 1: /*top*/
234
+ 2: int main() { return 0; }
235
+ 3: int t() { _fileno(); return 0; }
236
+ /* end */
237
+
238
+ --------------------
239
+
240
+ have_func: checking for _setmode()... -------------------- no
241
+
242
+ "cc -o conftest -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -L"." -L"/usr/lib" -L. -rdynamic -Wl,-export-dynamic -lruby1.8-static -lpthread -ldl -lcrypt -lm -lc"
243
+ conftest.c: In function 't':
244
+ conftest.c:3: error: '_setmode' undeclared (first use in this function)
245
+ conftest.c:3: error: (Each undeclared identifier is reported only once
246
+ conftest.c:3: error: for each function it appears in.)
247
+ checked program was:
248
+ /* begin */
249
+ 1: /*top*/
250
+ 2: int main() { return 0; }
251
+ 3: int t() { void ((*volatile p)()); p = (void ((*)()))_setmode; return 0; }
252
+ /* end */
253
+
254
+ "cc -o conftest -I. -I/usr/lib/ruby/1.8/i486-linux -I. -fno-strict-aliasing -g -O2 -fPIC conftest.c -L"." -L"/usr/lib" -L. -rdynamic -Wl,-export-dynamic -lruby1.8-static -lpthread -ldl -lcrypt -lm -lc"
255
+ /tmp/ccuDDvVo.o: In function `t':
256
+ /root/vcprojs/divsufsort/ext/conftest.c:3: undefined reference to `_setmode'
257
+ collect2: ld returned 1 exit status
258
+ checked program was:
259
+ /* begin */
260
+ 1: /*top*/
261
+ 2: int main() { return 0; }
262
+ 3: int t() { _setmode(); return 0; }
263
+ /* end */
264
+
265
+ --------------------
266
+
@@ -0,0 +1,815 @@
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
+ }