xref: /netbsd-src/external/gpl3/gdb/dist/libiberty/sort.c (revision 5173eb0a33e5d83890ba976253e703be4c92557c)
198b9484cSchristos /* Sorting algorithms.
2*5173eb0aSchristos    Copyright (C) 2000-2024 Free Software Foundation, Inc.
398b9484cSchristos    Contributed by Mark Mitchell <mark@codesourcery.com>.
498b9484cSchristos 
598b9484cSchristos This file is part of GNU CC.
698b9484cSchristos 
798b9484cSchristos GNU CC is free software; you can redistribute it and/or modify it
898b9484cSchristos under the terms of the GNU General Public License as published by
998b9484cSchristos the Free Software Foundation; either version 2, or (at your option)
1098b9484cSchristos any later version.
1198b9484cSchristos 
1298b9484cSchristos GNU CC is distributed in the hope that it will be useful, but
1398b9484cSchristos WITHOUT ANY WARRANTY; without even the implied warranty of
1498b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1598b9484cSchristos General Public License for more details.
1698b9484cSchristos 
1798b9484cSchristos You should have received a copy of the GNU General Public License
1898b9484cSchristos along with GNU CC; see the file COPYING.  If not, write to
1998b9484cSchristos the Free Software Foundation, 51 Franklin Street - Fifth Floor,
2098b9484cSchristos Boston, MA 02110-1301, USA.  */
2198b9484cSchristos 
2298b9484cSchristos #ifdef HAVE_CONFIG_H
2398b9484cSchristos #include "config.h"
2498b9484cSchristos #endif
2598b9484cSchristos #include "libiberty.h"
2698b9484cSchristos #include "sort.h"
2798b9484cSchristos #ifdef HAVE_LIMITS_H
2898b9484cSchristos #include <limits.h>
2998b9484cSchristos #endif
3098b9484cSchristos #ifdef HAVE_SYS_PARAM_H
3198b9484cSchristos #include <sys/param.h>
3298b9484cSchristos #endif
3398b9484cSchristos #ifdef HAVE_STDLIB_H
3498b9484cSchristos #include <stdlib.h>
3598b9484cSchristos #endif
3698b9484cSchristos #ifdef HAVE_STRING_H
3798b9484cSchristos #include <string.h>
3898b9484cSchristos #endif
3998b9484cSchristos 
4098b9484cSchristos #ifndef UCHAR_MAX
4198b9484cSchristos #define UCHAR_MAX ((unsigned char)(-1))
4298b9484cSchristos #endif
4398b9484cSchristos 
4498b9484cSchristos /* POINTERS and WORK are both arrays of N pointers.  When this
4598b9484cSchristos    function returns POINTERS will be sorted in ascending order.  */
4698b9484cSchristos 
4798b9484cSchristos void sort_pointers (size_t n, void **pointers, void **work)
4898b9484cSchristos {
4998b9484cSchristos   /* The type of a single digit.  This can be any unsigned integral
5098b9484cSchristos      type.  When changing this, DIGIT_MAX should be changed as
5198b9484cSchristos      well.  */
5298b9484cSchristos   typedef unsigned char digit_t;
5398b9484cSchristos 
5498b9484cSchristos   /* The maximum value a single digit can have.  */
5598b9484cSchristos #define DIGIT_MAX (UCHAR_MAX + 1)
5698b9484cSchristos 
5798b9484cSchristos   /* The Ith entry is the number of elements in *POINTERSP that have I
5898b9484cSchristos      in the digit on which we are currently sorting.  */
5998b9484cSchristos   unsigned int count[DIGIT_MAX];
6098b9484cSchristos   /* Nonzero if we are running on a big-endian machine.  */
6198b9484cSchristos   int big_endian_p;
6298b9484cSchristos   size_t i;
6398b9484cSchristos   size_t j;
6498b9484cSchristos 
6598b9484cSchristos   /* The algorithm used here is radix sort which takes time linear in
6698b9484cSchristos      the number of elements in the array.  */
6798b9484cSchristos 
6898b9484cSchristos   /* The algorithm here depends on being able to swap the two arrays
6998b9484cSchristos      an even number of times.  */
7098b9484cSchristos   if ((sizeof (void *) / sizeof (digit_t)) % 2 != 0)
7198b9484cSchristos     abort ();
7298b9484cSchristos 
7398b9484cSchristos   /* Figure out the endianness of the machine.  */
7498b9484cSchristos   for (i = 0, j = 0; i < sizeof (size_t); ++i)
7598b9484cSchristos     {
7698b9484cSchristos       j *= (UCHAR_MAX + 1);
7798b9484cSchristos       j += i;
7898b9484cSchristos     }
7998b9484cSchristos   big_endian_p = (((char *)&j)[0] == 0);
8098b9484cSchristos 
8198b9484cSchristos   /* Move through the pointer values from least significant to most
8298b9484cSchristos      significant digits.  */
8398b9484cSchristos   for (i = 0; i < sizeof (void *) / sizeof (digit_t); ++i)
8498b9484cSchristos     {
8598b9484cSchristos       digit_t *digit;
8698b9484cSchristos       digit_t *bias;
8798b9484cSchristos       digit_t *top;
8898b9484cSchristos       unsigned int *countp;
8998b9484cSchristos       void **pointerp;
9098b9484cSchristos 
9198b9484cSchristos       /* The offset from the start of the pointer will depend on the
9298b9484cSchristos 	 endianness of the machine.  */
9398b9484cSchristos       if (big_endian_p)
9498b9484cSchristos 	j = sizeof (void *) / sizeof (digit_t) - i;
9598b9484cSchristos       else
9698b9484cSchristos 	j = i;
9798b9484cSchristos 
9898b9484cSchristos       /* Now, perform a stable sort on this digit.  We use counting
9998b9484cSchristos 	 sort.  */
10098b9484cSchristos       memset (count, 0, DIGIT_MAX * sizeof (unsigned int));
10198b9484cSchristos 
10298b9484cSchristos       /* Compute the address of the appropriate digit in the first and
10398b9484cSchristos 	 one-past-the-end elements of the array.  On a little-endian
10498b9484cSchristos 	 machine, the least-significant digit is closest to the front.  */
10598b9484cSchristos       bias = ((digit_t *) pointers) + j;
10698b9484cSchristos       top = ((digit_t *) (pointers + n)) + j;
10798b9484cSchristos 
10898b9484cSchristos       /* Count how many there are of each value.  At the end of this
10998b9484cSchristos 	 loop, COUNT[K] will contain the number of pointers whose Ith
11098b9484cSchristos 	 digit is K.  */
11198b9484cSchristos       for (digit = bias;
11298b9484cSchristos 	   digit < top;
11398b9484cSchristos 	   digit += sizeof (void *) / sizeof (digit_t))
11498b9484cSchristos 	++count[*digit];
11598b9484cSchristos 
11698b9484cSchristos       /* Now, make COUNT[K] contain the number of pointers whose Ith
11798b9484cSchristos 	 digit is less than or equal to K.  */
11898b9484cSchristos       for (countp = count + 1; countp < count + DIGIT_MAX; ++countp)
11998b9484cSchristos 	*countp += countp[-1];
12098b9484cSchristos 
12198b9484cSchristos       /* Now, drop the pointers into their correct locations.  */
12298b9484cSchristos       for (pointerp = pointers + n - 1; pointerp >= pointers; --pointerp)
12398b9484cSchristos 	work[--count[((digit_t *) pointerp)[j]]] = *pointerp;
12498b9484cSchristos 
12598b9484cSchristos       /* Swap WORK and POINTERS so that POINTERS contains the sorted
12698b9484cSchristos 	 array.  */
12798b9484cSchristos       pointerp = pointers;
12898b9484cSchristos       pointers = work;
12998b9484cSchristos       work = pointerp;
13098b9484cSchristos     }
13198b9484cSchristos }
13298b9484cSchristos 
13398b9484cSchristos /* Everything below here is a unit test for the routines in this
13498b9484cSchristos    file.  */
13598b9484cSchristos 
13698b9484cSchristos #ifdef UNIT_TEST
13798b9484cSchristos 
13898b9484cSchristos #include <stdio.h>
13998b9484cSchristos 
14098b9484cSchristos void *xmalloc (size_t n)
14198b9484cSchristos {
14298b9484cSchristos   return malloc (n);
14398b9484cSchristos }
14498b9484cSchristos 
14598b9484cSchristos int main (int argc, char **argv)
14698b9484cSchristos {
14798b9484cSchristos   int k;
14898b9484cSchristos   int result;
14998b9484cSchristos   size_t i;
15098b9484cSchristos   void **pointers;
15198b9484cSchristos   void **work;
15298b9484cSchristos 
15398b9484cSchristos   if (argc > 1)
15498b9484cSchristos     k = atoi (argv[1]);
15598b9484cSchristos   else
15698b9484cSchristos     k = 10;
15798b9484cSchristos 
15898b9484cSchristos   pointers = XNEWVEC (void*, k);
15998b9484cSchristos   work = XNEWVEC (void*, k);
16098b9484cSchristos 
16198b9484cSchristos   for (i = 0; i < k; ++i)
16298b9484cSchristos     {
16398b9484cSchristos       pointers[i] = (void *) random ();
16498b9484cSchristos       printf ("%x\n", pointers[i]);
16598b9484cSchristos     }
16698b9484cSchristos 
16798b9484cSchristos   sort_pointers (k, pointers, work);
16898b9484cSchristos 
16998b9484cSchristos   printf ("\nSorted\n\n");
17098b9484cSchristos 
17198b9484cSchristos   result = 0;
17298b9484cSchristos 
17398b9484cSchristos   for (i = 0; i < k; ++i)
17498b9484cSchristos     {
17598b9484cSchristos       printf ("%x\n", pointers[i]);
17698b9484cSchristos       if (i > 0 && (char*) pointers[i] < (char*) pointers[i - 1])
17798b9484cSchristos 	result = 1;
17898b9484cSchristos     }
17998b9484cSchristos 
18098b9484cSchristos   free (pointers);
18198b9484cSchristos   free (work);
18298b9484cSchristos 
18398b9484cSchristos   return result;
18498b9484cSchristos }
18598b9484cSchristos 
18698b9484cSchristos #endif
187