Changeset: 41d9cbfc1870 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/41d9cbfc1870
Modified Files:
        gdk/gdk_batop.c
        gdk/gdk_private.h
        gdk/gdk_rsort.c
Branch: default
Log Message:

Use radix sort also for inet6 and floating point.
We need a little trickery for floating point, but it works.


diffs (240 lines):

diff --git a/gdk/gdk_batop.c b/gdk/gdk_batop.c
--- a/gdk/gdk_batop.c
+++ b/gdk/gdk_batop.c
@@ -2569,13 +2569,20 @@ do_sort(void *restrict h, void *restrict
        case TYPE_timestamp:
                assert(base == NULL);
                if (nilslast == reverse && (stable || n > 100))
-                       return GDKrsort(h, t, n, hs, ts, reverse, false);
+                       return GDKrsort(h, t, n, hs, ts, reverse, false, false);
                break;
        case TYPE_uuid:
        case TYPE_inet4:
+       case TYPE_inet6:
                assert(base == NULL);
                if (nilslast == reverse && (stable || n > 100))
-                       return GDKrsort(h, t, n, hs, ts, reverse, true);
+                       return GDKrsort(h, t, n, hs, ts, reverse, true, false);
+               break;
+       case TYPE_flt:
+       case TYPE_dbl:
+               assert(base == NULL);
+               if (nilslast == reverse && (stable || n > 100))
+                       return GDKrsort(h, t, n, hs, ts, reverse, false, true);
                break;
        default:
                break;
diff --git a/gdk/gdk_private.h b/gdk/gdk_private.h
--- a/gdk/gdk_private.h
+++ b/gdk/gdk_private.h
@@ -159,7 +159,7 @@ gdk_return GDKremovedir(int farmid, cons
 gdk_return GDKsave(int farmid, const char *nme, const char *ext, void *buf, 
size_t size, storage_t mode, bool dosync)
        __attribute__((__warn_unused_result__))
        __attribute__((__visibility__("hidden")));
-gdk_return GDKrsort(void *restrict h, void *restrict t, size_t n, size_t hs, 
size_t ts, bool reverse, bool isuuid)
+gdk_return GDKrsort(void *restrict h, void *restrict t, size_t n, size_t hs, 
size_t ts, bool reverse, bool bigendian, bool isfloat)
        __attribute__((__warn_unused_result__))
        __attribute__((__visibility__("hidden")));
 gdk_return GDKssort_rev(void *restrict h, void *restrict t, const void 
*restrict base, size_t n, int hs, int ts, int tpe)
diff --git a/gdk/gdk_rsort.c b/gdk/gdk_rsort.c
--- a/gdk/gdk_rsort.c
+++ b/gdk/gdk_rsort.c
@@ -18,7 +18,8 @@
 /* bigendian means value is in big-endian byte order, but also that it
  * is unsigned */
 gdk_return
-GDKrsort(void *restrict h, void *restrict t, size_t n, size_t hs, size_t ts, 
bool reverse, bool bigendian)
+GDKrsort(void *restrict h, void *restrict t, size_t n, size_t hs, size_t ts,
+        bool reverse, bool bigendian, bool isfloat)
 {
        allocator *ta = MT_thread_getallocator();
        allocator_state ta_state = ma_open(ta);
@@ -30,6 +31,7 @@ GDKrsort(void *restrict h, void *restric
        uint8_t *t2 = NULL;
        Heap tmph, tmpt;
 
+       assert(!isfloat || !bigendian); /* not both */
        if (counts == NULL) {
                ma_close(&ta_state);
                return GDK_FAIL;
@@ -61,6 +63,31 @@ GDKrsort(void *restrict h, void *restric
                ts = 0;
        }
 
+       if (isfloat) {
+               /* for floating point numbers, we can sort using the bit
+                * pattern, but negative numbers are then sorted in the
+                * reverse order; we therefore temporarily flip all bits
+                * for negative numbers and set the sign bit for
+                * positive ones; then sorting produces the correct
+                * order; at the end we undo the temporary change */
+               for (size_t i = 0, o = 0; i < n; i++, o += hs) {
+#ifndef WORDS_BIGENDIAN
+                       if (h1[o + hs - 1] & 0x80)
+                               for (size_t j = 0; j < hs; j++)
+                                       h1[o + j] = ~h1[o + j];
+                       else
+                               h1[o + hs - 1] |= 0x80;
+#else
+                       if (h1[o] & 0x80)
+                               for (size_t j = 0; j < hs; j++)
+                                       h1[o + j] = ~h1[o + j];
+                       else
+                               h1[o] |= 0x80;
+#endif
+               }
+       }
+
+       /* produce a histogram for each iteration */
 #ifndef WORDS_BIGENDIAN
        if (bigendian /* treat like big-endian */) {
 #endif
@@ -80,11 +107,21 @@ GDKrsort(void *restrict h, void *restric
                }
        }
 #endif
-       /* When sorting in ascending order, the negative numbers occupy
-        * the second half of the buckets in the last iteration; when
-        * sorting in descending order, the negative numbers occupy the
-        * first half.  In either case, at the end we need to put the
-        * second half first and the first half after. */
+
+       /* sort from least significant byte to most significant byte;
+        * each step is stable, so later reshuffles preserve the
+        * relative order established by previous iterations */
+
+       /* When sorting signed integers in ascending order, the negative
+        * numbers occupy the second half of the buckets in the last
+        * iteration; when sorting in descending order, the negative
+        * numbers occupy the first half.  In either case, at the end we
+        * need to put the second half first and the first half
+        * after.
+        * When sorting floating point numbers, negative numbers are
+        * dealt with, but nils are in the wrong place, similar to
+        * negative numbers in signed integers.  We use the same
+        * technique, but the details are slightly different. */
        size_t negpos = 0;
        for (size_t j = 0, k = hs - 1; j < hs; j++, k--) {
                size_t nb = counts[j][0] > 0;
@@ -102,8 +139,12 @@ GDKrsort(void *restrict h, void *restric
                        }
                }
                /* we're only interested in the position in the last
-                * iteration */
-               negpos = pos[NBUCKETS / 2 - reverse];
+                * iteration; for floating point, we're looking for nil
+                * which is encoded as sign bit (temporarily set to 1)
+                * followed by a size-dependent number of 1 bits (8 for
+                * float, 11 for double but in any case more than 7), so
+                * we're just looking at the last position */
+               negpos = isfloat ? pos[NBUCKETS - 1 - reverse] : pos[NBUCKETS / 
2 - reverse];
                if (nb == 1) {
                        /* no need to reshuffle data for this iteration:
                         * everything is in the same bucket */
@@ -137,15 +178,86 @@ GDKrsort(void *restrict h, void *restric
        }
        ma_close(&ta_state);
 
+
+       if (isfloat) {
+               /* undo the temporary change (see above) */
+               for (size_t i = 0, o = 0; i < n; i++, o += hs) {
+#ifndef WORDS_BIGENDIAN
+                       if ((h1[o + hs - 1] & 0x80) == 0)
+                               for (size_t j = 0; j < hs; j++)
+                                       h1[o + j] = ~h1[o + j];
+                       else
+                               h1[o + hs - 1] &= 0x7F;
+#else
+                       if ((h1[o] & 0x80) == 0)
+                               for (size_t j = 0; j < hs; j++)
+                                       h1[o + j] = ~h1[o + j];
+                       else
+                               h1[o] &= 0x7F;
+#endif
+               }
+               /* Deal with nils, we need to find the correct starting
+                * position (which depends on more than just the most
+                * significant byte.
+                * A nil is represented by a NaN, and a NaN is encoded
+                * by any sign bit (you can have positive and negative
+                * NaN), all bits of exponent set, and significand
+                * non-zero (zero represents infinity) */
+               if (reverse) {
+                       if (hs == 4) {
+                               /* float */
+                               while (negpos > 0) {
+                                       uint32_t v = ((uint32_t *) h1)[negpos - 
1];
+                                       if ((v & UINT32_C(0x7F800000)) == 
UINT32_C(0x7F800000) &&
+                                           (v & UINT32_C(0x7FFFFF)) != 0)
+                                               break;
+                                       negpos--;
+                               }
+                       } else {
+                               assert(hs == 8);
+                               /* double */
+                               while (negpos > 0) {
+                                       uint64_t v = ((uint64_t *) h1)[negpos - 
1];
+                                       if ((v & UINT64_C(0x7FF0000000000000)) 
== UINT64_C(0x7FF0000000000000) &&
+                                           (v & UINT64_C(0xFFFFFFFFFFFFF)) != 
0)
+                                               break;
+                                       negpos--;
+                               }
+                       }
+               } else {
+                       if (hs == 4) {
+                               /* float */
+                               while (negpos < n) {
+                                       uint32_t v = ((uint32_t *) h1)[negpos];
+                                       if ((v & UINT32_C(0x7F800000)) == 
UINT32_C(0x7F800000) &&
+                                           (v & UINT32_C(0x7FFFFF)) != 0)
+                                               break;
+                                       negpos++;
+                               }
+                       } else {
+                               assert(hs == 8);
+                               /* double */
+                               while (negpos < n) {
+                                       uint64_t v = ((uint64_t *) h1)[negpos];
+                                       if ((v & UINT64_C(0x7FF0000000000000)) 
== UINT64_C(0x7FF0000000000000) &&
+                                           (v & UINT64_C(0xFFFFFFFFFFFFF)) != 
0)
+                                               break;
+                                       negpos++;
+                               }
+                       }
+               }
+       }
        if (h1 != (uint8_t *) h) {
                /* we need to copy the data back to the correct heap */
                if (bigendian) {
-                       /* no negative values in bigendian, so no shuffling */
+                       /* no negative values in bigendian, so no
+                        * shuffling */
                        memcpy(h2, h1, n * hs);
                        if (t)
                                memcpy(t2, t1, n * ts);
                } else {
-                       /* copy the negative integers to the start, copy 
positive after */
+                       /* copy the negative integers to the start, copy
+                        * positive after */
                        if (negpos < n) {
                                memcpy(h2, h1 + hs * negpos, (n - negpos) * hs);
                                if (t)
@@ -158,7 +270,8 @@ GDKrsort(void *restrict h, void *restric
                        }
                }
        } else if (negpos > 0 && negpos < n && !bigendian) {
-               /* copy the negative integers to the start, copy positive after 
*/
+               /* copy the negative integers to the start, copy
+                * positive after */
                memcpy(h2, h1 + hs * negpos, (n - negpos) * hs);
                memcpy(h2 + hs * (n - negpos), h1, negpos * hs);
                memcpy(h, h2, n * hs);
@@ -168,6 +281,7 @@ GDKrsort(void *restrict h, void *restric
                        memcpy(t, t2, n * ts);
                }
        } /* else, everything is already in the correct place */
+
        HEAPfree(&tmph, true);
        if (t)
                HEAPfree(&tmpt, true);
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to