GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/sort/radixsort.c Lines: 147 189 77.8 %
Date: 2016-12-06 Branches: 49 88 55.7 %

Line Branch Exec Source
1
/*	$OpenBSD: radixsort.c,v 1.5 2015/04/02 21:00:08 tobias Exp $	*/
2
3
/*-
4
 * Copyright (C) 2012 Oleg Moskalenko <mom040267@gmail.com>
5
 * Copyright (C) 2012 Gabor Kovesdan <gabor@FreeBSD.org>
6
 * All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
#include <errno.h>
31
#include <err.h>
32
#include <langinfo.h>
33
#include <math.h>
34
#include <stdlib.h>
35
#include <string.h>
36
#include <wchar.h>
37
#include <wctype.h>
38
#include <unistd.h>
39
40
#include "coll.h"
41
#include "radixsort.h"
42
43
#define DEFAULT_SORT_FUNC_RADIXSORT mergesort
44
45
#define TINY_NODE(sl) ((sl)->tosort_num < 65)
46
#define SMALL_NODE(sl) ((sl)->tosort_num < 5)
47
48
/* are we sorting in reverse order ? */
49
static bool reverse_sort;
50
51
/* sort sub-levels array size */
52
static const size_t slsz = 256 * sizeof(struct sort_level *);
53
54
/* one sort level structure */
55
struct sort_level {
56
	struct sort_level	**sublevels;
57
	struct sort_list_item	**leaves;
58
	struct sort_list_item	**sorted;
59
	struct sort_list_item	**tosort;
60
	size_t			  leaves_num;
61
	size_t			  leaves_sz;
62
	size_t			  level;
63
	size_t			  real_sln;
64
	size_t			  start_position;
65
	size_t			  sln;
66
	size_t			  tosort_num;
67
	size_t			  tosort_sz;
68
};
69
70
/* stack of sort levels ready to be sorted */
71
struct level_stack {
72
	struct level_stack	 *next;
73
	struct sort_level	 *sl;
74
};
75
76
static struct level_stack *g_ls;
77
78
/*
79
 * Push sort level to the stack
80
 */
81
static inline void
82
push_ls(struct sort_level *sl)
83
426
{
84
	struct level_stack *new_ls;
85
86
426
	new_ls = sort_malloc(sizeof(struct level_stack));
87
426
	new_ls->sl = sl;
88
89
426
	new_ls->next = g_ls;
90
426
	g_ls = new_ls;
91
426
}
92
93
/*
94
 * Pop sort level from the stack (single-threaded style)
95
 */
