diff options
Diffstat (limited to 'lib/sort.c')
| -rw-r--r-- | lib/sort.c | 20 | 
1 files changed, 15 insertions, 5 deletions
diff --git a/lib/sort.c b/lib/sort.c index b399bf10d675..a0509088f82a 100644 --- a/lib/sort.c +++ b/lib/sort.c @@ -215,6 +215,7 @@ void sort_r(void *base, size_t num, size_t size,  	/* pre-scale counters for performance */  	size_t n = num * size, a = (num/2) * size;  	const unsigned int lsbit = size & -size;  /* Used to find parent */ +	size_t shift = 0;  	if (!a)		/* num < 2 || size == 0 */  		return; @@ -242,12 +243,21 @@ void sort_r(void *base, size_t num, size_t size,  	for (;;) {  		size_t b, c, d; -		if (a)			/* Building heap: sift down --a */ -			a -= size; -		else if (n -= size)	/* Sorting: Extract root to --n */ +		if (a)			/* Building heap: sift down a */ +			a -= size << shift; +		else if (n > 3 * size) { /* Sorting: Extract two largest elements */ +			n -= size;  			do_swap(base, base + n, size, swap_func, priv); -		else			/* Sort complete */ +			shift = do_cmp(base + size, base + 2 * size, cmp_func, priv) <= 0; +			a = size << shift; +			n -= size; +			do_swap(base + a, base + n, size, swap_func, priv); +		} else if (n > size) {	/* Sorting: Extract root */ +			n -= size; +			do_swap(base, base + n, size, swap_func, priv); +		} else	{		/* Sort complete */  			break; +		}  		/*  		 * Sift element at "a" down into heap.  This is the @@ -262,7 +272,7 @@ void sort_r(void *base, size_t num, size_t size,  		 * average, 3/4 worst-case.)  		 */  		for (b = a; c = 2*b + size, (d = c + size) < n;) -			b = do_cmp(base + c, base + d, cmp_func, priv) >= 0 ? c : d; +			b = do_cmp(base + c, base + d, cmp_func, priv) > 0 ? c : d;  		if (d == n)	/* Special case last leaf with no sibling */  			b = c;  | 
