LCOV - code coverage report
Current view: top level - gdk - gdk_group.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 321 411 78.1 %
Date: 2024-04-25 20:03:45 Functions: 3 3 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             : #include "gdk_cand.h"
      17             : 
      18             : /* how much to extend the extent and histo bats when we run out of space */
      19             : #define GROUPBATINCR    8192
      20             : 
      21             : /* BATgroup returns three bats that indicate the grouping of the input
      22             :  * bat.
      23             :  *
      24             :  * Grouping means that all equal values are in the same group, and
      25             :  * differing values are in different groups.  If specified, the input
      26             :  * bat g gives a pre-existing grouping which is then subdivided.  If a
      27             :  * candidate list s is specified, groups (both the pre-existing
      28             :  * grouping in g and the output grouping) are aligned with the
      29             :  * candidate list, else they are aligned with b.
      30             :  *
      31             :  * The outputs are as follows.
      32             :  *
      33             :  * The groups bat is aligned with the candidate list s, or the input
      34             :  * bat b if there is no candidate list, and the tail has group id's
      35             :  * (type oid).
      36             :  *
      37             :  * The extents and histo bats are indexed by group id.  The tail of
      38             :  * extents is the head oid from b of a representative of the group.
      39             :  * The tail of histo is of type lng and contains the number of
      40             :  * elements from b that are member of the group.  The extents BAT can
      41             :  * be used as a candidate list (sorted and unique).
      42             :  *
      43             :  * The extents and histo bats are optionally created.  The groups bat
      44             :  * is always created.  In other words, the groups argument may not be
      45             :  * NULL, but the extents and histo arguments may be NULL.
      46             :  *
      47             :  * There are six different implementations of the grouping code.
      48             :  *
      49             :  * If it can be trivially determined that all groups are singletons,
      50             :  * we can produce the outputs trivially.
      51             :  *
      52             :  * If all values in b are known to be equal (both sorted and reverse
      53             :  * sorted), we produce a single group or copy the input group.
      54             :  *
      55             :  * If the input bats b and g are sorted (either direction) or g is not
      56             :  * specified and b is sorted, or if the subsorted flag is set (only
      57             :  * used by BATsort), we only need to compare consecutive values.
      58             :  *
      59             :  * If the input bat b is sorted, but g is not, we can compare
      60             :  * consecutive values in b and need to scan sections of g for equal
      61             :  * groups.
      62             :  *
      63             :  * If a hash table already exists on b, we can make use of it.
      64             :  *
      65             :  * Otherwise we build a partial hash table on the fly.
      66             :  *
      67             :  * A decision should be made on the order in which grouping occurs.
      68             :  * Let |b| have << different values than |g| then the linked lists
      69             :  * gets extremely long, leading to a n^2 algorithm.
      70             :  * At the MAL level, the multigroup function would perform the dynamic
      71             :  * optimization.
      72             :  */
      73             : 
      74             : #define GRPnotfound()                                                   \
      75             :         do {                                                            \
      76             :                 /* no equal found: start new group */                   \
      77             :                 if (ngrp == maxgrps) {                                  \
      78             :                         /* we need to extend extents and histo bats, */ \
      79             :                         /* do it at most once */                        \
      80             :                         maxgrps = bi.count;                             \
      81             :                         if (extents) {                                  \
      82             :                                 BATsetcount(en, ngrp);                  \
      83             :                                 if (BATextend(en, maxgrps) != GDK_SUCCEED) \
      84             :                                         goto error;                     \
      85             :                                 exts = (oid *) Tloc(en, 0);             \
      86             :                         }                                               \
      87             :                         if (histo) {                                    \
      88             :                                 BATsetcount(hn, ngrp);                  \
      89             :                                 if (BATextend(hn, maxgrps) != GDK_SUCCEED) \
      90             :                                         goto error;                     \
      91             :                                 cnts = (lng *) Tloc(hn, 0);             \
      92             :                         }                                               \
      93             :                 }                                                       \
      94             :                 if (extents)                                            \
      95             :                         exts[ngrp] = hseqb + p - lo;                    \
      96             :                 if (histo)                                              \
      97             :                         cnts[ngrp] = 1;                                 \
      98             :                 ngrps[r] = ngrp++;                                      \
      99             :                 maxgrppos = r;                                          \
     100             :         } while (0)
     101             : 
     102             : 
     103             : #define GRP_compare_consecutive_values(INIT_0,INIT_1,DIFFER,KEEP)       \
     104             :         do {                                                            \
     105             :                 INIT_0;                                                 \
     106             :                 if (ci.tpe == cand_dense) {                             \
     107             :                         if (grps) {                                     \
     108             :                                 MT_thread_setalgorithm("GRP_compare_consecutive_values, dense, groups"); \
     109             :                                 TIMEOUT_LOOP_IDX(r, ci.ncand, timeoffset) { \
     110             :                                         p = canditer_next_dense(&ci) - hseqb; \
     111             :                                         INIT_1;                         \
     112             :                                         if (ngrp == 0 || grps[r] != prev || DIFFER) { \
     113             :                                                 GRPnotfound();          \
     114             :                                         } else {                        \
     115             :                                                 ngrps[r] = ngrp - 1;    \
     116             :                                                 if (histo)              \
     117             :                                                         cnts[ngrp - 1]++; \
     118             :                                         }                               \
     119             :                                         KEEP;                           \
     120             :                                         prev = grps[r];                 \
     121             :                                 }                                       \
     122             :                                 TIMEOUT_CHECK(timeoffset,               \
     123             :                                               GOTO_LABEL_TIMEOUT_HANDLER(error)); \
     124             :                         } else {                                        \
     125             :                                 MT_thread_setalgorithm("GRP_compare_consecutive_values, dense, !groups"); \
     126             :                                 TIMEOUT_LOOP_IDX(r, ci.ncand, timeoffset) { \
     127             :                                         p = canditer_next_dense(&ci) - hseqb; \
     128             :                                         INIT_1;                         \
     129             :                                         if (ngrp == 0 || DIFFER) {      \
     130             :                                                 GRPnotfound();          \
     131             :                                         } else {                        \
     132             :                                                 ngrps[r] = ngrp - 1;    \
     133             :                                                 if (histo)              \
     134             :                                                         cnts[ngrp - 1]++; \
     135             :                                         }                               \
     136             :                                         KEEP;                           \
     137             :                                 }                                       \
     138             :                                 TIMEOUT_CHECK(timeoffset,               \
     139             :                                               GOTO_LABEL_TIMEOUT_HANDLER(error)); \
     140             :                         }                                               \
     141             :                 } else {                                                \
     142             :                         if (grps) {                                     \
     143             :                                 MT_thread_setalgorithm("GRP_compare_consecutive_values, !dense, groups"); \
     144             :                                 TIMEOUT_LOOP_IDX(r, ci.ncand, timeoffset) { \
     145             :                                         p = canditer_next(&ci) - hseqb;     \
     146             :                                         INIT_1;                         \
     147             :                                         if (ngrp == 0 || grps[r] != prev || DIFFER) { \
     148             :                                                 GRPnotfound();          \
     149             :                                         } else {                        \
     150             :                                                 ngrps[r] = ngrp - 1;    \
     151             :                                                 if (histo)              \
     152             :                                                         cnts[ngrp - 1]++; \
     153             :                                         }                               \
     154             :                                         KEEP;                           \
     155             :                                         prev = grps[r];                 \
     156             :                                 }                                       \
     157             :                                 TIMEOUT_CHECK(timeoffset,               \
     158             :                                               GOTO_LABEL_TIMEOUT_HANDLER(error)); \
     159             :                         } else {                                        \
     160             :                                 MT_thread_setalgorithm("GRP_compare_consecutive_values, !dense, !groups"); \
     161             :                                 TIMEOUT_LOOP_IDX(r, ci.ncand, timeoffset) { \
     162             :                                         p = canditer_next(&ci) - hseqb;     \
     163             :                                         INIT_1;                         \
     164             :                                         if (ngrp == 0 || DIFFER) {      \
     165             :                                                 GRPnotfound();          \
     166             :                                         } else {                        \
     167             :                                                 ngrps[r] = ngrp - 1;    \
     168             :                                                 if (histo)              \
     169             :                                                         cnts[ngrp - 1]++; \
     170             :                                         }                               \
     171             :                                         KEEP;                           \
     172             :                                 }                                       \
     173             :                                 TIMEOUT_CHECK(timeoffset,               \
     174             :                                               GOTO_LABEL_TIMEOUT_HANDLER(error)); \
     175             :                         }                                               \
     176             :                 }                                                       \
     177             :         } while(0)
     178             : 
     179             : #define flt_neq(a, b)   (is_flt_nil(a) ? !is_flt_nil(b) : is_flt_nil(b) || (a) != (b))
     180             : #define dbl_neq(a, b)   (is_dbl_nil(a) ? !is_dbl_nil(b) : is_dbl_nil(b) || (a) != (b))
     181             : #define bte_neq(a, b)   ((a) != (b))
     182             : #define sht_neq(a, b)   ((a) != (b))
     183             : #define int_neq(a, b)   ((a) != (b))
     184             : #define lng_neq(a, b)   ((a) != (b))
     185             : #define hge_neq(a, b)   ((a) != (b))
     186             : 
     187             : #define GRP_compare_consecutive_values_tpe(TYPE)                \
     188             :         GRP_compare_consecutive_values(                         \
     189             :         /* INIT_0 */    const TYPE *w = (TYPE *) bi.base;       \
     190             :                         TYPE pw = 0                     ,       \
     191             :         /* INIT_1 */                                    ,       \
     192             :         /* DIFFER */    TYPE##_neq(w[p], pw)            ,       \
     193             :         /* KEEP   */    pw = w[p]                               \
     194             :         )
     195             : 
     196             : #define GRP_compare_consecutive_values_any()                    \
     197             :         GRP_compare_consecutive_values(                         \
     198             :         /* INIT_0 */    pv = NULL                       ,       \
     199             :         /* INIT_1 */    v = BUNtail(bi, p)              ,       \
     200             :         /* DIFFER */    cmp(v, pv) != 0                 ,       \
     201             :         /* KEEP   */    pv = v                                  \
     202             :         )
     203             : 
     204             : 
     205             : #define GRP_subscan_old_groups(INIT_0,INIT_1,EQUAL,KEEP)                \
     206             :         do {                                                            \
     207             :                 INIT_0;                                                 \
     208             :                 pgrp[grps[0]] = 0;                                      \
     209             :                 j = 0;                                                  \
     210             :                 if (ci.tpe == cand_dense) {                             \
     211             :                         MT_thread_setalgorithm("GRP_subscan_old_groups, dense"); \
     212             :                         TIMEOUT_LOOP_IDX(r, ci.ncand, timeoffset) {     \
     213             :                                 p = canditer_next_dense(&ci) - hseqb;       \
     214             :                                 INIT_1;                                 \
     215             :                                 if (ngrp != 0 && EQUAL) {               \
     216             :                                         /* range [j, r) is all same value */ \
     217             :                                         /* i is position where we saw r's */ \
     218             :                                         /* old group last */            \
     219             :                                         i = pgrp[grps[r]];              \
     220             :                                         /* p is new position where we saw this \
     221             :                                          * group */                     \
     222             :                                         pgrp[grps[r]] = r;              \
     223             :                                         if (j <= i && i < r)      {       \
     224             :                                                 /* i is position of equal */ \
     225             :                                                 /* value in same old group */ \
     226             :                                                 /* as r, so r gets same new */ \
     227             :                                                 /* group as i */        \
     228             :                                                 oid grp = ngrps[i];     \
     229             :                                                 ngrps[r] = grp;         \
     230             :                                                 if (histo)              \
     231             :                                                         cnts[grp]++;    \
     232             :                                                 if (gn->tsorted &&   \
     233             :                                                     grp != ngrp - 1)    \
     234             :                                                         gn->tsorted = false; \
     235             :                                                 /* we found the value/group */ \
     236             :                                                 /* combination, go to next */ \
     237             :                                                 /* value */             \
     238             :                                                 continue;               \
     239             :                                         }                               \
     240             :                                 } else {                                \
     241             :                                         /* value differs from previous value */ \
     242             :                                         /* (or is the first) */         \
     243             :                                         j = r;                          \
     244             :                                         KEEP;                           \
     245             :                                         pgrp[grps[r]] = r;              \
     246             :                                 }                                       \
     247             :                                 /* start a new group */                 \
     248             :                                 GRPnotfound();                          \
     249             :                         }                                               \
     250             :                         TIMEOUT_CHECK(timeoffset,                       \
     251             :                                       GOTO_LABEL_TIMEOUT_HANDLER(error)); \
     252             :                 } else {                                                \
     253             :                         MT_thread_setalgorithm("GRP_subscan_old_groups, !dense"); \
     254             :                         TIMEOUT_LOOP_IDX(r, ci.ncand, timeoffset) {     \
     255             :                                 p = canditer_next(&ci) - hseqb;             \
     256             :                                 INIT_1;                                 \
     257             :                                 if (ngrp != 0 && EQUAL) {               \
     258             :                                         /* range [j, r) is all same value */ \
     259             :                                         /* i is position where we saw r's */ \
     260             :                                         /* old group last */            \
     261             :                                         i = pgrp[grps[r]];              \
     262             :                                         /* p is new position where we saw this \
     263             :                                          * group */                     \
     264             :                                         pgrp[grps[r]] = r;              \
     265             :                                         if (j <= i && i < r)      {       \
     266             :                                                 /* i is position of equal */ \
     267             :                                                 /* value in same old group */ \
     268             :                                                 /* as r, so r gets same new */ \
     269             :                                                 /* group as i */        \
     270             :                                                 oid grp = ngrps[i];     \
     271             :                                                 ngrps[r] = grp;         \
     272             :                                                 if (histo)              \
     273             :                                                         cnts[grp]++;    \
     274             :                                                 if (gn->tsorted &&   \
     275             :                                                     grp != ngrp - 1)    \
     276             :                                                         gn->tsorted = false; \
     277             :                                                 /* we found the value/group */ \
     278             :                                                 /* combination, go to next */ \
     279             :                                                 /* value */             \
     280             :                                                 continue;               \
     281             :                                         }                               \
     282             :                                 } else {                                \
     283             :                                         /* value differs from previous value */ \
     284             :                                         /* (or is the first) */         \
     285             :                                         j = r;                          \
     286             :                                         KEEP;                           \
     287             :                                         pgrp[grps[r]] = r;              \
     288             :                                 }                                       \
     289             :                                 /* start a new group */                 \
     290             :                                 GRPnotfound();                          \
     291             :                         }                                               \
     292             :                         TIMEOUT_CHECK(timeoffset,                       \
     293             :                                       GOTO_LABEL_TIMEOUT_HANDLER(error)); \
     294             :                 }                                                       \
     295             :         } while(0)
     296             : 
     297             : #define flt_equ(a, b)   (is_flt_nil(a) ? is_flt_nil(b) : !is_flt_nil(b) && (a) == (b))
     298             : #define dbl_equ(a, b)   (is_dbl_nil(a) ? is_dbl_nil(b) : !is_dbl_nil(b) && (a) == (b))
     299             : #define bte_equ(a, b)   ((a) == (b))
     300             : #define sht_equ(a, b)   ((a) == (b))
     301             : #define int_equ(a, b)   ((a) == (b))
     302             : #define lng_equ(a, b)   ((a) == (b))
     303             : #define hge_equ(a, b)   ((a) == (b))
     304             : #ifdef HAVE_HGE
     305             : #define uuid_equ(a, b)  ((a).h == (b).h)
     306             : #else
     307             : #define uuid_equ(a, b)  (memcmp((a).u, (b).u, UUID_SIZE) == 0)
     308             : #endif
     309             : 
     310             : #define GRP_subscan_old_groups_tpe(TYPE)                        \
     311             :         GRP_subscan_old_groups(                                 \
     312             :         /* INIT_0 */    const TYPE *w = (TYPE *) bi.base;       \
     313             :                         TYPE pw = 0                     ,       \
     314             :         /* INIT_1 */                                    ,       \
     315             :         /* EQUAL  */    TYPE##_equ(w[p], pw)            ,       \
     316             :         /* KEEP   */    pw = w[p]                               \
     317             :         )
     318             : 
     319             : #define GRP_subscan_old_groups_any()                            \
     320             :         GRP_subscan_old_groups(                                 \
     321             :         /* INIT_0 */    pv = NULL                       ,       \
     322             :         /* INIT_1 */    v = BUNtail(bi, p)              ,       \
     323             :         /* EQUAL  */    cmp(v, pv) == 0                 ,       \
     324             :         /* KEEP   */    pv = v                                  \
     325             :         )
     326             : 
     327             : /* If a hash table exists on b we use it.
     328             :  *
     329             :  * The algorithm is simple.  We go through b and for each value we
     330             :  * follow the hash chain starting at the next element after that value
     331             :  * to find one that is equal to the value we're currently looking at.
     332             :  * If we found such a value, we add the value to the same group.  If
     333             :  * we reach the end of the chain, we create a new group.
     334             :  *
     335             :  * If b (the original, that is) is a view on another BAT, and this
     336             :  * other BAT has a hash, we use that.  The lo and hi values are the
     337             :  * bounds of the parent BAT that we're considering.
     338             :  *
     339             :  * Note this algorithm depends critically on the fact that our hash
     340             :  * chains go from higher to lower BUNs.
     341             :  */
     342             : #define GRP_use_existing_hash_table(INIT_0,INIT_1,EQUAL)                \
     343             :         do {                                                            \
     344             :                 INIT_0;                                                 \
     345             :                 assert(grps == NULL);                                   \
     346             :                 if (ci.tpe == cand_dense) {                             \
     347             :                         MT_thread_setalgorithm(phash ? "GRP_use_existing_hash_table, dense, parent hash" : "GRP_use_existing_hash_table, dense"); \
     348             :                         TIMEOUT_LOOP_IDX(r, ci.ncand, timeoffset) {     \
     349             :                                 oid o = canditer_next_dense(&ci);   \
     350             :                                 p = o - hseqb + lo;                     \
     351             :                                 INIT_1;                                 \
     352             :                                 /* this loop is similar, but not */     \
     353             :                                 /* equal, to HASHloop: the difference */ \
     354             :                                 /* is that we only consider BUNs */     \
     355             :                                 /* smaller than the one we're looking */ \
     356             :                                 /* up (p) */                            \
     357             :                                 for (hb = HASHgetlink(hs, p);           \
     358             :                                      hb != BUN_NONE && hb >= lo;     \
     359             :                                      hb = HASHgetlink(hs, hb)) {        \
     360             :                                         oid grp;                        \
     361             :                                         assert(hb < p);                      \
     362             :                                         q = canditer_search_dense(&ci, hb + hseqb - lo, false); \
     363             :                                         if (q == BUN_NONE)              \
     364             :                                                 continue;               \
     365             :                                         if (EQUAL) {                    \
     366             :                                                 grp = ngrps[q];         \
     367             :                                                 ngrps[r] = grp;         \
     368             :                                                 if (histo)              \
     369             :                                                         cnts[grp]++;    \
     370             :                                                 if (gn->tsorted &&   \
     371             :                                                     grp != ngrp - 1)    \
     372             :                                                         gn->tsorted = false; \
     373             :                                                 break;                  \
     374             :                                         }                               \
     375             :                                 }                                       \
     376             :                                 if (hb == BUN_NONE || hb < lo) {     \
     377             :                                         GRPnotfound();                  \
     378             :                                 }                                       \
     379             :                         }                                               \
     380             :                         TIMEOUT_CHECK(timeoffset,                       \
     381             :                                       GOTO_LABEL_TIMEOUT_HANDLER(error)); \
     382             :                 } else {                                                \
     383             :                         MT_thread_setalgorithm(phash ? "GRP_use_existing_hash_table, !dense, parent hash" : "GRP_use_existing_hash_table, !dense"); \
     384             :                         TIMEOUT_LOOP_IDX(r, ci.ncand, timeoffset) {     \
     385             :                                 oid o = canditer_next(&ci);         \
     386             :                                 p = o - hseqb + lo;                     \
     387             :                                 INIT_1;                                 \
     388             :                                 /* this loop is similar, but not */     \
     389             :                                 /* equal, to HASHloop: the difference */ \
     390             :                                 /* is that we only consider BUNs */     \
     391             :                                 /* smaller than the one we're looking */ \
     392             :                                 /* up (p) */                            \
     393             :                                 for (hb = HASHgetlink(hs, p);           \
     394             :                                      hb != BUN_NONE && hb >= lo;     \
     395             :                                      hb = HASHgetlink(hs, hb)) {        \
     396             :                                         oid grp;                        \
     397             :                                         assert(hb < p);                      \
     398             :                                         q = canditer_search(&ci, hb + hseqb - lo, false); \
     399             :                                         if (q == BUN_NONE)              \
     400             :                                                 continue;               \
     401             :                                         if (EQUAL) {                    \
     402             :                                                 grp = ngrps[q];         \
     403             :                                                 ngrps[r] = grp;         \
     404             :                                                 if (histo)              \
     405             :                                                         cnts[grp]++;    \
     406             :                                                 if (gn->tsorted &&   \
     407             :                                                     grp != ngrp - 1)    \
     408             :                                                         gn->tsorted = false; \
     409             :                                                 break;                  \
     410             :                                         }                               \
     411             :                                 }                                       \
     412             :                                 if (hb == BUN_NONE || hb < lo) {     \
     413             :                                         GRPnotfound();                  \
     414             :                                 }                                       \
     415             :                         }                                               \
     416             :                         TIMEOUT_CHECK(timeoffset,                       \
     417             :                                       GOTO_LABEL_TIMEOUT_HANDLER(error)); \
     418             :                 }                                                       \
     419             :         } while(0)
     420             : 
     421             : #define GRP_use_existing_hash_table_tpe(TYPE)                   \
     422             :         GRP_use_existing_hash_table(                            \
     423             :         /* INIT_0 */    const TYPE *w = (TYPE *) bi.base,       \
     424             :         /* INIT_1 */                                    ,       \
     425             :         /* EQUAL  */    TYPE##_equ(w[p], w[hb])                 \
     426             :         )
     427             : 
     428             : #define GRP_use_existing_hash_table_any()                       \
     429             :         GRP_use_existing_hash_table(                            \
     430             :         /* INIT_0 */                                    ,       \
     431             :         /* INIT_1 */    v = BUNtail(bi, p)              ,       \
     432             :         /* EQUAL  */    cmp(v, BUNtail(bi, hb)) == 0            \
     433             :         )
     434             : 
     435             : /* reverse the bits of an OID value */
     436             : static inline oid
     437    42870807 : rev(oid x)
     438             : {
     439             : #if SIZEOF_OID == 8
     440    42870807 :         x = ((x & 0x5555555555555555) <<  1) | ((x >>  1) & 0x5555555555555555);
     441    42870807 :         x = ((x & 0x3333333333333333) <<  2) | ((x >>  2) & 0x3333333333333333);
     442    42870807 :         x = ((x & 0x0F0F0F0F0F0F0F0F) <<  4) | ((x >>  4) & 0x0F0F0F0F0F0F0F0F);
     443    42870807 :         x = ((x & 0x00FF00FF00FF00FF) <<  8) | ((x >>  8) & 0x00FF00FF00FF00FF);
     444    42870807 :         x = ((x & 0x0000FFFF0000FFFF) << 16) | ((x >> 16) & 0x0000FFFF0000FFFF);
     445    42870807 :         x = ((x & 0x00000000FFFFFFFF) << 32) | ((x >> 32) & 0x00000000FFFFFFFF);
     446             : #else
     447             :         x = ((x & 0x55555555) <<  1) | ((x >>  1) & 0x55555555);
     448             :         x = ((x & 0x33333333) <<  2) | ((x >>  2) & 0x33333333);
     449             :         x = ((x & 0x0F0F0F0F) <<  4) | ((x >>  4) & 0x0F0F0F0F);
     450             :         x = ((x & 0x00FF00FF) <<  8) | ((x >>  8) & 0x00FF00FF);
     451             :         x = ((x & 0x0000FFFF) << 16) | ((x >> 16) & 0x0000FFFF);
     452             : #endif
     453    42870807 :         return x;
     454             : }
     455             : 
     456             : /* count trailing zeros, also see candmask_lobit in gdk_cand.h */
     457             : static inline int __attribute__((__const__))
     458       12440 : ctz(oid x)
     459             : {
     460             : #if defined(__GNUC__)
     461             : #if SIZEOF_OID == SIZEOF_INT
     462             :         return __builtin_ctz(x);
     463             : #else
     464       12440 :         return __builtin_ctzl(x);
     465             : #endif
     466             : #elif defined(_MSC_VER)
     467             : #if SIZEOF_OID == SIZEOF_INT
     468             :         unsigned long idx;
     469             :         if (_BitScanForward(&idx, (unsigned long) x))
     470             :                 return (int) idx;
     471             : #else
     472             :         unsigned long idx;
     473             :         if (_BitScanForward64(&idx, (unsigned __int64) x))
     474             :                 return (int) idx;
     475             : #endif
     476             :         return -1;
     477             : #else
     478             :         /* use binary search for the lowest set bit */
     479             :         int n = 1;
     480             : #if SIZEOF_OID == SIZEOF_INT
     481             :         if ((x & 0x0000FFFF) == 0) { n += 16; x >>= 16; }
     482             :         if ((x & 0x000000FF) == 0) { n +=  8; x >>=  8; }
     483             :         if ((x & 0x0000000F) == 0) { n +=  4; x >>=  4; }
     484             :         if ((x & 0x00000003) == 0) { n +=  2; x >>=  2; }
     485             : #else
     486             :         if ((x & UINT64_C(0x00000000FFFFFFFF)) == 0) { n += 32; x >>= 32; }
     487             :         if ((x & UINT64_C(0x000000000000FFFF)) == 0) { n += 16; x >>= 16; }
     488             :         if ((x & UINT64_C(0x00000000000000FF)) == 0) { n +=  8; x >>=  8; }
     489             :         if ((x & UINT64_C(0x000000000000000F)) == 0) { n +=  4; x >>=  4; }
     490             :         if ((x & UINT64_C(0x0000000000000003)) == 0) { n +=  2; x >>=  2; }
     491             : #endif
     492             :         return n - (x & 1);
     493             : #endif
     494             : }
     495             : 
     496             : #define GRP_create_partial_hash_table_core(INIT_1,HASH,EQUAL,ASSERT,GRPTST) \
     497             :         do {                                                            \
     498             :                 if (ci.tpe == cand_dense) {                             \
     499             :                         MT_thread_setalgorithm("GRP_create_partial_hash_table, dense"); \
     500             :                         TIMEOUT_LOOP_IDX(r, ci.ncand, timeoffset) {     \
     501             :                                 p = canditer_next_dense(&ci) - hseqb;       \
     502             :                                 INIT_1;                                 \
     503             :                                 prb = HASH;                             \
     504             :                                 for (hb = HASHget(hs, prb);             \
     505             :                                      hb != BUN_NONE;                    \
     506             :                                      hb = HASHgetlink(hs, hb)) {        \
     507             :                                         ASSERT;                         \
     508             :                                         q = canditer_search_dense(&ci, hb + hseqb, false); \
     509             :                                         if (q == BUN_NONE)              \
     510             :                                                 continue;               \
     511             :                                         GRPTST(q, r);                   \
     512             :                                         if (EQUAL) {                    \
     513             :                                                 grp = ngrps[q];         \
     514             :                                                 ngrps[r] = grp;         \
     515             :                                                 if (histo)              \
     516             :                                                         cnts[grp]++;    \
     517             :                                                 if (gn->tsorted &&   \
     518             :                                                     grp != ngrp - 1)    \
     519             :                                                         gn->tsorted = false; \
     520             :                                                 break;                  \
     521             :                                         }                               \
     522             :                                 }                                       \
     523             :                                 if (hb == BUN_NONE) {                   \
     524             :                                         GRPnotfound();                  \
     525             :                                         /* enter new group into hash table */ \
     526             :                                         HASHputlink(hs, p, HASHget(hs, prb)); \
     527             :                                         HASHput(hs, prb, p);            \
     528             :                                 }                                       \
     529             :                         }                                               \
     530             :                         TIMEOUT_CHECK(timeoffset,                       \
     531             :                                       GOTO_LABEL_TIMEOUT_HANDLER(error)); \
     532             :                 } else {                                                \
     533             :                         MT_thread_setalgorithm("GRP_create_partial_hash_table, !dense"); \
     534             :                         TIMEOUT_LOOP_IDX(r, ci.ncand, timeoffset) {     \
     535             :                                 p = canditer_next(&ci) - hseqb;             \
     536             :                                 INIT_1;                                 \
     537             :                                 prb = HASH;                             \
     538             :                                 for (hb = HASHget(hs, prb);             \
     539             :                                      hb != BUN_NONE;                    \
     540             :                                      hb = HASHgetlink(hs, hb)) {        \
     541             :                                         ASSERT;                         \
     542             :                                         q = canditer_search(&ci, hb + hseqb, false); \
     543             :                                         if (q == BUN_NONE)              \
     544             :                                                 continue;               \
     545             :                                         GRPTST(q, r);                   \
     546             :                                         if (EQUAL) {                    \
     547             :                                                 grp = ngrps[q];         \
     548             :                                                 ngrps[r] = grp;         \
     549             :                                                 if (histo)              \
     550             :                                                         cnts[grp]++;    \
     551             :                                                 if (gn->tsorted &&   \
     552             :                                                     grp != ngrp - 1)    \
     553             :                                                         gn->tsorted = false; \
     554             :                                                 break;                  \
     555             :                                         }                               \
     556             :                                 }                                       \
     557             :                                 if (hb == BUN_NONE) {                   \
     558             :                                         GRPnotfound();                  \
     559             :                                         /* enter new group into hash table */ \
     560             :                                         HASHputlink(hs, p, HASHget(hs, prb)); \
     561             :                                         HASHput(hs, prb, p);            \
     562             :                                 }                                       \
     563             :                         }                                               \
     564             :                         TIMEOUT_CHECK(timeoffset,                       \
     565             :                                       GOTO_LABEL_TIMEOUT_HANDLER(error)); \
     566             :                 }                                                       \
     567             :         } while (0)
     568             : #define GCGRPTST(i, j)  if (grps[i] != grps[j]) { hb = BUN_NONE; break; }
     569             : #define GRPTST(i, j)    if (grps[i] != grps[j]) continue
     570             : #define NOGRPTST(i, j)  (void) 0
     571             : #define GRP_create_partial_hash_table(INIT_0,INIT_1,HASH,EQUAL)         \
     572             :         do {                                                            \
     573             :                 INIT_0;                                                 \
     574             :                 if (grps) {                                             \
     575             :                         if (gc) {                                       \
     576             :                                 GRP_create_partial_hash_table_core(INIT_1,HASH,EQUAL,assert(HASHgetlink(hs, hb) == BUN_NONE || HASHgetlink(hs, hb) < hb),GCGRPTST); \
     577             :                         } else {                                        \
     578             :                                 GRP_create_partial_hash_table_core(INIT_1,HASH ^ (rev(grps[r]) >> bits),EQUAL,(void)0,GRPTST); \
     579             :                         }                                               \
     580             :                 } else {                                                \
     581             :                         GRP_create_partial_hash_table_core(INIT_1,HASH,EQUAL,(void)0,NOGRPTST); \
     582             :                 }                                                       \
     583             :         } while (0)
     584             : 
     585             : #define GRP_create_partial_hash_table_tpe(TYPE)                 \
     586             :         GRP_create_partial_hash_table(                          \
     587             :         /* INIT_0 */    const TYPE *w = (TYPE *) bi.base,       \
     588             :         /* INIT_1 */                                    ,       \
     589             :         /* HASH   */    hash_##TYPE(hs, &w[p])              ,       \
     590             :         /* EQUAL  */    TYPE##_equ(w[p], w[hb])                 \
     591             :         )
     592             : 
     593             : #define GRP_create_partial_hash_table_any()                     \
     594             :         GRP_create_partial_hash_table(                          \
     595             :         /* INIT_0 */                                    ,       \
     596             :         /* INIT_1 */    v = BUNtail(bi, p)              ,       \
     597             :         /* HASH   */    hash_any(hs, v)                 ,       \
     598             :         /* EQUAL  */    cmp(v, BUNtail(bi, hb)) == 0            \
     599             :         )
     600             : 
     601             : #define GRP_small_values(BG, BV, GV)                                    \
     602             :         do {                                                            \
     603             :                 uint##BG##_t sgrps[1 << BG];                              \
     604             :                 const uint##BV##_t *restrict w = (const uint##BV##_t *) bi.base; \
     605             :                 uint##BG##_t v;                                         \
     606             :                 memset(sgrps, 0xFF, sizeof(sgrps));                     \
     607             :                 if (histo)                                              \
     608             :                         memset(cnts, 0, maxgrps * sizeof(lng));         \
     609             :                 ngrp = 0;                                               \
     610             :                 gn->tsorted = true;                                  \
     611             :                 if (ci.tpe == cand_dense) {                             \
     612             :                         TIMEOUT_LOOP_IDX(r, ci.ncand, timeoffset) {     \
     613             :                                 oid o = canditer_next_dense(&ci);   \
     614             :                                 p = o - hseqb;                          \
     615             :                                 uint##BG##_t x = GV;                    \
     616             :                                 if ((v = sgrps[x]) == (uint##BG##_t) ~0 && ngrp < (1 << BG)) { \
     617             :                                         sgrps[x] = v = (uint##BG##_t) ngrp++; \
     618             :                                         maxgrppos = r;                  \
     619             :                                         if (extents)                    \
     620             :                                                 exts[v] = o;            \
     621             :                                 }                                       \
     622             :                                 ngrps[r] = v;                           \
     623             :                                 if (r > 0 && v < ngrps[r - 1])            \
     624             :                                         gn->tsorted = false;         \
     625             :                                 if (histo)                              \
     626             :                                         cnts[v]++;                      \
     627             :                         }                                               \
     628             :                 } else {                                                \
     629             :                         TIMEOUT_LOOP_IDX(r, ci.ncand, timeoffset) {     \
     630             :                                 oid o = canditer_next(&ci);         \
     631             :                                 p = o - hseqb;                          \
     632             :                                 uint##BG##_t x = GV;                    \
     633             :                                 if ((v = sgrps[x]) == (uint##BG##_t) ~0 && ngrp < (1 << BG)) { \
     634             :                                         sgrps[x] = v = (uint##BG##_t) ngrp++; \
     635             :                                         maxgrppos = r;                  \
     636             :                                         if (extents)                    \
     637             :                                                 exts[v] = o;            \
     638             :                                 }                                       \
     639             :                                 ngrps[r] = v;                           \
     640             :                                 if (r > 0 && v < ngrps[r - 1])            \
     641             :                                         gn->tsorted = false;         \
     642             :                                 if (histo)                              \
     643             :                                         cnts[v]++;                      \
     644             :                         }                                               \
     645             :                 }                                                       \
     646             :                 TIMEOUT_CHECK(timeoffset,                               \
     647             :                               GOTO_LABEL_TIMEOUT_HANDLER(error));       \
     648             :         } while (0)
     649             : 
     650             : gdk_return
     651       63810 : BATgroup_internal(BAT **groups, BAT **extents, BAT **histo,
     652             :                   BAT *b, BAT *s, BAT *g, BAT *e, BAT *h, bool subsorted)
     653             : {
     654       63810 :         BAT *gn = NULL, *en = NULL, *hn = NULL;
     655       63810 :         int t;
     656       63810 :         int (*cmp)(const void *, const void *);
     657       63810 :         const oid *grps = NULL;
     658       63810 :         oid *restrict ngrps, ngrp, prev = 0, hseqb = 0;
     659       63810 :         oid *restrict exts = NULL;
     660       63810 :         lng *restrict cnts = NULL;
     661       63810 :         BUN p, q, r;
     662       63810 :         const void *v, *pv;
     663       63810 :         BATiter bi;
     664       63810 :         Hash *hs = NULL;
     665       63810 :         BUN hb;
     666       63810 :         BUN maxgrps;
     667       63810 :         BUN maxgrppos = BUN_NONE;
     668       63810 :         bat parent;
     669       63810 :         BUN lo = 0;
     670       63810 :         struct canditer ci;
     671       63810 :         oid maxgrp = oid_nil;   /* maximum value of g BAT (if subgrouping) */
     672       63810 :         lng t0 = 0;
     673       63810 :         const char *algomsg = "";
     674       63810 :         bool locked = false;
     675             : 
     676       63810 :         lng timeoffset = 0;
     677       63810 :         QryCtx *qry_ctx = MT_thread_get_qry_ctx();
     678       63810 :         if (qry_ctx != NULL) {
     679       58083 :                 timeoffset = (qry_ctx->starttime && qry_ctx->querytimeout) ? (qry_ctx->starttime + qry_ctx->querytimeout) : 0;
     680             :         }
     681             : 
     682       63810 :         TRC_DEBUG_IF(ALGO) t0 = GDKusec();
     683       63810 :         if (b == NULL) {
     684           0 :                 GDKerror("b must exist\n");
     685           0 :                 return GDK_FAIL;
     686             :         }
     687       63810 :         assert(s == NULL || BATttype(s) == TYPE_oid);
     688       63810 :         canditer_init(&ci, b, s);
     689       63809 :         bi = bat_iterator(b);
     690             : 
     691             :         /* g is NULL or [oid(dense),oid] and same size as b or s */
     692       63801 :         assert(g == NULL || BATttype(g) == TYPE_oid || BATcount(g) == 0);
     693       19272 :         assert(g == NULL || BATcount(g) == ci.ncand);
     694       19272 :         assert(g == NULL || BATcount(b) == 0 || (s ? g->hseqbase == s->hseqbase : g->hseqbase == b->hseqbase));
     695             :         /* e is NULL or [oid(dense),oid] */
     696       63801 :         assert(e == NULL || BATttype(e) == TYPE_oid);
     697             :         /* h is NULL or [oid(dense),lng] */
     698       63801 :         assert(h == NULL || h->ttype == TYPE_lng);
     699             :         /* e and h are aligned */
     700       63801 :         assert(e == NULL || h == NULL || BATcount(e) == BATcount(h));
     701       63801 :         assert(e == NULL || h == NULL || e->hseqbase == h->hseqbase);
     702             :         /* we want our output to go somewhere */
     703       63801 :         assert(groups != NULL);
     704             : 
     705       63801 :         if (ci.ncand == 0) {
     706             :                 hseqb = 0;
     707             :         } else {
     708       48260 :                 hseqb = ci.seq;
     709             :         }
     710       63801 :         if (bi.key || ci.ncand <= 1 || (g && (g->tkey || BATtdense(g)))) {
     711             :                 /* grouping is trivial: 1 element per group */
     712       31602 :                 gn = BATdense(hseqb, 0, BATcount(b));
     713       31614 :                 if (gn == NULL)
     714           0 :                         goto error;
     715       31614 :                 *groups = gn;
     716       31614 :                 if (extents) {
     717       31177 :                         en = canditer_slice(&ci, 0, ci.ncand);
     718       31177 :                         if (en == NULL)
     719           0 :                                 goto error;
     720       31177 :                         *extents = en;
     721             :                 }
     722       31614 :                 if (histo) {
     723        3203 :                         hn = BATconstant(0, TYPE_lng, &(lng){1}, ci.ncand, TRANSIENT);
     724        3203 :                         if (hn == NULL)
     725           0 :                                 goto error;
     726        3203 :                         *histo = hn;
     727             :                 }
     728       31614 :                 bat_iterator_end(&bi);
     729       31614 :                 TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",s=" ALGOOPTBATFMT
     730             :                           ",g=" ALGOOPTBATFMT ",e=" ALGOOPTBATFMT
     731             :                           ",h=" ALGOOPTBATFMT ",subsorted=%s -> groups="
     732             :                           ALGOOPTBATFMT ",extents=" ALGOOPTBATFMT
     733             :                           ",histo=" ALGOOPTBATFMT " (1 element per group -- "
     734             :                           LLFMT " usec)\n",
     735             :                           ALGOBATPAR(b), ALGOOPTBATPAR(s), ALGOOPTBATPAR(g),
     736             :                           ALGOOPTBATPAR(e), ALGOOPTBATPAR(h),
     737             :                           subsorted ? "true" : "false", ALGOOPTBATPAR(gn),
     738             :                           ALGOOPTBATPAR(en), ALGOOPTBATPAR(hn), GDKusec() - t0);
     739       31614 :                 return GDK_SUCCEED;
     740             :         }
     741       32199 :         assert(!BATtdense(b));
     742       32199 :         if (g) {
     743        6275 :                 assert(!BATtdense(g));
     744        6275 :                 if (g->tsorted)
     745        4691 :                         maxgrp = * (oid *) Tloc(g, BATcount(g) - 1);
     746        1584 :                 else if (g->trevsorted)
     747           0 :                         maxgrp = * (oid *) Tloc(g, 0);
     748             :                 else {
     749             :                         /* group bats are not modified in parallel, so
     750             :                          * no need for locks */
     751        1584 :                         if (g->tmaxpos != BUN_NONE)
     752        1581 :                                 maxgrp = BUNtoid(g, g->tmaxpos);
     753        1584 :                         if (is_oid_nil(maxgrp) /* && BATcount(g) < 10240 */) {
     754           3 :                                 BATmax(g, &maxgrp);
     755             :                         }
     756             :                 }
     757        6275 :                 if (maxgrp == 0)
     758             :                         g = NULL; /* single group */
     759             :                 else
     760        4480 :                         grps = (const oid *) Tloc(g, 0);
     761             :         }
     762       32199 :         (void) BATordered(b);
     763       32199 :         (void) BATordered_rev(b);
     764       32200 :         bat_iterator_end(&bi);
     765       32200 :         bi = bat_iterator(b);
     766       32199 :         if (bi.sorted && bi.revsorted) {
     767             :                 /* all values are equal */
     768        3204 :                 if (g == NULL || (BATordered(g) && BATordered_rev(g))) {
     769             :                         /* there's only a single group: 0 */
     770        2881 :                         gn = BATconstant(hseqb, TYPE_oid, &(oid){0}, ci.ncand, TRANSIENT);
     771        2881 :                         if (gn == NULL)
     772           0 :                                 goto error;
     773        2881 :                         *groups = gn;
     774        2881 :                         if (extents) {
     775        1961 :                                 en = BATdense(0, canditer_next(&ci), 1);
     776        1961 :                                 if (en == NULL)
     777           0 :                                         goto error;
     778        1961 :                                 *extents = en;
     779             :                         }
     780        2881 :                         if (histo) {
     781          45 :                                 hn = BATconstant(0, TYPE_lng, &(lng){(lng)ci.ncand}, 1, TRANSIENT);
     782          45 :                                 if (hn == NULL)
     783           0 :                                         goto error;
     784          45 :                                 *histo = hn;
     785             :                         }
     786        2881 :                         bat_iterator_end(&bi);
     787        2882 :                         TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",s=" ALGOOPTBATFMT
     788             :                                   ",g=" ALGOOPTBATFMT ",e=" ALGOOPTBATFMT
     789             :                                   ",h=" ALGOOPTBATFMT ",subsorted=%s -> groups="
     790             :                                   ALGOOPTBATFMT ",extents=" ALGOOPTBATFMT
     791             :                                   ",histo=" ALGOOPTBATFMT " (single group -- "
     792             :                                   LLFMT " usec)\n",
     793             :                                   ALGOBATPAR(b), ALGOOPTBATPAR(s),
     794             :                                   ALGOOPTBATPAR(g), ALGOOPTBATPAR(e),
     795             :                                   ALGOOPTBATPAR(h),
     796             :                                   subsorted ? "true" : "false",
     797             :                                   ALGOOPTBATPAR(gn), ALGOOPTBATPAR(en),
     798             :                                   ALGOOPTBATPAR(hn), GDKusec() - t0);
     799        2882 :                         return GDK_SUCCEED;
     800             :                 }
     801         323 :                 if ((extents == NULL || e != NULL) &&
     802         142 :                     (histo == NULL || h != NULL) &&
     803         142 :                     ci.ncand == BATcount(b)) {
     804             :                         /* inherit given grouping; note that if
     805             :                          * extents/histo is to be returned, we need
     806             :                          * e/h available in order to copy them,
     807             :                          * otherwise we will need to calculate them
     808             :                          * which we will do using the "normal" case */
     809         142 :                         gn = COLcopy(g, g->ttype, false, TRANSIENT);
     810         142 :                         if (gn == NULL)
     811           0 :                                 goto error;
     812             : 
     813         142 :                         *groups = gn;
     814         142 :                         if (extents) {
     815           0 :                                 en = COLcopy(e, e->ttype, false, TRANSIENT);
     816           0 :                                 if (en == NULL)
     817           0 :                                         goto error;
     818           0 :                                 *extents = en;
     819             :                         }
     820         142 :                         if (histo) {
     821           0 :                                 hn = COLcopy(h, h->ttype, false, TRANSIENT);
     822           0 :                                 if (hn == NULL)
     823           0 :                                         goto error;
     824           0 :                                 *histo = hn;
     825             :                         }
     826         142 :                         bat_iterator_end(&bi);
     827         142 :                         TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",s=" ALGOOPTBATFMT
     828             :                                   ",g=" ALGOOPTBATFMT ",e=" ALGOOPTBATFMT
     829             :                                   ",h=" ALGOOPTBATFMT ",subsorted=%s -> groups="
     830             :                                   ALGOOPTBATFMT ",extents=" ALGOOPTBATFMT
     831             :                                   ",histo=" ALGOOPTBATFMT " (copy groups -- "
     832             :                                   LLFMT " usec)\n",
     833             :                                   ALGOBATPAR(b), ALGOOPTBATPAR(s),
     834             :                                   ALGOOPTBATPAR(g), ALGOOPTBATPAR(e),
     835             :                                   ALGOOPTBATPAR(h),
     836             :                                   subsorted ? "true" : "false",
     837             :                                   ALGOOPTBATPAR(gn), ALGOOPTBATPAR(en),
     838             :                                   ALGOOPTBATPAR(hn), GDKusec() - t0);
     839         142 :                         return GDK_SUCCEED;
     840             :                 }
     841             :         }
     842       29176 :         assert(g == NULL || !BATtdense(g)); /* i.e. g->ttype == TYPE_oid */
     843       29176 :         cmp = ATOMcompare(bi.type);
     844       29176 :         gn = COLnew(hseqb, TYPE_oid, ci.ncand, TRANSIENT);
     845       29176 :         if (gn == NULL)
     846           0 :                 goto error;
     847       29176 :         ngrps = (oid *) Tloc(gn, 0);
     848       29176 :         maxgrps = BUN_NONE;
     849       29176 :         MT_rwlock_rdlock(&b->thashlock);
     850       29176 :         if (b->thash && b->thash != (Hash *) 1)
     851           2 :                 maxgrps = b->thash->nunique;
     852       29176 :         MT_rwlock_rdunlock(&b->thashlock);
     853       29176 :         if (maxgrps == BUN_NONE) {
     854       29174 :                 if (bi.unique_est != 0) {
     855        2749 :                         maxgrps = (BUN) bi.unique_est;
     856        2749 :                         if (maxgrps > ci.ncand)
     857             :                                 maxgrps = ci.ncand;
     858             :                 } else
     859       26425 :                         maxgrps = ci.ncand / 10;
     860             :         }
     861       29176 :         if (!is_oid_nil(maxgrp) && maxgrps < maxgrp)
     862        2811 :                 maxgrps += maxgrp;
     863       29176 :         if (e && maxgrps < BATcount(e))
     864          12 :                 maxgrps += BATcount(e);
     865       29176 :         if (h && maxgrps < BATcount(h))
     866           0 :                 maxgrps += BATcount(h);
     867       29176 :         if (maxgrps < GROUPBATINCR)
     868             :                 maxgrps = GROUPBATINCR;
     869             : 
     870       29176 :         if (bi.width <= 2) {
     871        5416 :                 maxgrps = (BUN) 1 << (8 * bi.width);
     872        5416 :                 if (bi.width == 1 && maxgrp < 256)
     873         593 :                         maxgrps *= maxgrp;
     874             :         }
     875       29176 :         if (extents) {
     876       22921 :                 en = COLnew(0, TYPE_oid, maxgrps, TRANSIENT);
     877       22920 :                 if (en == NULL)
     878           0 :                         goto error;
     879       22920 :                 exts = (oid *) Tloc(en, 0);
     880             :         }
     881       29175 :         if (histo) {
     882        6476 :                 hn = COLnew(0, TYPE_lng, maxgrps, TRANSIENT);
     883        6476 :                 if (hn == NULL)
     884           0 :                         goto error;
     885        6476 :                 cnts = (lng *) Tloc(hn, 0);
     886             :         }
     887       29175 :         ngrp = 0;
     888       29175 :         BATsetcount(gn, ci.ncand);
     889             : 
     890       29176 :         hseqb = b->hseqbase; /* abbreviation */
     891             : 
     892             :         /* figure out if we can use the storage type also for
     893             :          * comparing values */
     894       29176 :         t = ATOMbasetype(bi.type);
     895             :         /* for strings we can use the offset instead of the actual
     896             :          * string values if we know that the strings in the string
     897             :          * heap are unique */
     898       29176 :         if (t == TYPE_str && GDK_ELIMDOUBLES(bi.vh)) {
     899        4764 :                 switch (bi.width) {
     900             :                 case 1:
     901             :                         t = TYPE_bte;
     902             :                         break;
     903        1819 :                 case 2:
     904        1819 :                         t = TYPE_sht;
     905        1819 :                         break;
     906          66 :                 case 4:
     907          66 :                         t = TYPE_int;
     908          66 :                         break;
     909             : #if SIZEOF_VAR_T == 8
     910           0 :                 case 8:
     911           0 :                         t = TYPE_lng;
     912           0 :                         break;
     913             : #endif
     914             :                 default:
     915           0 :                         MT_UNREACHABLE();
     916             :                 }
     917             :         }
     918             : 
     919       29176 :         if (g == NULL && t == TYPE_bte) {
     920             :                 /* byte-sized values, use 256 entry array to keep
     921             :                  * track of doled out group ids; note that we can't
     922             :                  * possibly have more than 256 groups, so the group id
     923             :                  * fits in a uint8_t */
     924     9626900 :                 GRP_small_values(8, 8, w[p]);
     925       26650 :         } else if (t == TYPE_bte && maxgrp < 256) {
     926             :                 /* subgrouping byte-sized values with a limited number
     927             :                  * of groups, use 65536 entry array to keep track of
     928             :                  * doled out group ids; note that we can't possibly have
     929             :                  * more than 65536 goups, so the group id fits in a
     930             :                  * uint16_t */
     931    18332353 :                 GRP_small_values(16, 8, (uint16_t) (w[p] | (grps[p] << 8)));
     932       26159 :         } else if (g == NULL && t == TYPE_sht) {
     933             :                 /* short-sized values, use 65536 entry array to keep
     934             :                  * track of doled out group ids; note that we can't
     935             :                  * possibly have more than 65536 groups, so the group
     936             :                  * id fits in a uint16_t */
     937     5967869 :                 GRP_small_values(16, 16, w[p]);
     938       24921 :         } else if (subsorted ||
     939       19562 :             ((bi.sorted || bi.revsorted) &&
     940         241 :              (g == NULL || BATordered(g) || BATordered_rev(g)))) {
     941             :                 /* we only need to compare each entry with the previous */
     942       12338 :                 algomsg = "compare consecutive values -- ";
     943       12338 :                 switch (t) {
     944         185 :                 case TYPE_bte:
     945      448913 :                         GRP_compare_consecutive_values_tpe(bte);
     946             :                         break;
     947         417 :                 case TYPE_sht:
     948      367167 :                         GRP_compare_consecutive_values_tpe(sht);
     949             :                         break;
     950        9484 :                 case TYPE_int:
     951    82404890 :                         GRP_compare_consecutive_values_tpe(int);
     952             :                         break;
     953        1520 :                 case TYPE_lng:
     954     1001822 :                         GRP_compare_consecutive_values_tpe(lng);
     955             :                         break;
     956             : #ifdef HAVE_HGE
     957         645 :                 case TYPE_hge:
     958      417563 :                         GRP_compare_consecutive_values_tpe(hge);
     959             :                         break;
     960             : #endif
     961           9 :                 case TYPE_flt:
     962         108 :                         GRP_compare_consecutive_values_tpe(flt);
     963             :                         break;
     964          67 :                 case TYPE_dbl:
     965       36640 :                         GRP_compare_consecutive_values_tpe(dbl);
     966             :                         break;
     967          11 :                 default:
     968       29833 :                         GRP_compare_consecutive_values_any();
     969             :                         break;
     970             :                 }
     971             : 
     972       12332 :                 gn->tsorted = true;
     973       12332 :                 *groups = gn;
     974       12583 :         } else if (bi.sorted || bi.revsorted) {
     975         142 :                 BUN i, j;
     976         142 :                 BUN *pgrp;
     977             : 
     978         142 :                 assert(g);      /* if g == NULL or if there is a single */
     979         142 :                 assert(grps);   /* group, we used the code above */
     980             :                 /* for each value, we need to scan all previous equal
     981             :                  * values (a consecutive, possibly empty, range) to
     982             :                  * see if we can find one in the same old group
     983             :                  *
     984             :                  * we do this by maintaining for each old group the
     985             :                  * last time we saw that group, so if the last time we
     986             :                  * saw the old group of the current value is within
     987             :                  * this range, we can reuse the new group */
     988         142 :                 algomsg = "subscan old groups -- ";
     989             :                 /* determine how many old groups there are */
     990         142 :                 if (e) {
     991           0 :                         j = BATcount(e) + (BUN) e->hseqbase;
     992         142 :                 } else if (h) {
     993           0 :                         j = BATcount(h) + (BUN) h->hseqbase;
     994             :                 } else {
     995         142 :                         oid m = 0;
     996    23086373 :                         for (i = 0, j= BATcount(g); i < j; i++)
     997    23086231 :                                 m = MAX(m , grps[i]);
     998         142 :                         j = (BUN) m + 1;
     999             :                 }
    1000             :                 /* array to maintain last time we saw each old group */
    1001         142 :                 pgrp = GDKmalloc(sizeof(BUN) * j);
    1002         142 :                 if (pgrp == NULL)
    1003           0 :                         goto error;
    1004             :                 /* initialize to impossible position */
    1005         142 :                 memset(pgrp, ~0, sizeof(BUN) * j);
    1006             : 
    1007         142 :                 gn->tsorted = true; /* be optimistic */
    1008             : 
    1009         142 :                 switch (t) {
    1010           4 :                 case TYPE_bte:
    1011       10193 :                         GRP_subscan_old_groups_tpe(bte);
    1012             :                         break;
    1013          13 :                 case TYPE_sht:
    1014         133 :                         GRP_subscan_old_groups_tpe(sht);
    1015             :                         break;
    1016         114 :                 case TYPE_int:
    1017    23076909 :                         GRP_subscan_old_groups_tpe(int);
    1018             :                         break;
    1019           3 :                 case TYPE_lng:
    1020         104 :                         GRP_subscan_old_groups_tpe(lng);
    1021             :                         break;
    1022             : #ifdef HAVE_HGE
    1023           0 :                 case TYPE_hge:
    1024           0 :                         GRP_subscan_old_groups_tpe(hge);
    1025             :                         break;
    1026             : #endif
    1027           2 :                 case TYPE_flt:
    1028          26 :                         GRP_subscan_old_groups_tpe(flt);
    1029             :                         break;
    1030           6 :                 case TYPE_dbl:
    1031         372 :                         GRP_subscan_old_groups_tpe(dbl);
    1032             :                         break;
    1033           0 :                 default:
    1034           0 :                         GRP_subscan_old_groups_any();
    1035             :                         break;
    1036             :                 }
    1037             : 
    1038         142 :                 GDKfree(pgrp);
    1039       12441 :         } else if (g == NULL &&
    1040       10869 :                    (BATcheckhash(b) ||
    1041       10869 :                     ((!bi.transient ||
    1042       10869 :                       (b->batRole == PERSISTENT && GDKinmemory(0))) &&
    1043           0 :                      BAThash(b) == GDK_SUCCEED) ||
    1044             :                     (/* DISABLES CODE */ (0) &&
    1045             :                      (parent = VIEWtparent(b)) != 0 &&
    1046             : /* if enabled, need to fix/unfix parent bat */
    1047           0 :                      BATcheckhash(BBP_cache(parent))))) {
    1048             :                 /* we already have a hash table on b, or b is
    1049             :                  * persistent and we could create a hash table, or b
    1050             :                  * is a view on a bat that already has a hash table;
    1051             :                  * but don't do this if we're checking for subgroups
    1052             :                  * since we may have to go through long lists of
    1053             :                  * duplicates in the hash table to find an old
    1054             :                  * group */
    1055           0 :                 bool phash = false;
    1056           0 :                 algomsg = "existing hash -- ";
    1057           0 :                 MT_rwlock_rdlock(&b->thashlock);
    1058           0 :                 if (b->thash == NULL &&
    1059             :                     /* DISABLES CODE */ (0) &&
    1060             :                     (parent = VIEWtparent(b)) != 0) {
    1061             :                         /* b is a view on another bat (b2 for now).
    1062             :                          * calculate the bounds [lo, lo+BATcount(b))
    1063             :                          * in the parent that b uses */
    1064             : /* if enabled, need to fix/unfix parent bat */
    1065             :                         BAT *b2 = BBP_cache(parent);
    1066             :                         MT_rwlock_rdunlock(&b->thashlock);
    1067             :                         lo = b->tbaseoff - b2->tbaseoff;
    1068             :                         b = b2;
    1069             :                         bat_iterator_end(&bi);
    1070             :                         bi = bat_iterator(b);
    1071             :                         MT_rwlock_rdlock(&b->thashlock);
    1072             :                         algomsg = "existing parent hash -- ";
    1073             :                         phash = true;
    1074             :                 }
    1075           0 :                 hs = b->thash;
    1076           0 :                 if (hs == NULL) {
    1077           0 :                         MT_rwlock_rdunlock(&b->thashlock);
    1078           0 :                         goto lost_hash;
    1079             :                 }
    1080           0 :                 locked = true;
    1081           0 :                 gn->tsorted = true; /* be optimistic */
    1082             : 
    1083           0 :                 switch (t) {
    1084           0 :                 case TYPE_bte:
    1085           0 :                         GRP_use_existing_hash_table_tpe(bte);
    1086             :                         break;
    1087           0 :                 case TYPE_sht:
    1088           0 :                         GRP_use_existing_hash_table_tpe(sht);
    1089             :                         break;
    1090           0 :                 case TYPE_int:
    1091           0 :                         GRP_use_existing_hash_table_tpe(int);
    1092             :                         break;
    1093           0 :                 case TYPE_lng:
    1094           0 :                         GRP_use_existing_hash_table_tpe(lng);
    1095             :                         break;
    1096             : #ifdef HAVE_HGE
    1097           0 :                 case TYPE_hge:
    1098           0 :                         GRP_use_existing_hash_table_tpe(hge);
    1099             :                         break;
    1100             : #endif
    1101           0 :                 case TYPE_flt:
    1102           0 :                         GRP_use_existing_hash_table_tpe(flt);
    1103             :                         break;
    1104           0 :                 case TYPE_dbl:
    1105           0 :                         GRP_use_existing_hash_table_tpe(dbl);
    1106             :                         break;
    1107           0 :                 case TYPE_uuid:
    1108           0 :                         GRP_use_existing_hash_table_tpe(uuid);
    1109             :                         break;
    1110           0 :                 default:
    1111           0 :                         GRP_use_existing_hash_table_any();
    1112             :                         break;
    1113             :                 }
    1114           0 :                 MT_rwlock_rdunlock(&b->thashlock);
    1115           0 :                 locked = false;
    1116             :         } else {
    1117        1572 :                 bool gc;
    1118        1572 :                 const char *nme;
    1119        1572 :                 BUN prb;
    1120        1572 :                 int bits;
    1121        1572 :                 BUN nbucket;
    1122        1572 :                 oid grp;
    1123             : 
    1124        1572 :           lost_hash:
    1125        1572 :                 gc = g != NULL && (BATordered(g) || BATordered_rev(g));
    1126       12440 :                 bits = 0;
    1127       12440 :                 GDKclrerr();    /* not interested in BAThash errors */
    1128             : 
    1129             :                 /* not sorted, and no pre-existing hash table: we'll
    1130             :                  * build an incomplete hash table on the fly--also see
    1131             :                  * BATassertProps for similar code; we also exploit if
    1132             :                  * g is clustered */
    1133       12441 :                 algomsg = "new partial hash -- ";
    1134       12441 :                 nme = GDKinmemory(bi.h->farmid) ? ":memory:" : BBP_physical(b->batCacheid);
    1135       12440 :                 if (grps && !gc) {
    1136             :                         /* we manipulate the hash value after having
    1137             :                          * calculated it, and when doing that, we
    1138             :                          * assume the mask (i.e. nbucket-1) is a
    1139             :                          * power-of-two minus one, so make sure it
    1140             :                          * is */
    1141        1170 :                         nbucket = ci.ncand | ci.ncand >> 1;
    1142        1170 :                         nbucket |= nbucket >> 2;
    1143        1170 :                         nbucket |= nbucket >> 4;
    1144        1170 :                         nbucket |= nbucket >> 8;
    1145        1170 :                         nbucket |= nbucket >> 16;
    1146             : #if SIZEOF_BUN == 8
    1147        1170 :                         nbucket |= nbucket >> 32;
    1148             : #endif
    1149        1170 :                         nbucket++;
    1150             :                 } else {
    1151       11270 :                         nbucket = MAX(HASHmask(ci.ncand), 1 << 16);
    1152             :                 }
    1153       12440 :                 if (grps == NULL || is_oid_nil(maxgrp)
    1154             : #if SIZEOF_OID == SIZEOF_LNG
    1155        1572 :                     || maxgrp >= ((oid) 1 << (SIZEOF_LNG * 8 - 8))
    1156             : #endif
    1157             :                         ) {
    1158       10868 :                         switch (t) {
    1159             :                         case TYPE_bte:
    1160       12440 :                                 nbucket = 256;
    1161             :                                 break;
    1162           0 :                         case TYPE_sht:
    1163           0 :                                 nbucket = 65536;
    1164           0 :                                 break;
    1165             :                         default:
    1166             :                                 break;
    1167             :                         }
    1168             :                 }
    1169             :                 /* nbucket is a power of two, so ctz(nbucket)
    1170             :                  * tells us which power of two */
    1171       12440 :                 bits = 8 * SIZEOF_OID - ctz(nbucket);
    1172       12440 :                 if ((hs = GDKzalloc(sizeof(Hash))) == NULL ||
    1173       12441 :                     (hs->heaplink.farmid = BBPselectfarm(TRANSIENT, bi.type, hashheap)) < 0 ||
    1174       12440 :                     (hs->heapbckt.farmid = BBPselectfarm(TRANSIENT, bi.type, hashheap)) < 0) {
    1175           0 :                         GDKfree(hs);
    1176           0 :                         hs = NULL;
    1177           0 :                         GDKerror("cannot allocate hash table\n");
    1178           0 :                         goto error;
    1179             :                 }
    1180       12440 :                 hs->heapbckt.parentid = b->batCacheid;
    1181       12440 :                 hs->heaplink.parentid = b->batCacheid;
    1182       12440 :                 if (snprintf(hs->heaplink.filename, sizeof(hs->heaplink.filename), "%s.thshgrpl%x", nme, (unsigned) MT_getpid()) >= (int) sizeof(hs->heaplink.filename) ||
    1183       24881 :                     snprintf(hs->heapbckt.filename, sizeof(hs->heapbckt.filename), "%s.thshgrpb%x", nme, (unsigned) MT_getpid()) >= (int) sizeof(hs->heapbckt.filename) ||
    1184       12441 :                     HASHnew(hs, bi.type, BATcount(b), nbucket, BUN_NONE, false) != GDK_SUCCEED) {
    1185           0 :                         GDKfree(hs);
    1186           0 :                         hs = NULL;
    1187           0 :                         GDKerror("cannot allocate hash table\n");
    1188           0 :                         goto error;
    1189             :                 }
    1190       12439 :                 gn->tsorted = true; /* be optimistic */
    1191             : 
    1192       12439 :                 switch (t) {
    1193          24 :                 case TYPE_bte:
    1194          24 :                         if (grps && !is_oid_nil(maxgrp)
    1195             : #if SIZEOF_OID == SIZEOF_LNG
    1196          24 :                             && maxgrp < ((oid) 1 << (SIZEOF_LNG * 8 - 8))
    1197             : #endif
    1198             :                                 ) {
    1199          24 :                                 ulng v;
    1200          24 :                                 const bte *w = (bte *) bi.base;
    1201      257614 :                                 GRP_create_partial_hash_table_core(
    1202             :                                         (void) 0,
    1203             :                                         (v = ((ulng)grps[r]<<8)|(uint8_t)w[p], hash_lng(hs, &v)),
    1204             :                                         w[p] == w[hb] && grps[r] == grps[q],
    1205             :                                         (void) 0,
    1206             :                                         NOGRPTST);
    1207             :                         } else
    1208           0 :                                 GRP_create_partial_hash_table_tpe(bte);
    1209             :                         break;
    1210         513 :                 case TYPE_sht:
    1211         513 :                         if (grps && !is_oid_nil(maxgrp)
    1212             : #if SIZEOF_OID == SIZEOF_LNG
    1213         513 :                             && maxgrp < ((oid) 1 << (SIZEOF_LNG * 8 - 16))
    1214             : #endif
    1215             :                                 ) {
    1216         513 :                                 ulng v;
    1217         513 :                                 const sht *w = (sht *) bi.base;
    1218    32421737 :                                 GRP_create_partial_hash_table_core(
    1219             :                                         (void) 0,
    1220             :                                         (v = ((ulng)grps[r]<<16)|(uint16_t)w[p], hash_lng(hs, &v)),
    1221             :                                         w[p] == w[hb] && grps[r] == grps[q],
    1222             :                                         (void) 0,
    1223             :                                         NOGRPTST);
    1224             :                         } else
    1225           0 :                                 GRP_create_partial_hash_table_tpe(sht);
    1226             :                         break;
    1227       11313 :                 case TYPE_int:
    1228       11313 :                         if (grps && !is_oid_nil(maxgrp)
    1229             : #if SIZEOF_OID == SIZEOF_LNG
    1230         822 :                             && maxgrp < ((oid) 1 << (SIZEOF_LNG * 8 - 32))
    1231             : #endif
    1232             :                                 ) {
    1233         822 :                                 ulng v;
    1234         822 :                                 const int *w = (int *) bi.base;
    1235   120274492 :                                 GRP_create_partial_hash_table_core(
    1236             :                                         (void) 0,
    1237             :                                         (v = ((ulng)grps[r]<<32)|(unsigned int)w[p], hash_lng(hs, &v)),
    1238             :                                         w[p] == w[hb] && grps[r] == grps[q],
    1239             :                                         (void) 0,
    1240             :                                         NOGRPTST);
    1241             :                         } else
    1242    83678396 :                                 GRP_create_partial_hash_table_tpe(int);
    1243             :                         break;
    1244         197 :                 case TYPE_lng:
    1245             : #ifdef HAVE_HGE
    1246         197 :                         if (grps) {
    1247          16 :                                 uhge v;
    1248          16 :                                 const lng *w = (lng *) bi.base;
    1249     1999919 :                                 GRP_create_partial_hash_table_core(
    1250             :                                         (void) 0,
    1251             :                                         (v = ((uhge)grps[r]<<64)|(ulng)w[p], hash_hge(hs, &v)),
    1252             :                                         w[p] == w[hb] && grps[r] == grps[q],
    1253             :                                         (void) 0,
    1254             :                                         NOGRPTST);
    1255             :                         } else
    1256             : #endif
    1257      107024 :                                 GRP_create_partial_hash_table_tpe(lng);
    1258             :                         break;
    1259             : #ifdef HAVE_HGE
    1260          21 :                 case TYPE_hge:
    1261    57801810 :                         GRP_create_partial_hash_table_tpe(hge);
    1262             :                         break;
    1263             : #endif
    1264          15 :                 case TYPE_flt:
    1265         729 :                         GRP_create_partial_hash_table_tpe(flt);
    1266             :                         break;
    1267         115 :                 case TYPE_dbl:
    1268       36405 :                         GRP_create_partial_hash_table_tpe(dbl);
    1269             :                         break;
    1270           8 :                 case TYPE_uuid:
    1271          86 :                         GRP_create_partial_hash_table_tpe(uuid);
    1272             :                         break;
    1273         233 :                 default:
    1274    79471445 :                         GRP_create_partial_hash_table_any();
    1275             :                 }
    1276             : 
    1277       12440 :                 HEAPfree(&hs->heapbckt, true);
    1278       12441 :                 HEAPfree(&hs->heaplink, true);
    1279       12441 :                 GDKfree(hs);
    1280             :         }
    1281       29170 :         bat_iterator_end(&bi);
    1282       29174 :         if (extents) {
    1283       22920 :                 BATsetcount(en, (BUN) ngrp);
    1284       22921 :                 en->tkey = true;
    1285       22921 :                 en->tsorted = true;
    1286       22921 :                 en->trevsorted = ngrp == 1;
    1287       22921 :                 en->tnonil = true;
    1288       22921 :                 en->tnil = false;
    1289       22921 :                 *extents = virtualize(en);
    1290             :         }
    1291       29175 :         if (histo) {
    1292        6475 :                 BATsetcount(hn, (BUN) ngrp);
    1293        6476 :                 if (ngrp == ci.ncand || ngrp == 1) {
    1294        4039 :                         hn->tkey = ngrp == 1;
    1295        4039 :                         hn->tsorted = true;
    1296        4039 :                         hn->trevsorted = true;
    1297             :                 } else {
    1298        2437 :                         hn->tkey = false;
    1299        2437 :                         hn->tsorted = false;
    1300        2437 :                         hn->trevsorted = false;
    1301             :                 }
    1302        6476 :                 hn->tnonil = true;
    1303        6476 :                 hn->tnil = false;
    1304        6476 :                 *histo = hn;
    1305             :         }
    1306       29176 :         gn->tkey = ngrp == BATcount(gn);
    1307       29176 :         gn->trevsorted = ngrp == 1 || BATcount(gn) <= 1;
    1308       29176 :         gn->tnonil = true;
    1309       29176 :         gn->tnil = false;
    1310       29176 :         gn->tmaxpos = maxgrppos;
    1311       29176 :         *groups = gn;
    1312       29176 :         TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",s=" ALGOOPTBATFMT
    1313             :                   ",g=" ALGOOPTBATFMT ",e=" ALGOOPTBATFMT
    1314             :                   ",h=" ALGOOPTBATFMT ",subsorted=%s -> groups="
    1315             :                   ALGOOPTBATFMT ",extents=" ALGOOPTBATFMT
    1316             :                   ",histo=" ALGOOPTBATFMT " (%s" LLFMT " usec)\n",
    1317             :                   ALGOBATPAR(b), ALGOOPTBATPAR(s),
    1318             :                   ALGOOPTBATPAR(g), ALGOOPTBATPAR(e),
    1319             :                   ALGOOPTBATPAR(h),
    1320             :                   subsorted ? "true" : "false",
    1321             :                   ALGOOPTBATPAR(gn), ALGOOPTBATPAR(en),
    1322             :                   ALGOOPTBATPAR(hn), algomsg, GDKusec() - t0);
    1323             :         return GDK_SUCCEED;
    1324           0 :   error:
    1325           0 :         bat_iterator_end(&bi);
    1326           0 :         if (hs != NULL && hs != b->thash) {
    1327           0 :                 HEAPfree(&hs->heaplink, true);
    1328           0 :                 HEAPfree(&hs->heapbckt, true);
    1329           0 :                 GDKfree(hs);
    1330             :         }
    1331           0 :         if (locked)
    1332           0 :                 MT_rwlock_rdunlock(&b->thashlock);
    1333           0 :         BBPreclaim(gn);
    1334           0 :         BBPreclaim(en);
    1335           0 :         BBPreclaim(hn);
    1336             :         return GDK_FAIL;
    1337             : }
    1338             : 
    1339             : gdk_return
    1340       56056 : BATgroup(BAT **groups, BAT **extents, BAT **histo,
    1341             :          BAT *b, BAT *s, BAT *g, BAT *e, BAT *h)
    1342             : {
    1343       56056 :         return BATgroup_internal(groups, extents, histo, b, s, g, e, h, false);
    1344             : }

Generated by: LCOV version 1.14