96
static inline struct sort_level *
97
pop_ls_st(void)
98
437
{
99
	struct sort_level *sl;
100
101
437
	if (g_ls) {
102
		struct level_stack *saved_ls;
103
104
426
		sl = g_ls->sl;
105
426
		saved_ls = g_ls;
106
426
		g_ls = g_ls->next;
107
426
		sort_free(saved_ls);
108
	} else
109
11
		sl = NULL;
110
111
437
	return sl;
112
}
113
114
static void
115
add_to_sublevel(struct sort_level *sl, struct sort_list_item *item, size_t indx)
116
35673
{
117
	struct sort_level *ssl;
118
119
35673
	ssl = sl->sublevels[indx];
120
121
35673
	if (ssl == NULL) {
122
467
		ssl = sort_calloc(1, sizeof(struct sort_level));
123
467
		ssl->level = sl->level + 1;
124
467
		sl->sublevels[indx] = ssl;
125
126
467
		++(sl->real_sln);
127
	}
128
129
35673
	if (++(ssl->tosort_num) > ssl->tosort_sz) {
130
671
		ssl->tosort_sz = ssl->tosort_num + 128;
131
671
		ssl->tosort = sort_reallocarray(ssl->tosort, ssl->tosort_sz,
132
		    sizeof(struct sort_list_item *));
133
	}
134
135
35673
	ssl->tosort[ssl->tosort_num - 1] = item;
136
35673
}
137
138
static inline void
139
add_leaf(struct sort_level *sl, struct sort_list_item *item)
140
{
141
	if (++(sl->leaves_num) > sl->leaves_sz) {
142
		sl->leaves_sz = sl->leaves_num + 128;
143
		sl->leaves = sort_reallocarray(sl->leaves, sl->leaves_sz,
144
		    sizeof(struct sort_list_item *));
145
	}
146
	sl->leaves[sl->leaves_num - 1] = item;
147
}
148
149
static inline int
150
get_wc_index(struct sort_list_item *sli, size_t level)
151
{
152
	const struct bwstring *bws;
153
154
35673
	bws = sli->ka.key[0].k;
155
156
35673
	if ((BWSLEN(bws) > level))
157
35673
		return (unsigned char)BWS_GET(bws, level);
158
	return -1;
159
}
160
161
static void
162
place_item(struct sort_level *sl, size_t item)
163
35673
{
164
	struct sort_list_item *sli;
165
	int c;
166
167
35673
	sli = sl->tosort[item];
168
71346
	c = get_wc_index(sli, sl->level);
169
170
35673
	if (c == -1)
171
		add_leaf(sl, sli);
172
	else
173
35673
		add_to_sublevel(sl, sli, c);
174
35673
}
175
176
static void
177
free_sort_level(struct sort_level *sl)
178
22238
{
179
22238
	if (sl) {
180
478
		sort_free(sl->leaves);
181
182
478
		if (sl->level > 0)
183
467
			sort_free(sl->tosort);
184
185
478
		if (sl->sublevels) {
186
			struct sort_level *slc;
187
			size_t i, sln;
188
189
85
			sln = sl->sln;
190
191
21845
			for (i = 0; i < sln; ++i) {
192
21760
				slc = sl->sublevels[i];
193
21760
				free_sort_level(slc);
194
			}
195
196
85
			sort_free(sl->sublevels);
197
		}
198
199
478
		sort_free(sl);
200
	}
201
22238
}
202
203
static void
204
run_sort_level_next(struct sort_level *sl)
205
467
{
206
	struct sort_level *slc;
207
	size_t i, sln, tosort_num;
208
209
467
	sort_free(sl->sublevels);
210
467
	sl->sublevels = NULL;
211
212

467
	switch (sl->tosort_num) {
213
	case 0:
214
		goto end;
215
	case 1:
216
49
		sl->sorted[sl->start_position] = sl->tosort[0];
217
49
		goto end;
218
	case 2:
219
16
		if (list_coll_offset(&(sl->tosort[0]), &(sl->tosort[1]),
220
		    sl->level) > 0) {
221
8
			sl->sorted[sl->start_position++] = sl->tosort[1];
222
8
			sl->sorted[sl->start_position] = sl->tosort[0];
223
		} else {
224
8
			sl->sorted[sl->start_position++] = sl->tosort[0];
225
8
			sl->sorted[sl->start_position] = sl->tosort[1];
226
		}
227
228
		goto end;
229
	default:
230

402
		if (TINY_NODE(sl) || (sl->level > 15)) {
231
			listcoll_t func;
232
233
328
			func = get_list_call_func(sl->level);
234
235
328
			sl->leaves = sl->tosort;
236
328
			sl->leaves_num = sl->tosort_num;
237
328
			sl->leaves_sz = sl->leaves_num;
238
328
			sl->leaves = sort_reallocarray(sl->leaves,
239
			    sl->leaves_sz, sizeof(struct sort_list_item *));
240
328
			sl->tosort = NULL;
241
328
			sl->tosort_num = 0;
242
328
			sl->tosort_sz = 0;
243
328
			sl->sln = 0;
244
328
			sl->real_sln = 0;
245
328
			if (sort_opts_vals.sflag) {
246
1
				if (mergesort(sl->leaves, sl->leaves_num,
247
				    sizeof(struct sort_list_item *),
248
				    (int(*)(const void *, const void *)) func) == -1)
249
					/* NOTREACHED */
250
					err(2, "Radix sort error 3");
251
			} else
252
327
				DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
253
				    sizeof(struct sort_list_item *),
254
				    (int(*)(const void *, const void *)) func);
255
256
328
			memcpy(sl->sorted + sl->start_position,
257
			    sl->leaves, sl->leaves_num *
258
			    sizeof(struct sort_list_item *));
259
260
328
			goto end;
261
		} else {
262
74
			sl->tosort_sz = sl->tosort_num;
263
74
			sl->tosort = sort_reallocarray(sl->tosort,
264
			    sl->tosort_sz, sizeof(struct sort_list_item *));
265
		}
266
	}
267
268
74
	sl->sln = 256;
269
74
	sl->sublevels = sort_calloc(1, slsz);
270
74
	sl->real_sln = 0;
271
272
74
	tosort_num = sl->tosort_num;
273
31897
	for (i = 0; i < tosort_num; ++i)
274
31823
		place_item(sl, i);
275
276
74
	sort_free(sl->tosort);
277
74
	sl->tosort = NULL;
278
74
	sl->tosort_num = 0;
279
74
	sl->tosort_sz = 0;
280
281
74
	if (sl->leaves_num > 1) {
282
		if (keys_num > 1) {
283
			if (sort_opts_vals.sflag) {
284
				mergesort(sl->leaves, sl->leaves_num,
285
				    sizeof(struct sort_list_item *), list_coll);
286
			} else {
287
				DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
288
				    sizeof(struct sort_list_item *), list_coll);
289
			}
290
		} else if (!sort_opts_vals.sflag && sort_opts_vals.complex_sort) {
291
			DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
292
			    sizeof(struct sort_list_item *), list_coll);
293
		}
294
	}
295
296
74
	sl->leaves_sz = sl->leaves_num;
297
74
	sl->leaves = sort_reallocarray(sl->leaves, sl->leaves_sz,
298
	    sizeof(struct sort_list_item *));
