LCOV - code coverage report
Current view: top level - gdk - gdk_rsort.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 78 86 90.7 %
Date: 2024-11-15 19:37:45 Functions: 1 1 100.0 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : #include "gdk.h"
      15             : #include "gdk_private.h"
      16             : 
      17             : #define RADIX 8                 /* one char at a time */
      18             : #define NBUCKETS (1 << RADIX)
      19             : 
      20             : gdk_return
      21       20145 : GDKrsort(void *restrict h, void *restrict t, size_t n, size_t hs, size_t ts, bool reverse, bool isuuid)
      22             : {
      23       20145 :         size_t (*counts)[NBUCKETS] = GDKmalloc(hs * sizeof(counts[0]));
      24       20145 :         size_t pos[NBUCKETS];
      25       20145 :         uint8_t *h1 = h;
      26       20145 :         uint8_t *h2;
      27       20145 :         uint8_t *t1 = NULL;
      28       20145 :         uint8_t *t2 = NULL;
      29       20145 :         Heap tmph, tmpt;
      30             : 
      31       20145 :         if (counts == NULL)
      32             :                 return GDK_FAIL;
      33             : 
      34       20145 :         tmph = tmpt = (Heap) {
      35             :                 .farmid = 1,
      36             :         };
      37             : 
      38       40290 :         snprintf(tmph.filename, sizeof(tmph.filename), "%s%crsort%zuh",
      39       20145 :                  TEMPDIR_NAME, DIR_SEP, (size_t) MT_getpid());
      40       20145 :         if (HEAPalloc(&tmph, n, hs) != GDK_SUCCEED) {
      41           0 :                 GDKfree(counts);
      42           0 :                 return GDK_FAIL;
      43             :         }
      44       20145 :         h2 = (uint8_t *) tmph.base;
      45             : 
      46       20145 :         if (t) {
      47       39920 :                 snprintf(tmpt.filename, sizeof(tmpt.filename), "%s%crsort%zut",
      48       19960 :                          TEMPDIR_NAME, DIR_SEP, (size_t) MT_getpid());
      49       19960 :                 if (HEAPalloc(&tmpt, n, ts) != GDK_SUCCEED) {
      50           0 :                         GDKfree(counts);
      51           0 :                         HEAPfree(&tmph, true);
      52           0 :                         return GDK_FAIL;
      53             :                 }
      54       19960 :                 t1 = t;
      55       19960 :                 t2 = (uint8_t *) tmpt.base;
      56             :         } else {
      57             :                 ts = 0;
      58             :         }
      59             : 
      60       20145 :         memset(counts, 0, hs * sizeof(counts[0]));
      61             : #ifndef WORDS_BIGENDIAN
      62       20145 :         if (isuuid /* UUID, treat like big-endian */) {
      63             : #endif
      64           5 :                 for (size_t i = 0, o = 0; i < n; i++, o += hs) {
      65          68 :                         for (size_t j = 0, k = hs - 1; j < hs; j++, k--) {
      66          64 :                                 uint8_t v = h1[o + k];
      67          64 :                                 counts[j][v]++;
      68             :                         }
      69             :                 }
      70             : #ifndef WORDS_BIGENDIAN
      71             :         } else {
      72    45350813 :                 for (size_t i = 0, o = 0; i < n; i++, o += hs) {
      73   242614770 :                         for (size_t j = 0; j < hs; j++) {
      74   197284101 :                                 uint8_t v = h1[o + j];
      75   197284101 :                                 counts[j][v]++;
      76             :                         }
      77             :                 }
      78             :         }
      79             : #endif
      80             :         /* When sorting in ascending order, the negative numbers occupy
      81             :          * the second half of the buckets in the last iteration; when
      82             :          * sorting in descending order, the negative numbers occupy the
      83             :          * first half.  In either case, at the end we need to put the
      84             :          * second half first and the first half after. */
      85       20145 :         size_t negpos = 0;
      86      101445 :         for (size_t j = 0, k = hs - 1; j < hs; j++, k--) {
      87       81300 :                 size_t nb = counts[j][0] > 0;
      88       81300 :                 if (reverse) {
      89         430 :                         pos[NBUCKETS - 1] = 0;
      90      110080 :                         for (size_t i = NBUCKETS - 1; i > 0; i--) {
      91      109650 :                                 pos[i - 1] = pos[i] + counts[j][i];
      92      109650 :                                 nb += counts[j][i] > 0;
      93             :                         }
      94             :                 } else {
      95       80870 :                         pos[0] = 0;
      96    20701190 :                         for (size_t i = 1; i < NBUCKETS; i++) {
      97    20620320 :                                 pos[i] = pos[i - 1] + counts[j][i - 1];
      98    20620320 :                                 nb += counts[j][i] > 0;
      99             :                         }
     100             :                 }
     101             :                 /* we're only interested in the position in the last
     102             :                  * iteration */
     103       81300 :                 negpos = pos[NBUCKETS / 2 - reverse];
     104       81300 :                 if (nb == 1) {
     105             :                         /* no need to reshuffle data for this iteration:
     106             :                          * everything is in the same bucket */
     107       21917 :                         continue;
     108             :                 }
     109             :                 /* note, this loop changes the pos array */
     110             : #ifndef WORDS_BIGENDIAN
     111       59383 :                 if (isuuid /* UUID, treat like big-endian */)
     112             : #endif
     113          80 :                         for (size_t i = 0, ho = 0, to = 0; i < n; i++, ho += hs, to += ts) {
     114          64 :                                 uint8_t v = h1[ho + k];
     115          64 :                                 if (t)
     116          64 :                                         memcpy(t2 + ts * pos[v], t1 + to, ts);
     117          64 :                                 memcpy(h2 + hs * pos[v]++, h1 + ho, hs);
     118             :                         }
     119             : #ifndef WORDS_BIGENDIAN
     120             :                 else
     121    86693220 :                         for (size_t i = 0, ho = 0, to = 0; i < n; i++, ho += hs, to += ts) {
     122    86633853 :                                 uint8_t v = h1[ho + j];
     123    86633853 :                                 if (t)
     124    83243939 :                                         memcpy(t2 + ts * pos[v], t1 + to, ts);
     125    86633853 :                                 memcpy(h2 + hs * pos[v]++, h1 + ho, hs);
     126             :                         }
     127             : #endif
     128             :                 uint8_t *t = h1;
     129             :                 h1 = h2;
     130             :                 h2 = t;
     131             :                 t = t1;
     132             :                 t1 = t2;
     133             :                 t2 = t;
     134             :         }
     135       20145 :         GDKfree(counts);
     136             : 
     137       20145 :         if (h1 != (uint8_t *) h) {
     138             :                 /* we need to copy the data back to the correct heap */
     139       19141 :                 if (isuuid) {
     140             :                         /* no negative values in uuid, so no shuffling */
     141           0 :                         memcpy(h2, h1, n * hs);
     142           0 :                         if (t)
     143           0 :                                 memcpy(t2, t1, n * ts);
     144             :                 } else {
     145             :                         /* copy the negative integers to the start, copy positive after */
     146       19141 :                         if (negpos < n) {
     147          47 :                                 memcpy(h2, h1 + hs * negpos, (n - negpos) * hs);
     148          47 :                                 if (t)
     149          44 :                                         memcpy(t2, t1 + ts * negpos, (n - negpos) * ts);
     150             :                         }
     151       19141 :                         if (negpos > 0) {
     152       19108 :                                 memcpy(h2 + hs * (n - negpos), h1, negpos * hs);
     153       19108 :                                 if (t)
     154       18960 :                                         memcpy(t2 + ts * (n - negpos), t1, negpos * ts);
     155             :                         }
     156             :                 }
     157        1004 :         } else if (negpos > 0 && negpos < n && !isuuid) {
     158             :                 /* copy the negative integers to the start, copy positive after */
     159          28 :                 memcpy(h2, h1 + hs * negpos, (n - negpos) * hs);
     160          28 :                 memcpy(h2 + hs * (n - negpos), h1, negpos * hs);
     161          28 :                 memcpy(h, h2, n * hs);
     162          28 :                 if (t) {
     163          26 :                         memcpy(t2, t1 + ts * negpos, (n - negpos) * ts);
     164          26 :                         memcpy(t2 + ts * (n - negpos), t1, negpos * ts);
     165          26 :                         memcpy(t, t2, n * ts);
     166             :                 }
     167             :         } /* else, everything is already in the correct place */
     168       20145 :         HEAPfree(&tmph, true);
     169       20144 :         if (t)
     170       19960 :                 HEAPfree(&tmpt, true);
     171             :         return GDK_SUCCEED;
     172             : }

Generated by: LCOV version 1.14