1f9f848faSopenharmony_ci/*- 2f9f848faSopenharmony_ci * SPDX-License-Identifier: BSD-3-Clause 3f9f848faSopenharmony_ci * 4f9f848faSopenharmony_ci * Copyright (c) 1992, 1993 5f9f848faSopenharmony_ci * The Regents of the University of California. All rights reserved. 6f9f848faSopenharmony_ci * 7f9f848faSopenharmony_ci * Redistribution and use in source and binary forms, with or without 8f9f848faSopenharmony_ci * modification, are permitted provided that the following conditions 9f9f848faSopenharmony_ci * are met: 10f9f848faSopenharmony_ci * 1. Redistributions of source code must retain the above copyright 11f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer. 12f9f848faSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 13f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer in the 14f9f848faSopenharmony_ci * documentation and/or other materials provided with the distribution. 15f9f848faSopenharmony_ci * 3. Neither the name of the University nor the names of its contributors 16f9f848faSopenharmony_ci * may be used to endorse or promote products derived from this software 17f9f848faSopenharmony_ci * without specific prior written permission. 18f9f848faSopenharmony_ci * 19f9f848faSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20f9f848faSopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21f9f848faSopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22f9f848faSopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23f9f848faSopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24f9f848faSopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25f9f848faSopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26f9f848faSopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27f9f848faSopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28f9f848faSopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29f9f848faSopenharmony_ci * SUCH DAMAGE. 30f9f848faSopenharmony_ci */ 31f9f848faSopenharmony_ci 32f9f848faSopenharmony_ci#if defined(LIBC_SCCS) && !defined(lint) 33f9f848faSopenharmony_cistatic char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93"; 34f9f848faSopenharmony_ci#endif /* LIBC_SCCS and not lint */ 35f9f848faSopenharmony_ci// #include <sys/cdefs.h> 36f9f848faSopenharmony_ci 37f9f848faSopenharmony_ci#if defined(__GNUC__) 38f9f848faSopenharmony_ci#define __IDSTRING(name,string) __asm__(".ident\t\"" string "\"") 39f9f848faSopenharmony_ci#else 40f9f848faSopenharmony_ci/* 41f9f848faSopenharmony_ci * The following definition might not work well if used in header files, 42f9f848faSopenharmony_ci * but it should be better than nothing. If you want a "do nothing" 43f9f848faSopenharmony_ci * version, then it should generate some harmless declaration, such as: 44f9f848faSopenharmony_ci * #define __IDSTRING(name,string) struct __hack 45f9f848faSopenharmony_ci */ 46f9f848faSopenharmony_ci#define __IDSTRING(name,string) static const char name[] __unused = string 47f9f848faSopenharmony_ci#endif 48f9f848faSopenharmony_ci 49f9f848faSopenharmony_ci/* 50f9f848faSopenharmony_ci * Embed the rcs id of a source file in the resulting library. Note that in 51f9f848faSopenharmony_ci * more recent ELF binutils, we use .ident allowing the ID to be stripped. 52f9f848faSopenharmony_ci * Usage: 53f9f848faSopenharmony_ci * __FBSDID("$FreeBSD$"); 54f9f848faSopenharmony_ci */ 55f9f848faSopenharmony_ci#ifndef __FBSDID 56f9f848faSopenharmony_ci#if !defined(STRIP_FBSDID) 57f9f848faSopenharmony_ci#define __FBSDID(s) __IDSTRING(__CONCAT(__rcsid_,__LINE__),s) 58f9f848faSopenharmony_ci#else 59f9f848faSopenharmony_ci#define __FBSDID(s) struct __hack 60f9f848faSopenharmony_ci#endif 61f9f848faSopenharmony_ci#endif 62f9f848faSopenharmony_ci 63f9f848faSopenharmony_ci#if defined(__GNUC__) 64f9f848faSopenharmony_ci#define __GNUC_PREREQ__(ma, mi) \ 65f9f848faSopenharmony_ci (__GNUC__ > (ma) || __GNUC__ == (ma) && __GNUC_MINOR__ >= (mi)) 66f9f848faSopenharmony_ci#else 67f9f848faSopenharmony_ci#define __GNUC_PREREQ__(ma, mi) 0 68f9f848faSopenharmony_ci#endif 69f9f848faSopenharmony_ci 70f9f848faSopenharmony_ci#if !__GNUC_PREREQ__(2, 5) 71f9f848faSopenharmony_ci#define __unused 72f9f848faSopenharmony_ci#endif 73f9f848faSopenharmony_ci#if __GNUC__ == 2 && __GNUC_MINOR__ >= 5 && __GNUC_MINOR__ < 7 74f9f848faSopenharmony_ci#define __unused 75f9f848faSopenharmony_ci/* XXX Find out what to do for __packed, __aligned and __section */ 76f9f848faSopenharmony_ci#endif 77f9f848faSopenharmony_ci#if __GNUC_PREREQ__(2, 7) 78f9f848faSopenharmony_ci#define __unused __attribute__((__unused__)) 79f9f848faSopenharmony_ci#endif 80f9f848faSopenharmony_ci 81f9f848faSopenharmony_ci#if __GNUC_PREREQ__(2, 96) 82f9f848faSopenharmony_ci#define __predict_false(exp) __builtin_expect((exp), 0) 83f9f848faSopenharmony_ci#else 84f9f848faSopenharmony_ci#define __predict_false(exp) (exp) 85f9f848faSopenharmony_ci#endif 86f9f848faSopenharmony_ci 87f9f848faSopenharmony_ci__FBSDID("$FreeBSD$"); 88f9f848faSopenharmony_ci 89f9f848faSopenharmony_ci#include <errno.h> 90f9f848faSopenharmony_ci#include <stdint.h> 91f9f848faSopenharmony_ci#include <stdlib.h> 92f9f848faSopenharmony_ci#include <string.h> 93f9f848faSopenharmony_ci// #include "libc_private.h" 94f9f848faSopenharmony_ci 95f9f848faSopenharmony_ci#if defined(I_AM_QSORT_R) 96f9f848faSopenharmony_citypedef int cmp_t(void *, const void *, const void *); 97f9f848faSopenharmony_ci#elif defined(I_AM_QSORT_S) 98f9f848faSopenharmony_citypedef int cmp_t(const void *, const void *, void *); 99f9f848faSopenharmony_ci#else 100f9f848faSopenharmony_citypedef int cmp_t(const void *, const void *); 101f9f848faSopenharmony_ci#endif 102f9f848faSopenharmony_cistatic inline char *med3(char *, char *, char *, cmp_t *, void *); 103f9f848faSopenharmony_ci 104f9f848faSopenharmony_ci#define MIN(a, b) ((a) < (b) ? a : b) 105f9f848faSopenharmony_ci 106f9f848faSopenharmony_ci/* 107f9f848faSopenharmony_ci * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". 108f9f848faSopenharmony_ci */ 109f9f848faSopenharmony_ci 110f9f848faSopenharmony_cistatic inline void 111f9f848faSopenharmony_ciswapfunc(char *a, char *b, size_t es) 112f9f848faSopenharmony_ci{ 113f9f848faSopenharmony_ci char t; 114f9f848faSopenharmony_ci 115f9f848faSopenharmony_ci do { 116f9f848faSopenharmony_ci t = *a; 117f9f848faSopenharmony_ci *a++ = *b; 118f9f848faSopenharmony_ci *b++ = t; 119f9f848faSopenharmony_ci } while (--es > 0); 120f9f848faSopenharmony_ci} 121f9f848faSopenharmony_ci 122f9f848faSopenharmony_ci#define vecswap(a, b, n) \ 123f9f848faSopenharmony_ci if ((n) > 0) swapfunc(a, b, n) 124f9f848faSopenharmony_ci 125f9f848faSopenharmony_ci#if defined(I_AM_QSORT_R) 126f9f848faSopenharmony_ci#define CMP(t, x, y) (cmp((t), (x), (y))) 127f9f848faSopenharmony_ci#elif defined(I_AM_QSORT_S) 128f9f848faSopenharmony_ci#define CMP(t, x, y) (cmp((x), (y), (t))) 129f9f848faSopenharmony_ci#else 130f9f848faSopenharmony_ci#define CMP(t, x, y) (cmp((x), (y))) 131f9f848faSopenharmony_ci#endif 132f9f848faSopenharmony_ci 133f9f848faSopenharmony_cistatic inline char * 134f9f848faSopenharmony_cimed3(char *a, char *b, char *c, cmp_t *cmp, void *thunk 135f9f848faSopenharmony_ci#if !defined(I_AM_QSORT_R) && !defined(I_AM_QSORT_S) 136f9f848faSopenharmony_ci__unused 137f9f848faSopenharmony_ci#endif 138f9f848faSopenharmony_ci) 139f9f848faSopenharmony_ci{ 140f9f848faSopenharmony_ci return CMP(thunk, a, b) < 0 ? 141f9f848faSopenharmony_ci (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a )) 142f9f848faSopenharmony_ci :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c )); 143f9f848faSopenharmony_ci} 144f9f848faSopenharmony_ci 145f9f848faSopenharmony_ci/* 146f9f848faSopenharmony_ci * The actual qsort() implementation is static to avoid preemptible calls when 147f9f848faSopenharmony_ci * recursing. Also give them different names for improved debugging. 148f9f848faSopenharmony_ci */ 149f9f848faSopenharmony_ci#if defined(I_AM_QSORT_R) 150f9f848faSopenharmony_ci#define local_qsort local_qsort_r 151f9f848faSopenharmony_ci#elif defined(I_AM_QSORT_S) 152f9f848faSopenharmony_ci#define local_qsort local_qsort_s 153f9f848faSopenharmony_ci#endif 154f9f848faSopenharmony_cistatic void 155f9f848faSopenharmony_cilocal_qsort(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk) 156f9f848faSopenharmony_ci{ 157f9f848faSopenharmony_ci char *pa, *pb, *pc, *pd, *pl, *pm, *pn; 158f9f848faSopenharmony_ci size_t d1, d2; 159f9f848faSopenharmony_ci int cmp_result; 160f9f848faSopenharmony_ci int swap_cnt; 161f9f848faSopenharmony_ci 162f9f848faSopenharmony_ci if (__predict_false(n == 0)) 163f9f848faSopenharmony_ci return; 164f9f848faSopenharmony_ciloop: 165f9f848faSopenharmony_ci swap_cnt = 0; 166f9f848faSopenharmony_ci if (n < 7) { 167f9f848faSopenharmony_ci for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) 168f9f848faSopenharmony_ci for (pl = pm; 169f9f848faSopenharmony_ci pl > (char *)a && CMP(thunk, pl - es, pl) > 0; 170f9f848faSopenharmony_ci pl -= es) 171f9f848faSopenharmony_ci swapfunc(pl, pl - es, es); 172f9f848faSopenharmony_ci return; 173f9f848faSopenharmony_ci } 174f9f848faSopenharmony_ci pm = (char *)a + (n / 2) * es; 175f9f848faSopenharmony_ci if (n > 7) { 176f9f848faSopenharmony_ci pl = a; 177f9f848faSopenharmony_ci pn = (char *)a + (n - 1) * es; 178f9f848faSopenharmony_ci if (n > 40) { 179f9f848faSopenharmony_ci size_t d = (n / 8) * es; 180f9f848faSopenharmony_ci 181f9f848faSopenharmony_ci pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk); 182f9f848faSopenharmony_ci pm = med3(pm - d, pm, pm + d, cmp, thunk); 183f9f848faSopenharmony_ci pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk); 184f9f848faSopenharmony_ci } 185f9f848faSopenharmony_ci pm = med3(pl, pm, pn, cmp, thunk); 186f9f848faSopenharmony_ci } 187f9f848faSopenharmony_ci swapfunc(a, pm, es); 188f9f848faSopenharmony_ci pa = pb = (char *)a + es; 189f9f848faSopenharmony_ci 190f9f848faSopenharmony_ci pc = pd = (char *)a + (n - 1) * es; 191f9f848faSopenharmony_ci for (;;) { 192f9f848faSopenharmony_ci while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) { 193f9f848faSopenharmony_ci if (cmp_result == 0) { 194f9f848faSopenharmony_ci swap_cnt = 1; 195f9f848faSopenharmony_ci swapfunc(pa, pb, es); 196f9f848faSopenharmony_ci pa += es; 197f9f848faSopenharmony_ci } 198f9f848faSopenharmony_ci pb += es; 199f9f848faSopenharmony_ci } 200f9f848faSopenharmony_ci while (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) { 201f9f848faSopenharmony_ci if (cmp_result == 0) { 202f9f848faSopenharmony_ci swap_cnt = 1; 203f9f848faSopenharmony_ci swapfunc(pc, pd, es); 204f9f848faSopenharmony_ci pd -= es; 205f9f848faSopenharmony_ci } 206f9f848faSopenharmony_ci pc -= es; 207f9f848faSopenharmony_ci } 208f9f848faSopenharmony_ci if (pb > pc) 209f9f848faSopenharmony_ci break; 210f9f848faSopenharmony_ci swapfunc(pb, pc, es); 211f9f848faSopenharmony_ci swap_cnt = 1; 212f9f848faSopenharmony_ci pb += es; 213f9f848faSopenharmony_ci pc -= es; 214f9f848faSopenharmony_ci } 215f9f848faSopenharmony_ci if (swap_cnt == 0) { /* Switch to insertion sort */ 216f9f848faSopenharmony_ci for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) 217f9f848faSopenharmony_ci for (pl = pm; 218f9f848faSopenharmony_ci pl > (char *)a && CMP(thunk, pl - es, pl) > 0; 219f9f848faSopenharmony_ci pl -= es) 220f9f848faSopenharmony_ci swapfunc(pl, pl - es, es); 221f9f848faSopenharmony_ci return; 222f9f848faSopenharmony_ci } 223f9f848faSopenharmony_ci 224f9f848faSopenharmony_ci pn = (char *)a + n * es; 225f9f848faSopenharmony_ci d1 = MIN(pa - (char *)a, pb - pa); 226f9f848faSopenharmony_ci vecswap(a, pb - d1, d1); 227f9f848faSopenharmony_ci d1 = MIN(pd - pc, pn - pd - es); 228f9f848faSopenharmony_ci vecswap(pb, pn - d1, d1); 229f9f848faSopenharmony_ci 230f9f848faSopenharmony_ci d1 = pb - pa; 231f9f848faSopenharmony_ci d2 = pd - pc; 232f9f848faSopenharmony_ci if (d1 <= d2) { 233f9f848faSopenharmony_ci /* Recurse on left partition, then iterate on right partition */ 234f9f848faSopenharmony_ci if (d1 > es) { 235f9f848faSopenharmony_ci local_qsort(a, d1 / es, es, cmp, thunk); 236f9f848faSopenharmony_ci } 237f9f848faSopenharmony_ci if (d2 > es) { 238f9f848faSopenharmony_ci /* Iterate rather than recurse to save stack space */ 239f9f848faSopenharmony_ci /* qsort(pn - d2, d2 / es, es, cmp); */ 240f9f848faSopenharmony_ci a = pn - d2; 241f9f848faSopenharmony_ci n = d2 / es; 242f9f848faSopenharmony_ci goto loop; 243f9f848faSopenharmony_ci } 244f9f848faSopenharmony_ci } else { 245f9f848faSopenharmony_ci /* Recurse on right partition, then iterate on left partition */ 246f9f848faSopenharmony_ci if (d2 > es) { 247f9f848faSopenharmony_ci local_qsort(pn - d2, d2 / es, es, cmp, thunk); 248f9f848faSopenharmony_ci } 249f9f848faSopenharmony_ci if (d1 > es) { 250f9f848faSopenharmony_ci /* Iterate rather than recurse to save stack space */ 251f9f848faSopenharmony_ci /* qsort(a, d1 / es, es, cmp); */ 252f9f848faSopenharmony_ci n = d1 / es; 253f9f848faSopenharmony_ci goto loop; 254f9f848faSopenharmony_ci } 255f9f848faSopenharmony_ci } 256f9f848faSopenharmony_ci} 257f9f848faSopenharmony_ci 258f9f848faSopenharmony_ci#if defined(I_AM_QSORT_R) 259f9f848faSopenharmony_civoid 260f9f848faSopenharmony_ciqsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp) 261f9f848faSopenharmony_ci{ 262f9f848faSopenharmony_ci local_qsort_r(a, n, es, cmp, thunk); 263f9f848faSopenharmony_ci} 264f9f848faSopenharmony_ci#elif defined(I_AM_QSORT_S) 265f9f848faSopenharmony_cierrno_t 266f9f848faSopenharmony_ciqsort_s(void *a, rsize_t n, rsize_t es, cmp_t *cmp, void *thunk) 267f9f848faSopenharmony_ci{ 268f9f848faSopenharmony_ci if (n > RSIZE_MAX) { 269f9f848faSopenharmony_ci __throw_constraint_handler_s("qsort_s : n > RSIZE_MAX", EINVAL); 270f9f848faSopenharmony_ci return (EINVAL); 271f9f848faSopenharmony_ci } else if (es > RSIZE_MAX) { 272f9f848faSopenharmony_ci __throw_constraint_handler_s("qsort_s : es > RSIZE_MAX", 273f9f848faSopenharmony_ci EINVAL); 274f9f848faSopenharmony_ci return (EINVAL); 275f9f848faSopenharmony_ci } else if (n != 0) { 276f9f848faSopenharmony_ci if (a == NULL) { 277f9f848faSopenharmony_ci __throw_constraint_handler_s("qsort_s : a == NULL", 278f9f848faSopenharmony_ci EINVAL); 279f9f848faSopenharmony_ci return (EINVAL); 280f9f848faSopenharmony_ci } else if (cmp == NULL) { 281f9f848faSopenharmony_ci __throw_constraint_handler_s("qsort_s : cmp == NULL", 282f9f848faSopenharmony_ci EINVAL); 283f9f848faSopenharmony_ci return (EINVAL); 284f9f848faSopenharmony_ci } 285f9f848faSopenharmony_ci } 286f9f848faSopenharmony_ci 287f9f848faSopenharmony_ci local_qsort_s(a, n, es, cmp, thunk); 288f9f848faSopenharmony_ci return (0); 289f9f848faSopenharmony_ci} 290f9f848faSopenharmony_ci#else 291f9f848faSopenharmony_civoid 292f9f848faSopenharmony_ciqsort(void *a, size_t n, size_t es, cmp_t *cmp) 293f9f848faSopenharmony_ci{ 294f9f848faSopenharmony_ci local_qsort(a, n, es, cmp, NULL); 295f9f848faSopenharmony_ci} 296f9f848faSopenharmony_ci#endif