/** * Copyright (C) Mellanox Technologies Ltd. 2001-2016. ALL RIGHTS RESERVED. * * See file LICENSE for terms. */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "qsort_r.h" #include #include #include /* * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". */ #define ucs_qsort_swapcode(TYPE, parmi, parmj, n) \ { \ long i = (n) / sizeof (TYPE); \ register TYPE *pi = (TYPE *) (parmi); \ register TYPE *pj = (TYPE *) (parmj); \ do { \ register TYPE t = *pi; \ *pi++ = *pj; \ *pj++ = t; \ } while (--i > 0); \ } #define ucs_qsort_swaptype(a, size) \ ({ \ (((char *)a - (char *)0) % sizeof(long)) || \ (size % sizeof(long)) ? 2 : (size == sizeof(long)) ? 0 : 1; \ }) #define ucs_qsort_swap(a, b) \ if (swaptype == 0) { \ long t = *(long *)(a); \ *(long *)(a) = *(long *)(b); \ *(long *)(b) = t; \ } else { \ ucs_qsort_swapfunc(a, b, size, swaptype); \ } #define ucs_qsort_vecswap(a, b, n) \ if ((n) > 0) { \ ucs_qsort_swapfunc(a, b, n, swaptype); \ } static UCS_F_ALWAYS_INLINE void ucs_qsort_swapfunc(char *a, char *b, int n, int swaptype) { if (swaptype <= 1) { ucs_qsort_swapcode(long, a, b, n) } else { ucs_qsort_swapcode(char, a, b, n) } } static UCS_F_ALWAYS_INLINE char * ucs_qsort_med3(char *a, char *b, char *c, ucs_qsort_r_compare_cb_t *compare, void *arg) { return (compare(a, b, arg) < 0) ? ((compare(b, c, arg) < 0) ? b : ((compare(a, c, arg)) < 0 ? c : a)) : ((compare(b, c, arg) > 0) ? b : ((compare(a, c, arg)) < 0 ? a : c)); } void ucs_qsort_r(void *base, size_t nmemb, size_t size, ucs_qsort_r_compare_cb_t *compare, void *arg) { char *pa, *pb, *pc, *md, *pl, *pm, *pn; int d, r, swaptype, swap_cnt; loop: swaptype = ucs_qsort_swaptype(base, size); swap_cnt = 0; if (nmemb < 7) { /* Switch to insertion sort */ for (pm = (char*)base + size; pm < (char*)base + nmemb * size; pm += size) { for (pl = pm; pl > (char*)base && compare(pl - size, pl, arg) > 0; pl -= size) { ucs_qsort_swap(pl, pl - size); } } return; } pm = (char*)base + (nmemb / 2) * size; if (nmemb > 7) { pl = base; pn = (char*)base + (nmemb - 1) * size; if (nmemb > 40) { d = (nmemb / 8) * size; pl = ucs_qsort_med3(pl, pl + d, pl + 2 * d, compare, arg); pm = ucs_qsort_med3(pm - d, pm, pm + d, compare, arg); pn = ucs_qsort_med3(pn - 2 * d, pn - d, pn, compare, arg); } pm = ucs_qsort_med3(pl, pm, pn, compare, arg); } ucs_qsort_swap(base, pm); pa = pb = (char*)base + size; pc = md = (char*)base + (nmemb - 1) * size; for (;;) { while ((pb <= pc) && (r = compare(pb, base, arg)) <= 0) { if (r == 0) { swap_cnt = 1; ucs_qsort_swap(pa, pb); pa += size; } pb += size; } while ((pb <= pc) && (r = compare(pc, base, arg)) >= 0) { if (r == 0) { swap_cnt = 1; ucs_qsort_swap(pc, md); md -= size; } pc -= size; } if (pb > pc) { break; } ucs_qsort_swap(pb, pc); swap_cnt = 1; pb += size; pc -= size; } if (swap_cnt == 0) { /* Switch to insertion sort */ for (pm = (char*)base + size; pm < (char*)base + nmemb * size; pm += size) { for (pl = pm; pl > (char *)base && compare(pl - size, pl, arg) > 0; pl -= size) { ucs_qsort_swap(pl, pl - size); } } return; } pn = (char*)base + nmemb * size; r = ucs_min(pa - (char*)base, pb - pa); ucs_qsort_vecswap(base, pb - r, r); r = ucs_min(md - pc, pn - md - size); ucs_qsort_vecswap(pb, pn - r, r); if ((r = pb - pa) > size) { ucs_qsort_r(base, r / size, size, compare, arg); } if ((r = md - pc) > size) { /* Iterate rather than recurse to save stack space */ base = pn - r; nmemb = r / size; goto loop; } }