/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1991, 19934* The Regents of the University of California. All rights reserved.5* Copyright (c) 2014 David T. Chisnall6* All rights reserved.7*8* This code is derived from software contributed to Berkeley by9* Ronnie Kon at Mindcraft Inc., Kevin Lew and Elmer Yglesias.10*11* Redistribution and use in source and binary forms, with or without12* modification, are permitted provided that the following conditions13* are met:14* 1. Redistributions of source code must retain the above copyright15* notice, this list of conditions and the following disclaimer.16* 2. Redistributions in binary form must reproduce the above copyright17* notice, this list of conditions and the following disclaimer in the18* documentation and/or other materials provided with the distribution.19* 3. Neither the name of the University nor the names of its contributors20* may be used to endorse or promote products derived from this software21* without specific prior written permission.22*23* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND24* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE25* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE26* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE27* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL28* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS29* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)30* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT31* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY32* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF33* SUCH DAMAGE.34*/3536#include <errno.h>37#include <stddef.h>38#include <stdlib.h>3940#ifdef I_AM_HEAPSORT_B41#include "block_abi.h"42#define COMPAR(x, y) CALL_BLOCK(compar, x, y)43typedef DECLARE_BLOCK(int, heapsort_block, const void *, const void *);44#else45#define COMPAR(x, y) compar(x, y)46#endif4748/*49* Swap two areas of size number of bytes. Although qsort(3) permits random50* blocks of memory to be sorted, sorting pointers is almost certainly the51* common case (and, were it not, could easily be made so). Regardless, it52* isn't worth optimizing; the SWAP's get sped up by the cache, and pointer53* arithmetic gets lost in the time required for comparison function calls.54*/55#define SWAP(a, b, count, size, tmp) { \56count = size; \57do { \58tmp = *a; \59*a++ = *b; \60*b++ = tmp; \61} while (--count); \62}6364/* Copy one block of size size to another. */65#define COPY(a, b, count, size, tmp1, tmp2) { \66count = size; \67tmp1 = a; \68tmp2 = b; \69do { \70*tmp1++ = *tmp2++; \71} while (--count); \72}7374/*75* Build the list into a heap, where a heap is defined such that for76* the records K1 ... KN, Kj/2 >= Kj for 1 <= j/2 <= j <= N.77*78* There two cases. If j == nmemb, select largest of Ki and Kj. If79* j < nmemb, select largest of Ki, Kj and Kj+1.80*/81#define CREATE(initval, nmemb, par_i, child_i, par, child, size, count, tmp) { \82for (par_i = initval; (child_i = par_i * 2) <= nmemb; \83par_i = child_i) { \84child = base + child_i * size; \85if (child_i < nmemb && COMPAR(child, child + size) < 0) { \86child += size; \87++child_i; \88} \89par = base + par_i * size; \90if (COMPAR(child, par) <= 0) \91break; \92SWAP(par, child, count, size, tmp); \93} \94}9596/*97* Select the top of the heap and 'heapify'. Since by far the most expensive98* action is the call to the compar function, a considerable optimization99* in the average case can be achieved due to the fact that k, the displaced100* elememt, is usually quite small, so it would be preferable to first101* heapify, always maintaining the invariant that the larger child is copied102* over its parent's record.103*104* Then, starting from the *bottom* of the heap, finding k's correct place,105* again maintianing the invariant. As a result of the invariant no element106* is 'lost' when k is assigned its correct place in the heap.107*108* The time savings from this optimization are on the order of 15-20% for the109* average case. See Knuth, Vol. 3, page 158, problem 18.110*111* XXX Don't break the #define SELECT line, below. Reiser cpp gets upset.112*/113#define SELECT(par_i, child_i, nmemb, par, child, size, k, count, tmp1, tmp2) { \114for (par_i = 1; (child_i = par_i * 2) <= nmemb; par_i = child_i) { \115child = base + child_i * size; \116if (child_i < nmemb && COMPAR(child, child + size) < 0) { \117child += size; \118++child_i; \119} \120par = base + par_i * size; \121COPY(par, child, count, size, tmp1, tmp2); \122} \123for (;;) { \124child_i = par_i; \125par_i = child_i / 2; \126child = base + child_i * size; \127par = base + par_i * size; \128if (child_i == 1 || COMPAR(k, par) < 0) { \129COPY(child, k, count, size, tmp1, tmp2); \130break; \131} \132COPY(child, par, count, size, tmp1, tmp2); \133} \134}135136#ifdef I_AM_HEAPSORT_B137int heapsort_b(void *, size_t, size_t, heapsort_block);138#else139int heapsort(void *, size_t, size_t,140int (*)(const void *, const void *));141#endif142/*143* Heapsort -- Knuth, Vol. 3, page 145. Runs in O (N lg N), both average144* and worst. While heapsort is faster than the worst case of quicksort,145* the BSD quicksort does median selection so that the chance of finding146* a data set that will trigger the worst case is nonexistent. Heapsort's147* only advantage over quicksort is that it requires little additional memory.148*/149#ifdef I_AM_HEAPSORT_B150int151heapsort_b(void *vbase, size_t nmemb, size_t size, heapsort_block compar)152#else153int154heapsort(void *vbase, size_t nmemb, size_t size,155int (*compar)(const void *, const void *))156#endif157{158size_t cnt, i, j, l;159char tmp, *tmp1, *tmp2;160char *base, *k, *p, *t;161162if (nmemb <= 1)163return (0);164165if (!size) {166errno = EINVAL;167return (-1);168}169170if ((k = malloc(size)) == NULL)171return (-1);172173/*174* Items are numbered from 1 to nmemb, so offset from size bytes175* below the starting address.176*/177base = (char *)vbase - size;178179for (l = nmemb / 2 + 1; --l;)180CREATE(l, nmemb, i, j, t, p, size, cnt, tmp);181182/*183* For each element of the heap, save the largest element into its184* final slot, save the displaced element (k), then recreate the185* heap.186*/187while (nmemb > 1) {188COPY(k, base + nmemb * size, cnt, size, tmp1, tmp2);189COPY(base + nmemb * size, base + size, cnt, size, tmp1, tmp2);190--nmemb;191SELECT(i, j, nmemb, t, p, size, k, cnt, tmp1, tmp2);192}193free(k);194return (0);195}196197198