@@ -98,6 +98,7 @@ typedef struct
98
98
{
99
99
char * lo ;
100
100
char * hi ;
101
+ size_t depth ;
101
102
} stack_node ;
102
103
103
104
/* The stack needs log (total_elements) entries (we could even subtract
@@ -107,22 +108,85 @@ typedef struct
107
108
enum { STACK_SIZE = CHAR_BIT * sizeof (size_t ) };
108
109
109
110
static inline stack_node *
110
- push (stack_node * top , char * lo , char * hi )
111
+ push (stack_node * top , char * lo , char * hi , size_t depth )
111
112
{
112
113
top -> lo = lo ;
113
114
top -> hi = hi ;
115
+ top -> depth = depth ;
114
116
return ++ top ;
115
117
}
116
118
117
119
static inline stack_node *
118
- pop (stack_node * top , char * * lo , char * * hi )
120
+ pop (stack_node * top , char * * lo , char * * hi , size_t * depth )
119
121
{
120
122
-- top ;
121
123
* lo = top -> lo ;
122
124
* hi = top -> hi ;
125
+ * depth = top -> depth ;
123
126
return top ;
124
127
}
125
128
129
+ /* NB: N is inclusive bound for BASE. */
130
+ static inline void
131
+ siftdown (void * base , size_t size , size_t k , size_t n ,
132
+ enum swap_type_t swap_type , __compar_d_fn_t cmp , void * arg )
133
+ {
134
+ while (k <= n / 2 )
135
+ {
136
+ size_t j = 2 * k ;
137
+ if (j < n && cmp (base + (j * size ), base + ((j + 1 ) * size ), arg ) < 0 )
138
+ j ++ ;
139
+
140
+ if (cmp (base + (k * size ), base + (j * size ), arg ) >= 0 )
141
+ break ;
142
+
143
+ do_swap (base + (size * j ), base + (k * size ), size , swap_type );
144
+ k = j ;
145
+ }
146
+ }
147
+
148
+ static inline void
149
+ heapify (void * base , size_t size , size_t n , enum swap_type_t swap_type ,
150
+ __compar_d_fn_t cmp , void * arg )
151
+ {
152
+ size_t k = n / 2 ;
153
+ while (1 )
154
+ {
155
+ siftdown (base , size , k , n , swap_type , cmp , arg );
156
+ if (k -- == 0 )
157
+ break ;
158
+ }
159
+ }
160
+
161
+ /* A non-recursive heapsort, used on introsort implementation as a fallback
162
+ routine with worst-case performance of O(nlog n) and worst-case space
163
+ complexity of O(1). It sorts the array starting at BASE and ending at
164
+ END, with each element of SIZE bytes. The SWAP_TYPE is the callback
165
+ function used to swap elements, and CMP is the function used to compare
166
+ elements. */
167
+ static void
168
+ heapsort_r (void * base , void * end , size_t size , enum swap_type_t swap_type ,
169
+ __compar_d_fn_t cmp , void * arg )
170
+ {
171
+ const size_t count = ((uintptr_t ) end - (uintptr_t ) base ) / size ;
172
+
173
+ if (count < 2 )
174
+ return ;
175
+
176
+ size_t n = count - 1 ;
177
+
178
+ /* Build the binary heap, largest value at the base[0]. */
179
+ heapify (base , size , n , swap_type , cmp , arg );
180
+
181
+ /* On each iteration base[0:n] is the binary heap, while base[n:count]
182
+ is sorted. */
183
+ while (n > 0 )
184
+ {
185
+ do_swap (base , base + (n * size ), size , swap_type );
186
+ n -- ;
187
+ siftdown (base , size , 0 , n , swap_type , cmp , arg );
188
+ }
189
+ }
126
190
127
191
static inline void
128
192
insertion_sort_qsort_partitions (void * const pbase , size_t total_elems ,
@@ -208,7 +272,7 @@ _quicksort (void *const pbase, size_t total_elems, size_t size,
208
272
209
273
const size_t max_thresh = MAX_THRESH * size ;
210
274
211
- if (total_elems == 0 )
275
+ if (total_elems <= 1 )
212
276
/* Avoid lossage with unsigned arithmetic below. */
213
277
return ;
214
278
@@ -220,15 +284,26 @@ _quicksort (void *const pbase, size_t total_elems, size_t size,
220
284
else
221
285
swap_type = SWAP_BYTES ;
222
286
287
+ /* Maximum depth before quicksort switches to heapsort. */
288
+ size_t depth = 2 * (sizeof (size_t ) * CHAR_BIT - 1
289
+ - __builtin_clzl (total_elems ));
290
+
223
291
if (total_elems > MAX_THRESH )
224
292
{
225
293
char * lo = base_ptr ;
226
294
char * hi = & lo [size * (total_elems - 1 )];
227
295
stack_node stack [STACK_SIZE ];
228
- stack_node * top = stack + 1 ;
296
+ stack_node * top = push ( stack , NULL , NULL , depth ) ;
229
297
230
298
while (stack < top )
231
299
{
300
+ if (depth == 0 )
301
+ {
302
+ heapsort_r (lo , hi , size , swap_type , cmp , arg );
303
+ top = pop (top , & lo , & hi , & depth );
304
+ continue ;
305
+ }
306
+
232
307
char * left_ptr ;
233
308
char * right_ptr ;
234
309
@@ -292,7 +367,7 @@ _quicksort (void *const pbase, size_t total_elems, size_t size,
292
367
{
293
368
if ((size_t ) (hi - left_ptr ) <= max_thresh )
294
369
/* Ignore both small partitions. */
295
- top = pop (top , & lo , & hi );
370
+ top = pop (top , & lo , & hi , & depth );
296
371
else
297
372
/* Ignore small left partition. */
298
373
lo = left_ptr ;
@@ -303,13 +378,13 @@ _quicksort (void *const pbase, size_t total_elems, size_t size,
303
378
else if ((right_ptr - lo ) > (hi - left_ptr ))
304
379
{
305
380
/* Push larger left partition indices. */
306
- top = push (top , lo , right_ptr );
381
+ top = push (top , lo , right_ptr , depth - 1 );
307
382
lo = left_ptr ;
308
383
}
309
384
else
310
385
{
311
386
/* Push larger right partition indices. */
312
- top = push (top , left_ptr , hi );
387
+ top = push (top , left_ptr , hi , depth - 1 );
313
388
hi = right_ptr ;
314
389
}
315
390
}
0 commit comments