xref: /aosp_15_r20/external/lzma/C/BwtSort.c (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker /* BwtSort.c -- BWT block sorting
2*f6dc9357SAndroid Build Coastguard Worker 2023-04-02 : Igor Pavlov : Public domain */
3*f6dc9357SAndroid Build Coastguard Worker 
4*f6dc9357SAndroid Build Coastguard Worker #include "Precomp.h"
5*f6dc9357SAndroid Build Coastguard Worker 
6*f6dc9357SAndroid Build Coastguard Worker #include "BwtSort.h"
7*f6dc9357SAndroid Build Coastguard Worker #include "Sort.h"
8*f6dc9357SAndroid Build Coastguard Worker 
9*f6dc9357SAndroid Build Coastguard Worker /* #define BLOCK_SORT_USE_HEAP_SORT */
10*f6dc9357SAndroid Build Coastguard Worker 
11*f6dc9357SAndroid Build Coastguard Worker /* Don't change it !!! */
12*f6dc9357SAndroid Build Coastguard Worker #define kNumHashBytes 2
13*f6dc9357SAndroid Build Coastguard Worker #define kNumHashValues (1 << (kNumHashBytes * 8))
14*f6dc9357SAndroid Build Coastguard Worker 
15*f6dc9357SAndroid Build Coastguard Worker /* kNumRefBitsMax must be < (kNumHashBytes * 8) = 16 */
16*f6dc9357SAndroid Build Coastguard Worker #define kNumRefBitsMax 12
17*f6dc9357SAndroid Build Coastguard Worker 
18*f6dc9357SAndroid Build Coastguard Worker #define BS_TEMP_SIZE kNumHashValues
19*f6dc9357SAndroid Build Coastguard Worker 
20*f6dc9357SAndroid Build Coastguard Worker #ifdef BLOCK_SORT_EXTERNAL_FLAGS
21*f6dc9357SAndroid Build Coastguard Worker 
22*f6dc9357SAndroid Build Coastguard Worker /* 32 Flags in UInt32 word */
23*f6dc9357SAndroid Build Coastguard Worker #define kNumFlagsBits 5
24*f6dc9357SAndroid Build Coastguard Worker #define kNumFlagsInWord (1 << kNumFlagsBits)
25*f6dc9357SAndroid Build Coastguard Worker #define kFlagsMask (kNumFlagsInWord - 1)
26*f6dc9357SAndroid Build Coastguard Worker #define kAllFlags 0xFFFFFFFF
27*f6dc9357SAndroid Build Coastguard Worker 
28*f6dc9357SAndroid Build Coastguard Worker #else
29*f6dc9357SAndroid Build Coastguard Worker 
30*f6dc9357SAndroid Build Coastguard Worker #define kNumBitsMax 20
31*f6dc9357SAndroid Build Coastguard Worker #define kIndexMask ((1 << kNumBitsMax) - 1)
32*f6dc9357SAndroid Build Coastguard Worker #define kNumExtraBits (32 - kNumBitsMax)
33*f6dc9357SAndroid Build Coastguard Worker #define kNumExtra0Bits (kNumExtraBits - 2)
34*f6dc9357SAndroid Build Coastguard Worker #define kNumExtra0Mask ((1 << kNumExtra0Bits) - 1)
35*f6dc9357SAndroid Build Coastguard Worker 
36*f6dc9357SAndroid Build Coastguard Worker #define SetFinishedGroupSize(p, size) \
37*f6dc9357SAndroid Build Coastguard Worker   {  *(p) |= ((((size) - 1) & kNumExtra0Mask) << kNumBitsMax); \
38*f6dc9357SAndroid Build Coastguard Worker     if ((size) > (1 << kNumExtra0Bits)) { \
39*f6dc9357SAndroid Build Coastguard Worker     *(p) |= 0x40000000;  *((p) + 1) |= ((((size) - 1)>> kNumExtra0Bits) << kNumBitsMax); } } \
40*f6dc9357SAndroid Build Coastguard Worker 
SetGroupSize(UInt32 * p,UInt32 size)41*f6dc9357SAndroid Build Coastguard Worker static void SetGroupSize(UInt32 *p, UInt32 size)
42*f6dc9357SAndroid Build Coastguard Worker {
43*f6dc9357SAndroid Build Coastguard Worker   if (--size == 0)
44*f6dc9357SAndroid Build Coastguard Worker     return;
45*f6dc9357SAndroid Build Coastguard Worker   *p |= 0x80000000 | ((size & kNumExtra0Mask) << kNumBitsMax);
46*f6dc9357SAndroid Build Coastguard Worker   if (size >= (1 << kNumExtra0Bits))
47*f6dc9357SAndroid Build Coastguard Worker   {
48*f6dc9357SAndroid Build Coastguard Worker     *p |= 0x40000000;
49*f6dc9357SAndroid Build Coastguard Worker     p[1] |= ((size >> kNumExtra0Bits) << kNumBitsMax);
50*f6dc9357SAndroid Build Coastguard Worker   }
51*f6dc9357SAndroid Build Coastguard Worker }
52*f6dc9357SAndroid Build Coastguard Worker 
53*f6dc9357SAndroid Build Coastguard Worker #endif
54*f6dc9357SAndroid Build Coastguard Worker 
55*f6dc9357SAndroid Build Coastguard Worker /*
56*f6dc9357SAndroid Build Coastguard Worker SortGroup - is recursive Range-Sort function with HeapSort optimization for small blocks
57*f6dc9357SAndroid Build Coastguard Worker   "range" is not real range. It's only for optimization.
58*f6dc9357SAndroid Build Coastguard Worker returns: 1 - if there are groups, 0 - no more groups
59*f6dc9357SAndroid Build Coastguard Worker */
60*f6dc9357SAndroid Build Coastguard Worker 
61*f6dc9357SAndroid Build Coastguard Worker static
62*f6dc9357SAndroid Build Coastguard Worker UInt32
63*f6dc9357SAndroid Build Coastguard Worker Z7_FASTCALL
SortGroup(UInt32 BlockSize,UInt32 NumSortedBytes,UInt32 groupOffset,UInt32 groupSize,int NumRefBits,UInt32 * Indices,UInt32 left,UInt32 range)64*f6dc9357SAndroid Build Coastguard Worker SortGroup(UInt32 BlockSize, UInt32 NumSortedBytes, UInt32 groupOffset, UInt32 groupSize, int NumRefBits, UInt32 *Indices
65*f6dc9357SAndroid Build Coastguard Worker   #ifndef BLOCK_SORT_USE_HEAP_SORT
66*f6dc9357SAndroid Build Coastguard Worker   , UInt32 left, UInt32 range
67*f6dc9357SAndroid Build Coastguard Worker   #endif
68*f6dc9357SAndroid Build Coastguard Worker   )
69*f6dc9357SAndroid Build Coastguard Worker {
70*f6dc9357SAndroid Build Coastguard Worker   UInt32 *ind2 = Indices + groupOffset;
71*f6dc9357SAndroid Build Coastguard Worker   UInt32 *Groups;
72*f6dc9357SAndroid Build Coastguard Worker   if (groupSize <= 1)
73*f6dc9357SAndroid Build Coastguard Worker   {
74*f6dc9357SAndroid Build Coastguard Worker     /*
75*f6dc9357SAndroid Build Coastguard Worker     #ifndef BLOCK_SORT_EXTERNAL_FLAGS
76*f6dc9357SAndroid Build Coastguard Worker     SetFinishedGroupSize(ind2, 1)
77*f6dc9357SAndroid Build Coastguard Worker     #endif
78*f6dc9357SAndroid Build Coastguard Worker     */
79*f6dc9357SAndroid Build Coastguard Worker     return 0;
80*f6dc9357SAndroid Build Coastguard Worker   }
81*f6dc9357SAndroid Build Coastguard Worker   Groups = Indices + BlockSize + BS_TEMP_SIZE;
82*f6dc9357SAndroid Build Coastguard Worker   if (groupSize <= ((UInt32)1 << NumRefBits)
83*f6dc9357SAndroid Build Coastguard Worker       #ifndef BLOCK_SORT_USE_HEAP_SORT
84*f6dc9357SAndroid Build Coastguard Worker       && groupSize <= range
85*f6dc9357SAndroid Build Coastguard Worker       #endif
86*f6dc9357SAndroid Build Coastguard Worker       )
87*f6dc9357SAndroid Build Coastguard Worker   {
88*f6dc9357SAndroid Build Coastguard Worker     UInt32 *temp = Indices + BlockSize;
89*f6dc9357SAndroid Build Coastguard Worker     UInt32 j;
90*f6dc9357SAndroid Build Coastguard Worker     UInt32 mask, thereAreGroups, group, cg;
91*f6dc9357SAndroid Build Coastguard Worker     {
92*f6dc9357SAndroid Build Coastguard Worker       UInt32 gPrev;
93*f6dc9357SAndroid Build Coastguard Worker       UInt32 gRes = 0;
94*f6dc9357SAndroid Build Coastguard Worker       {
95*f6dc9357SAndroid Build Coastguard Worker         UInt32 sp = ind2[0] + NumSortedBytes;
96*f6dc9357SAndroid Build Coastguard Worker         if (sp >= BlockSize) sp -= BlockSize;
97*f6dc9357SAndroid Build Coastguard Worker         gPrev = Groups[sp];
98*f6dc9357SAndroid Build Coastguard Worker         temp[0] = (gPrev << NumRefBits);
99*f6dc9357SAndroid Build Coastguard Worker       }
100*f6dc9357SAndroid Build Coastguard Worker 
101*f6dc9357SAndroid Build Coastguard Worker       for (j = 1; j < groupSize; j++)
102*f6dc9357SAndroid Build Coastguard Worker       {
103*f6dc9357SAndroid Build Coastguard Worker         UInt32 sp = ind2[j] + NumSortedBytes;
104*f6dc9357SAndroid Build Coastguard Worker         UInt32 g;
105*f6dc9357SAndroid Build Coastguard Worker         if (sp >= BlockSize) sp -= BlockSize;
106*f6dc9357SAndroid Build Coastguard Worker         g = Groups[sp];
107*f6dc9357SAndroid Build Coastguard Worker         temp[j] = (g << NumRefBits) | j;
108*f6dc9357SAndroid Build Coastguard Worker         gRes |= (gPrev ^ g);
109*f6dc9357SAndroid Build Coastguard Worker       }
110*f6dc9357SAndroid Build Coastguard Worker       if (gRes == 0)
111*f6dc9357SAndroid Build Coastguard Worker       {
112*f6dc9357SAndroid Build Coastguard Worker         #ifndef BLOCK_SORT_EXTERNAL_FLAGS
113*f6dc9357SAndroid Build Coastguard Worker         SetGroupSize(ind2, groupSize);
114*f6dc9357SAndroid Build Coastguard Worker         #endif
115*f6dc9357SAndroid Build Coastguard Worker         return 1;
116*f6dc9357SAndroid Build Coastguard Worker       }
117*f6dc9357SAndroid Build Coastguard Worker     }
118*f6dc9357SAndroid Build Coastguard Worker 
119*f6dc9357SAndroid Build Coastguard Worker     HeapSort(temp, groupSize);
120*f6dc9357SAndroid Build Coastguard Worker     mask = (((UInt32)1 << NumRefBits) - 1);
121*f6dc9357SAndroid Build Coastguard Worker     thereAreGroups = 0;
122*f6dc9357SAndroid Build Coastguard Worker 
123*f6dc9357SAndroid Build Coastguard Worker     group = groupOffset;
124*f6dc9357SAndroid Build Coastguard Worker     cg = (temp[0] >> NumRefBits);
125*f6dc9357SAndroid Build Coastguard Worker     temp[0] = ind2[temp[0] & mask];
126*f6dc9357SAndroid Build Coastguard Worker 
127*f6dc9357SAndroid Build Coastguard Worker     {
128*f6dc9357SAndroid Build Coastguard Worker     #ifdef BLOCK_SORT_EXTERNAL_FLAGS
129*f6dc9357SAndroid Build Coastguard Worker     UInt32 *Flags = Groups + BlockSize;
130*f6dc9357SAndroid Build Coastguard Worker     #else
131*f6dc9357SAndroid Build Coastguard Worker     UInt32 prevGroupStart = 0;
132*f6dc9357SAndroid Build Coastguard Worker     #endif
133*f6dc9357SAndroid Build Coastguard Worker 
134*f6dc9357SAndroid Build Coastguard Worker     for (j = 1; j < groupSize; j++)
135*f6dc9357SAndroid Build Coastguard Worker     {
136*f6dc9357SAndroid Build Coastguard Worker       UInt32 val = temp[j];
137*f6dc9357SAndroid Build Coastguard Worker       UInt32 cgCur = (val >> NumRefBits);
138*f6dc9357SAndroid Build Coastguard Worker 
139*f6dc9357SAndroid Build Coastguard Worker       if (cgCur != cg)
140*f6dc9357SAndroid Build Coastguard Worker       {
141*f6dc9357SAndroid Build Coastguard Worker         cg = cgCur;
142*f6dc9357SAndroid Build Coastguard Worker         group = groupOffset + j;
143*f6dc9357SAndroid Build Coastguard Worker 
144*f6dc9357SAndroid Build Coastguard Worker         #ifdef BLOCK_SORT_EXTERNAL_FLAGS
145*f6dc9357SAndroid Build Coastguard Worker         {
146*f6dc9357SAndroid Build Coastguard Worker         UInt32 t = group - 1;
147*f6dc9357SAndroid Build Coastguard Worker         Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
148*f6dc9357SAndroid Build Coastguard Worker         }
149*f6dc9357SAndroid Build Coastguard Worker         #else
150*f6dc9357SAndroid Build Coastguard Worker         SetGroupSize(temp + prevGroupStart, j - prevGroupStart);
151*f6dc9357SAndroid Build Coastguard Worker         prevGroupStart = j;
152*f6dc9357SAndroid Build Coastguard Worker         #endif
153*f6dc9357SAndroid Build Coastguard Worker       }
154*f6dc9357SAndroid Build Coastguard Worker       else
155*f6dc9357SAndroid Build Coastguard Worker         thereAreGroups = 1;
156*f6dc9357SAndroid Build Coastguard Worker       {
157*f6dc9357SAndroid Build Coastguard Worker       UInt32 ind = ind2[val & mask];
158*f6dc9357SAndroid Build Coastguard Worker       temp[j] = ind;
159*f6dc9357SAndroid Build Coastguard Worker       Groups[ind] = group;
160*f6dc9357SAndroid Build Coastguard Worker       }
161*f6dc9357SAndroid Build Coastguard Worker     }
162*f6dc9357SAndroid Build Coastguard Worker 
163*f6dc9357SAndroid Build Coastguard Worker     #ifndef BLOCK_SORT_EXTERNAL_FLAGS
164*f6dc9357SAndroid Build Coastguard Worker     SetGroupSize(temp + prevGroupStart, j - prevGroupStart);
165*f6dc9357SAndroid Build Coastguard Worker     #endif
166*f6dc9357SAndroid Build Coastguard Worker     }
167*f6dc9357SAndroid Build Coastguard Worker 
168*f6dc9357SAndroid Build Coastguard Worker     for (j = 0; j < groupSize; j++)
169*f6dc9357SAndroid Build Coastguard Worker       ind2[j] = temp[j];
170*f6dc9357SAndroid Build Coastguard Worker     return thereAreGroups;
171*f6dc9357SAndroid Build Coastguard Worker   }
172*f6dc9357SAndroid Build Coastguard Worker 
173*f6dc9357SAndroid Build Coastguard Worker   /* Check that all strings are in one group (cannot sort) */
174*f6dc9357SAndroid Build Coastguard Worker   {
175*f6dc9357SAndroid Build Coastguard Worker     UInt32 group, j;
176*f6dc9357SAndroid Build Coastguard Worker     UInt32 sp = ind2[0] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
177*f6dc9357SAndroid Build Coastguard Worker     group = Groups[sp];
178*f6dc9357SAndroid Build Coastguard Worker     for (j = 1; j < groupSize; j++)
179*f6dc9357SAndroid Build Coastguard Worker     {
180*f6dc9357SAndroid Build Coastguard Worker       sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
181*f6dc9357SAndroid Build Coastguard Worker       if (Groups[sp] != group)
182*f6dc9357SAndroid Build Coastguard Worker         break;
183*f6dc9357SAndroid Build Coastguard Worker     }
184*f6dc9357SAndroid Build Coastguard Worker     if (j == groupSize)
185*f6dc9357SAndroid Build Coastguard Worker     {
186*f6dc9357SAndroid Build Coastguard Worker       #ifndef BLOCK_SORT_EXTERNAL_FLAGS
187*f6dc9357SAndroid Build Coastguard Worker       SetGroupSize(ind2, groupSize);
188*f6dc9357SAndroid Build Coastguard Worker       #endif
189*f6dc9357SAndroid Build Coastguard Worker       return 1;
190*f6dc9357SAndroid Build Coastguard Worker     }
191*f6dc9357SAndroid Build Coastguard Worker   }
192*f6dc9357SAndroid Build Coastguard Worker 
193*f6dc9357SAndroid Build Coastguard Worker   #ifndef BLOCK_SORT_USE_HEAP_SORT
194*f6dc9357SAndroid Build Coastguard Worker   {
195*f6dc9357SAndroid Build Coastguard Worker   /* ---------- Range Sort ---------- */
196*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
197*f6dc9357SAndroid Build Coastguard Worker   UInt32 mid;
198*f6dc9357SAndroid Build Coastguard Worker   for (;;)
199*f6dc9357SAndroid Build Coastguard Worker   {
200*f6dc9357SAndroid Build Coastguard Worker     UInt32 j;
201*f6dc9357SAndroid Build Coastguard Worker     if (range <= 1)
202*f6dc9357SAndroid Build Coastguard Worker     {
203*f6dc9357SAndroid Build Coastguard Worker       #ifndef BLOCK_SORT_EXTERNAL_FLAGS
204*f6dc9357SAndroid Build Coastguard Worker       SetGroupSize(ind2, groupSize);
205*f6dc9357SAndroid Build Coastguard Worker       #endif
206*f6dc9357SAndroid Build Coastguard Worker       return 1;
207*f6dc9357SAndroid Build Coastguard Worker     }
208*f6dc9357SAndroid Build Coastguard Worker     mid = left + ((range + 1) >> 1);
209*f6dc9357SAndroid Build Coastguard Worker     j = groupSize;
210*f6dc9357SAndroid Build Coastguard Worker     i = 0;
211*f6dc9357SAndroid Build Coastguard Worker     do
212*f6dc9357SAndroid Build Coastguard Worker     {
213*f6dc9357SAndroid Build Coastguard Worker       UInt32 sp = ind2[i] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
214*f6dc9357SAndroid Build Coastguard Worker       if (Groups[sp] >= mid)
215*f6dc9357SAndroid Build Coastguard Worker       {
216*f6dc9357SAndroid Build Coastguard Worker         for (j--; j > i; j--)
217*f6dc9357SAndroid Build Coastguard Worker         {
218*f6dc9357SAndroid Build Coastguard Worker           sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
219*f6dc9357SAndroid Build Coastguard Worker           if (Groups[sp] < mid)
220*f6dc9357SAndroid Build Coastguard Worker           {
221*f6dc9357SAndroid Build Coastguard Worker             UInt32 temp = ind2[i]; ind2[i] = ind2[j]; ind2[j] = temp;
222*f6dc9357SAndroid Build Coastguard Worker             break;
223*f6dc9357SAndroid Build Coastguard Worker           }
224*f6dc9357SAndroid Build Coastguard Worker         }
225*f6dc9357SAndroid Build Coastguard Worker         if (i >= j)
226*f6dc9357SAndroid Build Coastguard Worker           break;
227*f6dc9357SAndroid Build Coastguard Worker       }
228*f6dc9357SAndroid Build Coastguard Worker     }
229*f6dc9357SAndroid Build Coastguard Worker     while (++i < j);
230*f6dc9357SAndroid Build Coastguard Worker     if (i == 0)
231*f6dc9357SAndroid Build Coastguard Worker     {
232*f6dc9357SAndroid Build Coastguard Worker       range = range - (mid - left);
233*f6dc9357SAndroid Build Coastguard Worker       left = mid;
234*f6dc9357SAndroid Build Coastguard Worker     }
235*f6dc9357SAndroid Build Coastguard Worker     else if (i == groupSize)
236*f6dc9357SAndroid Build Coastguard Worker       range = (mid - left);
237*f6dc9357SAndroid Build Coastguard Worker     else
238*f6dc9357SAndroid Build Coastguard Worker       break;
239*f6dc9357SAndroid Build Coastguard Worker   }
240*f6dc9357SAndroid Build Coastguard Worker 
241*f6dc9357SAndroid Build Coastguard Worker   #ifdef BLOCK_SORT_EXTERNAL_FLAGS
242*f6dc9357SAndroid Build Coastguard Worker   {
243*f6dc9357SAndroid Build Coastguard Worker     UInt32 t = (groupOffset + i - 1);
244*f6dc9357SAndroid Build Coastguard Worker     UInt32 *Flags = Groups + BlockSize;
245*f6dc9357SAndroid Build Coastguard Worker     Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
246*f6dc9357SAndroid Build Coastguard Worker   }
247*f6dc9357SAndroid Build Coastguard Worker   #endif
248*f6dc9357SAndroid Build Coastguard Worker 
249*f6dc9357SAndroid Build Coastguard Worker   {
250*f6dc9357SAndroid Build Coastguard Worker     UInt32 j;
251*f6dc9357SAndroid Build Coastguard Worker     for (j = i; j < groupSize; j++)
252*f6dc9357SAndroid Build Coastguard Worker       Groups[ind2[j]] = groupOffset + i;
253*f6dc9357SAndroid Build Coastguard Worker   }
254*f6dc9357SAndroid Build Coastguard Worker 
255*f6dc9357SAndroid Build Coastguard Worker   {
256*f6dc9357SAndroid Build Coastguard Worker   UInt32 res = SortGroup(BlockSize, NumSortedBytes, groupOffset, i, NumRefBits, Indices, left, mid - left);
257*f6dc9357SAndroid Build Coastguard Worker   return res | SortGroup(BlockSize, NumSortedBytes, groupOffset + i, groupSize - i, NumRefBits, Indices, mid, range - (mid - left));
258*f6dc9357SAndroid Build Coastguard Worker   }
259*f6dc9357SAndroid Build Coastguard Worker 
260*f6dc9357SAndroid Build Coastguard Worker   }
261*f6dc9357SAndroid Build Coastguard Worker 
262*f6dc9357SAndroid Build Coastguard Worker   #else
263*f6dc9357SAndroid Build Coastguard Worker 
264*f6dc9357SAndroid Build Coastguard Worker   /* ---------- Heap Sort ---------- */
265*f6dc9357SAndroid Build Coastguard Worker 
266*f6dc9357SAndroid Build Coastguard Worker   {
267*f6dc9357SAndroid Build Coastguard Worker     UInt32 j;
268*f6dc9357SAndroid Build Coastguard Worker     for (j = 0; j < groupSize; j++)
269*f6dc9357SAndroid Build Coastguard Worker     {
270*f6dc9357SAndroid Build Coastguard Worker       UInt32 sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
271*f6dc9357SAndroid Build Coastguard Worker       ind2[j] = sp;
272*f6dc9357SAndroid Build Coastguard Worker     }
273*f6dc9357SAndroid Build Coastguard Worker 
274*f6dc9357SAndroid Build Coastguard Worker     HeapSortRef(ind2, Groups, groupSize);
275*f6dc9357SAndroid Build Coastguard Worker 
276*f6dc9357SAndroid Build Coastguard Worker     /* Write Flags */
277*f6dc9357SAndroid Build Coastguard Worker     {
278*f6dc9357SAndroid Build Coastguard Worker     UInt32 sp = ind2[0];
279*f6dc9357SAndroid Build Coastguard Worker     UInt32 group = Groups[sp];
280*f6dc9357SAndroid Build Coastguard Worker 
281*f6dc9357SAndroid Build Coastguard Worker     #ifdef BLOCK_SORT_EXTERNAL_FLAGS
282*f6dc9357SAndroid Build Coastguard Worker     UInt32 *Flags = Groups + BlockSize;
283*f6dc9357SAndroid Build Coastguard Worker     #else
284*f6dc9357SAndroid Build Coastguard Worker     UInt32 prevGroupStart = 0;
285*f6dc9357SAndroid Build Coastguard Worker     #endif
286*f6dc9357SAndroid Build Coastguard Worker 
287*f6dc9357SAndroid Build Coastguard Worker     for (j = 1; j < groupSize; j++)
288*f6dc9357SAndroid Build Coastguard Worker     {
289*f6dc9357SAndroid Build Coastguard Worker       sp = ind2[j];
290*f6dc9357SAndroid Build Coastguard Worker       if (Groups[sp] != group)
291*f6dc9357SAndroid Build Coastguard Worker       {
292*f6dc9357SAndroid Build Coastguard Worker         group = Groups[sp];
293*f6dc9357SAndroid Build Coastguard Worker         #ifdef BLOCK_SORT_EXTERNAL_FLAGS
294*f6dc9357SAndroid Build Coastguard Worker         {
295*f6dc9357SAndroid Build Coastguard Worker         UInt32 t = groupOffset + j - 1;
296*f6dc9357SAndroid Build Coastguard Worker         Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
297*f6dc9357SAndroid Build Coastguard Worker         }
298*f6dc9357SAndroid Build Coastguard Worker         #else
299*f6dc9357SAndroid Build Coastguard Worker         SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart);
300*f6dc9357SAndroid Build Coastguard Worker         prevGroupStart = j;
301*f6dc9357SAndroid Build Coastguard Worker         #endif
302*f6dc9357SAndroid Build Coastguard Worker       }
303*f6dc9357SAndroid Build Coastguard Worker     }
304*f6dc9357SAndroid Build Coastguard Worker 
305*f6dc9357SAndroid Build Coastguard Worker     #ifndef BLOCK_SORT_EXTERNAL_FLAGS
306*f6dc9357SAndroid Build Coastguard Worker     SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart);
307*f6dc9357SAndroid Build Coastguard Worker     #endif
308*f6dc9357SAndroid Build Coastguard Worker     }
309*f6dc9357SAndroid Build Coastguard Worker     {
310*f6dc9357SAndroid Build Coastguard Worker     /* Write new Groups values and Check that there are groups */
311*f6dc9357SAndroid Build Coastguard Worker     UInt32 thereAreGroups = 0;
312*f6dc9357SAndroid Build Coastguard Worker     for (j = 0; j < groupSize; j++)
313*f6dc9357SAndroid Build Coastguard Worker     {
314*f6dc9357SAndroid Build Coastguard Worker       UInt32 group = groupOffset + j;
315*f6dc9357SAndroid Build Coastguard Worker       #ifndef BLOCK_SORT_EXTERNAL_FLAGS
316*f6dc9357SAndroid Build Coastguard Worker       UInt32 subGroupSize = ((ind2[j] & ~0xC0000000) >> kNumBitsMax);
317*f6dc9357SAndroid Build Coastguard Worker       if ((ind2[j] & 0x40000000) != 0)
318*f6dc9357SAndroid Build Coastguard Worker         subGroupSize += ((ind2[(size_t)j + 1] >> kNumBitsMax) << kNumExtra0Bits);
319*f6dc9357SAndroid Build Coastguard Worker       subGroupSize++;
320*f6dc9357SAndroid Build Coastguard Worker       for (;;)
321*f6dc9357SAndroid Build Coastguard Worker       {
322*f6dc9357SAndroid Build Coastguard Worker         UInt32 original = ind2[j];
323*f6dc9357SAndroid Build Coastguard Worker         UInt32 sp = original & kIndexMask;
324*f6dc9357SAndroid Build Coastguard Worker         if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes;
325*f6dc9357SAndroid Build Coastguard Worker         ind2[j] = sp | (original & ~kIndexMask);
326*f6dc9357SAndroid Build Coastguard Worker         Groups[sp] = group;
327*f6dc9357SAndroid Build Coastguard Worker         if (--subGroupSize == 0)
328*f6dc9357SAndroid Build Coastguard Worker           break;
329*f6dc9357SAndroid Build Coastguard Worker         j++;
330*f6dc9357SAndroid Build Coastguard Worker         thereAreGroups = 1;
331*f6dc9357SAndroid Build Coastguard Worker       }
332*f6dc9357SAndroid Build Coastguard Worker       #else
333*f6dc9357SAndroid Build Coastguard Worker       UInt32 *Flags = Groups + BlockSize;
334*f6dc9357SAndroid Build Coastguard Worker       for (;;)
335*f6dc9357SAndroid Build Coastguard Worker       {
336*f6dc9357SAndroid Build Coastguard Worker         UInt32 sp = ind2[j]; if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes;
337*f6dc9357SAndroid Build Coastguard Worker         ind2[j] = sp;
338*f6dc9357SAndroid Build Coastguard Worker         Groups[sp] = group;
339*f6dc9357SAndroid Build Coastguard Worker         if ((Flags[(groupOffset + j) >> kNumFlagsBits] & (1 << ((groupOffset + j) & kFlagsMask))) == 0)
340*f6dc9357SAndroid Build Coastguard Worker           break;
341*f6dc9357SAndroid Build Coastguard Worker         j++;
342*f6dc9357SAndroid Build Coastguard Worker         thereAreGroups = 1;
343*f6dc9357SAndroid Build Coastguard Worker       }
344*f6dc9357SAndroid Build Coastguard Worker       #endif
345*f6dc9357SAndroid Build Coastguard Worker     }
346*f6dc9357SAndroid Build Coastguard Worker     return thereAreGroups;
347*f6dc9357SAndroid Build Coastguard Worker     }
348*f6dc9357SAndroid Build Coastguard Worker   }
349*f6dc9357SAndroid Build Coastguard Worker   #endif
350*f6dc9357SAndroid Build Coastguard Worker }
351*f6dc9357SAndroid Build Coastguard Worker 
352*f6dc9357SAndroid Build Coastguard Worker /* conditions: blockSize > 0 */
BlockSort(UInt32 * Indices,const Byte * data,UInt32 blockSize)353*f6dc9357SAndroid Build Coastguard Worker UInt32 BlockSort(UInt32 *Indices, const Byte *data, UInt32 blockSize)
354*f6dc9357SAndroid Build Coastguard Worker {
355*f6dc9357SAndroid Build Coastguard Worker   UInt32 *counters = Indices + blockSize;
356*f6dc9357SAndroid Build Coastguard Worker   UInt32 i;
357*f6dc9357SAndroid Build Coastguard Worker   UInt32 *Groups;
358*f6dc9357SAndroid Build Coastguard Worker   #ifdef BLOCK_SORT_EXTERNAL_FLAGS
359*f6dc9357SAndroid Build Coastguard Worker   UInt32 *Flags;
360*f6dc9357SAndroid Build Coastguard Worker   #endif
361*f6dc9357SAndroid Build Coastguard Worker 
362*f6dc9357SAndroid Build Coastguard Worker   /* Radix-Sort for 2 bytes */
363*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < kNumHashValues; i++)
364*f6dc9357SAndroid Build Coastguard Worker     counters[i] = 0;
365*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < blockSize - 1; i++)
366*f6dc9357SAndroid Build Coastguard Worker     counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]++;
367*f6dc9357SAndroid Build Coastguard Worker   counters[((UInt32)data[i] << 8) | data[0]]++;
368*f6dc9357SAndroid Build Coastguard Worker 
369*f6dc9357SAndroid Build Coastguard Worker   Groups = counters + BS_TEMP_SIZE;
370*f6dc9357SAndroid Build Coastguard Worker   #ifdef BLOCK_SORT_EXTERNAL_FLAGS
371*f6dc9357SAndroid Build Coastguard Worker   Flags = Groups + blockSize;
372*f6dc9357SAndroid Build Coastguard Worker     {
373*f6dc9357SAndroid Build Coastguard Worker       UInt32 numWords = (blockSize + kFlagsMask) >> kNumFlagsBits;
374*f6dc9357SAndroid Build Coastguard Worker       for (i = 0; i < numWords; i++)
375*f6dc9357SAndroid Build Coastguard Worker         Flags[i] = kAllFlags;
376*f6dc9357SAndroid Build Coastguard Worker     }
377*f6dc9357SAndroid Build Coastguard Worker   #endif
378*f6dc9357SAndroid Build Coastguard Worker 
379*f6dc9357SAndroid Build Coastguard Worker   {
380*f6dc9357SAndroid Build Coastguard Worker     UInt32 sum = 0;
381*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < kNumHashValues; i++)
382*f6dc9357SAndroid Build Coastguard Worker     {
383*f6dc9357SAndroid Build Coastguard Worker       UInt32 groupSize = counters[i];
384*f6dc9357SAndroid Build Coastguard Worker       if (groupSize > 0)
385*f6dc9357SAndroid Build Coastguard Worker       {
386*f6dc9357SAndroid Build Coastguard Worker         #ifdef BLOCK_SORT_EXTERNAL_FLAGS
387*f6dc9357SAndroid Build Coastguard Worker         UInt32 t = sum + groupSize - 1;
388*f6dc9357SAndroid Build Coastguard Worker         Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
389*f6dc9357SAndroid Build Coastguard Worker         #endif
390*f6dc9357SAndroid Build Coastguard Worker         sum += groupSize;
391*f6dc9357SAndroid Build Coastguard Worker       }
392*f6dc9357SAndroid Build Coastguard Worker       counters[i] = sum - groupSize;
393*f6dc9357SAndroid Build Coastguard Worker     }
394*f6dc9357SAndroid Build Coastguard Worker 
395*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < blockSize - 1; i++)
396*f6dc9357SAndroid Build Coastguard Worker       Groups[i] = counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]];
397*f6dc9357SAndroid Build Coastguard Worker     Groups[i] = counters[((UInt32)data[i] << 8) | data[0]];
398*f6dc9357SAndroid Build Coastguard Worker 
399*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < blockSize - 1; i++)
400*f6dc9357SAndroid Build Coastguard Worker       Indices[counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]++] = i;
401*f6dc9357SAndroid Build Coastguard Worker     Indices[counters[((UInt32)data[i] << 8) | data[0]]++] = i;
402*f6dc9357SAndroid Build Coastguard Worker 
403*f6dc9357SAndroid Build Coastguard Worker     #ifndef BLOCK_SORT_EXTERNAL_FLAGS
404*f6dc9357SAndroid Build Coastguard Worker     {
405*f6dc9357SAndroid Build Coastguard Worker     UInt32 prev = 0;
406*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < kNumHashValues; i++)
407*f6dc9357SAndroid Build Coastguard Worker     {
408*f6dc9357SAndroid Build Coastguard Worker       UInt32 prevGroupSize = counters[i] - prev;
409*f6dc9357SAndroid Build Coastguard Worker       if (prevGroupSize == 0)
410*f6dc9357SAndroid Build Coastguard Worker         continue;
411*f6dc9357SAndroid Build Coastguard Worker       SetGroupSize(Indices + prev, prevGroupSize);
412*f6dc9357SAndroid Build Coastguard Worker       prev = counters[i];
413*f6dc9357SAndroid Build Coastguard Worker     }
414*f6dc9357SAndroid Build Coastguard Worker     }
415*f6dc9357SAndroid Build Coastguard Worker     #endif
416*f6dc9357SAndroid Build Coastguard Worker   }
417*f6dc9357SAndroid Build Coastguard Worker 
418*f6dc9357SAndroid Build Coastguard Worker   {
419*f6dc9357SAndroid Build Coastguard Worker   int NumRefBits;
420*f6dc9357SAndroid Build Coastguard Worker   UInt32 NumSortedBytes;
421*f6dc9357SAndroid Build Coastguard Worker   for (NumRefBits = 0; ((blockSize - 1) >> NumRefBits) != 0; NumRefBits++);
422*f6dc9357SAndroid Build Coastguard Worker   NumRefBits = 32 - NumRefBits;
423*f6dc9357SAndroid Build Coastguard Worker   if (NumRefBits > kNumRefBitsMax)
424*f6dc9357SAndroid Build Coastguard Worker     NumRefBits = kNumRefBitsMax;
425*f6dc9357SAndroid Build Coastguard Worker 
426*f6dc9357SAndroid Build Coastguard Worker   for (NumSortedBytes = kNumHashBytes; ; NumSortedBytes <<= 1)
427*f6dc9357SAndroid Build Coastguard Worker   {
428*f6dc9357SAndroid Build Coastguard Worker     #ifndef BLOCK_SORT_EXTERNAL_FLAGS
429*f6dc9357SAndroid Build Coastguard Worker     UInt32 finishedGroupSize = 0;
430*f6dc9357SAndroid Build Coastguard Worker     #endif
431*f6dc9357SAndroid Build Coastguard Worker     UInt32 newLimit = 0;
432*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < blockSize;)
433*f6dc9357SAndroid Build Coastguard Worker     {
434*f6dc9357SAndroid Build Coastguard Worker       UInt32 groupSize;
435*f6dc9357SAndroid Build Coastguard Worker       #ifdef BLOCK_SORT_EXTERNAL_FLAGS
436*f6dc9357SAndroid Build Coastguard Worker 
437*f6dc9357SAndroid Build Coastguard Worker       if ((Flags[i >> kNumFlagsBits] & (1 << (i & kFlagsMask))) == 0)
438*f6dc9357SAndroid Build Coastguard Worker       {
439*f6dc9357SAndroid Build Coastguard Worker         i++;
440*f6dc9357SAndroid Build Coastguard Worker         continue;
441*f6dc9357SAndroid Build Coastguard Worker       }
442*f6dc9357SAndroid Build Coastguard Worker       for (groupSize = 1;
443*f6dc9357SAndroid Build Coastguard Worker         (Flags[(i + groupSize) >> kNumFlagsBits] & (1 << ((i + groupSize) & kFlagsMask))) != 0;
444*f6dc9357SAndroid Build Coastguard Worker         groupSize++);
445*f6dc9357SAndroid Build Coastguard Worker 
446*f6dc9357SAndroid Build Coastguard Worker       groupSize++;
447*f6dc9357SAndroid Build Coastguard Worker 
448*f6dc9357SAndroid Build Coastguard Worker       #else
449*f6dc9357SAndroid Build Coastguard Worker 
450*f6dc9357SAndroid Build Coastguard Worker       groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax);
451*f6dc9357SAndroid Build Coastguard Worker       {
452*f6dc9357SAndroid Build Coastguard Worker       BoolInt finishedGroup = ((Indices[i] & 0x80000000) == 0);
453*f6dc9357SAndroid Build Coastguard Worker       if ((Indices[i] & 0x40000000) != 0)
454*f6dc9357SAndroid Build Coastguard Worker       {
455*f6dc9357SAndroid Build Coastguard Worker         groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits);
456*f6dc9357SAndroid Build Coastguard Worker         Indices[(size_t)i + 1] &= kIndexMask;
457*f6dc9357SAndroid Build Coastguard Worker       }
458*f6dc9357SAndroid Build Coastguard Worker       Indices[i] &= kIndexMask;
459*f6dc9357SAndroid Build Coastguard Worker       groupSize++;
460*f6dc9357SAndroid Build Coastguard Worker       if (finishedGroup || groupSize == 1)
461*f6dc9357SAndroid Build Coastguard Worker       {
462*f6dc9357SAndroid Build Coastguard Worker         Indices[i - finishedGroupSize] &= kIndexMask;
463*f6dc9357SAndroid Build Coastguard Worker         if (finishedGroupSize > 1)
464*f6dc9357SAndroid Build Coastguard Worker           Indices[(size_t)(i - finishedGroupSize) + 1] &= kIndexMask;
465*f6dc9357SAndroid Build Coastguard Worker         {
466*f6dc9357SAndroid Build Coastguard Worker         UInt32 newGroupSize = groupSize + finishedGroupSize;
467*f6dc9357SAndroid Build Coastguard Worker         SetFinishedGroupSize(Indices + i - finishedGroupSize, newGroupSize)
468*f6dc9357SAndroid Build Coastguard Worker         finishedGroupSize = newGroupSize;
469*f6dc9357SAndroid Build Coastguard Worker         }
470*f6dc9357SAndroid Build Coastguard Worker         i += groupSize;
471*f6dc9357SAndroid Build Coastguard Worker         continue;
472*f6dc9357SAndroid Build Coastguard Worker       }
473*f6dc9357SAndroid Build Coastguard Worker       finishedGroupSize = 0;
474*f6dc9357SAndroid Build Coastguard Worker       }
475*f6dc9357SAndroid Build Coastguard Worker 
476*f6dc9357SAndroid Build Coastguard Worker       #endif
477*f6dc9357SAndroid Build Coastguard Worker 
478*f6dc9357SAndroid Build Coastguard Worker       if (NumSortedBytes >= blockSize)
479*f6dc9357SAndroid Build Coastguard Worker       {
480*f6dc9357SAndroid Build Coastguard Worker         UInt32 j;
481*f6dc9357SAndroid Build Coastguard Worker         for (j = 0; j < groupSize; j++)
482*f6dc9357SAndroid Build Coastguard Worker         {
483*f6dc9357SAndroid Build Coastguard Worker           UInt32 t = (i + j);
484*f6dc9357SAndroid Build Coastguard Worker           /* Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); */
485*f6dc9357SAndroid Build Coastguard Worker           Groups[Indices[t]] = t;
486*f6dc9357SAndroid Build Coastguard Worker         }
487*f6dc9357SAndroid Build Coastguard Worker       }
488*f6dc9357SAndroid Build Coastguard Worker       else
489*f6dc9357SAndroid Build Coastguard Worker         if (SortGroup(blockSize, NumSortedBytes, i, groupSize, NumRefBits, Indices
490*f6dc9357SAndroid Build Coastguard Worker           #ifndef BLOCK_SORT_USE_HEAP_SORT
491*f6dc9357SAndroid Build Coastguard Worker           , 0, blockSize
492*f6dc9357SAndroid Build Coastguard Worker           #endif
493*f6dc9357SAndroid Build Coastguard Worker           ) != 0)
494*f6dc9357SAndroid Build Coastguard Worker           newLimit = i + groupSize;
495*f6dc9357SAndroid Build Coastguard Worker       i += groupSize;
496*f6dc9357SAndroid Build Coastguard Worker     }
497*f6dc9357SAndroid Build Coastguard Worker     if (newLimit == 0)
498*f6dc9357SAndroid Build Coastguard Worker       break;
499*f6dc9357SAndroid Build Coastguard Worker   }
500*f6dc9357SAndroid Build Coastguard Worker   }
501*f6dc9357SAndroid Build Coastguard Worker   #ifndef BLOCK_SORT_EXTERNAL_FLAGS
502*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < blockSize;)
503*f6dc9357SAndroid Build Coastguard Worker   {
504*f6dc9357SAndroid Build Coastguard Worker     UInt32 groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax);
505*f6dc9357SAndroid Build Coastguard Worker     if ((Indices[i] & 0x40000000) != 0)
506*f6dc9357SAndroid Build Coastguard Worker     {
507*f6dc9357SAndroid Build Coastguard Worker       groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits);
508*f6dc9357SAndroid Build Coastguard Worker       Indices[(size_t)i + 1] &= kIndexMask;
509*f6dc9357SAndroid Build Coastguard Worker     }
510*f6dc9357SAndroid Build Coastguard Worker     Indices[i] &= kIndexMask;
511*f6dc9357SAndroid Build Coastguard Worker     groupSize++;
512*f6dc9357SAndroid Build Coastguard Worker     i += groupSize;
513*f6dc9357SAndroid Build Coastguard Worker   }
514*f6dc9357SAndroid Build Coastguard Worker   #endif
515*f6dc9357SAndroid Build Coastguard Worker   return Groups[0];
516*f6dc9357SAndroid Build Coastguard Worker }
517