299
300
74
	if (!reverse_sort) {
301
74
		memcpy(sl->sorted + sl->start_position, sl->leaves,
302
		    sl->leaves_num * sizeof(struct sort_list_item *));
303
74
		sl->start_position += sl->leaves_num;
304
305
74
		sort_free(sl->leaves);
306
74
		sl->leaves = NULL;
307
74
		sl->leaves_num = 0;
308
74
		sl->leaves_sz = 0;
309
310
74
		sln = sl->sln;
311
312
19018
		for (i = 0; i < sln; ++i) {
313
18944
			slc = sl->sublevels[i];
314
315
18944
			if (slc) {
316
397
				slc->sorted = sl->sorted;
317
397
				slc->start_position = sl->start_position;
318
397
				sl->start_position += slc->tosort_num;
319
397
				if (SMALL_NODE(slc))
320
41
					run_sort_level_next(slc);
321
				else
322
356
					push_ls(slc);
323
397
				sl->sublevels[i] = NULL;
324
			}
325
		}
326
327
	} else {
328
		size_t n;
329
330
		sln = sl->sln;
331
332
		for (i = 0; i < sln; ++i) {
333
			n = sln - i - 1;
334
			slc = sl->sublevels[n];
335
336
			if (slc) {
337
				slc->sorted = sl->sorted;
338
				slc->start_position = sl->start_position;
339
				sl->start_position += slc->tosort_num;
340
				if (SMALL_NODE(slc))
341
					run_sort_level_next(slc);
342
				else
343
					push_ls(slc);
344
				sl->sublevels[n] = NULL;
345
			}
346
		}
347
348
		memcpy(sl->sorted + sl->start_position, sl->leaves,
349
		    sl->leaves_num * sizeof(struct sort_list_item *));
350
	}
351
352
467
end:
353
467
	free_sort_level(sl);
354
467
}
355
356
/*
357
 * Single-threaded sort cycle
358
 */
359
static void
360
run_sort_cycle_st(void)
361
437
{
362
	struct sort_level *slc;
363
364
	for (;;) {
365
437
		slc = pop_ls_st();
366
437
		if (slc == NULL) {
367
11
			break;
368
		}
369
426
		run_sort_level_next(slc);
370
426
	}
371
11
}
372
373
static void
374
run_top_sort_level(struct sort_level *sl)
375
11
{
376
	struct sort_level *slc;
377
	size_t i;
378
379
11
	reverse_sort = sort_opts_vals.kflag ? keys[0].sm.rflag :
380
	    default_sort_mods->rflag;
381
382
11
	sl->start_position = 0;
383
11
	sl->sln = 256;
384
11
	sl->sublevels = sort_calloc(1, slsz);
385
386
3861
	for (i = 0; i < sl->tosort_num; ++i)
387
3850
		place_item(sl, i);
388
389
11
	if (sl->leaves_num > 1) {
390
		if (keys_num > 1) {
391
			if (sort_opts_vals.sflag) {
392
				mergesort(sl->leaves, sl->leaves_num,
393
				    sizeof(struct sort_list_item *), list_coll);
394
			} else {
395
				DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
396
				    sizeof(struct sort_list_item *), list_coll);
397
			}
398
		} else if (!sort_opts_vals.sflag && sort_opts_vals.complex_sort) {
399
			DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
400
			    sizeof(struct sort_list_item *), list_coll);
401
		}
402
	}
403
404
11
	if (!reverse_sort) {
405
		size_t i;
406
407
11
		memcpy(sl->tosort + sl->start_position, sl->leaves,
408
		    sl->leaves_num * sizeof(struct sort_list_item *));
409
11
		sl->start_position += sl->leaves_num;
410
411
2827
		for (i = 0; i < sl->sln; ++i) {
412
2816
			slc = sl->sublevels[i];
413
414
2816
			if (slc) {
415
70
				slc->sorted = sl->tosort;
416
70
				slc->start_position = sl->start_position;
417
70
				sl->start_position += slc->tosort_num;
418
70
				push_ls(slc);
419
70
				sl->sublevels[i] = NULL;
420
			}
421
		}
422
423
	} else {
424
		size_t i, n;
425
426
		for (i = 0; i < sl->sln; ++i) {
427
428
			n = sl->sln - i - 1;
429
			slc = sl->sublevels[n];
430
431
			if (slc) {
432
				slc->sorted = sl->tosort;
433
				slc->start_position = sl->start_position;
434
				sl->start_position += slc->tosort_num;
435
				push_ls(slc);
436
				sl->sublevels[n] = NULL;
437
			}
438
		}
439
440
		memcpy(sl->tosort + sl->start_position, sl->leaves,
441
		    sl->leaves_num * sizeof(struct sort_list_item *));
442
	}
443
11
	run_sort_cycle_st();
444
11
}
445
446
void
447
rxsort(struct sort_list_item **base, size_t nmemb)
448
11
{
449
	struct sort_level *sl;
450
451
11
	sl = sort_calloc(1, sizeof(struct sort_level));
452
11
	sl->tosort = base;
453
11
	sl->tosort_num = nmemb;
454
11
	sl->tosort_sz = nmemb;
455
456
11
	run_top_sort_level(sl);
457
458
11
	free_sort_level(sl);
459
11
}