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_analytic.h"
16 : #include "gdk_calc_private.h"
17 :
18 : BAT *
19 221 : GDKinitialize_segment_tree(void)
20 : {
21 : /* The tree is allocated using raw bytes, so use a GDK type of size 1 */
22 221 : BAT *st = COLnew(0, TYPE_bte, 0, TRANSIENT);
23 :
24 221 : if (!st)
25 : return NULL;
26 221 : assert(st->tshift == 0);
27 221 : BATsetcount(st, 0);
28 221 : st->tsorted = st->trevsorted = st->tkey = st->tnonil = st->tnil = false;
29 221 : st->tnosorted = st->tnorevsorted = 0;
30 221 : return st;
31 : }
32 :
33 : gdk_return
34 41538 : GDKrebuild_segment_tree(oid ncount, oid data_size, BAT *st, void **segment_tree, oid **levels_offset, oid *nlevels)
35 : {
36 41538 : oid total_size, next_tree_size = ncount, counter = ncount, next_levels = 1; /* there will be at least one level */
37 :
38 41538 : assert(ncount > 0);
39 71772 : do { /* compute the next number of levels */
40 71772 : counter = (counter+(SEGMENT_TREE_FANOUT-1)) / SEGMENT_TREE_FANOUT;
41 71772 : next_tree_size += counter;
42 71772 : next_levels++;
43 71772 : } while (counter > 1);
44 :
45 41538 : *nlevels = next_levels; /* set the logical size of levels before the physical one */
46 41538 : next_tree_size *= data_size;
47 : /* round up to multiple of sizeof(oid) */
48 41538 : next_tree_size = ((next_tree_size + SIZEOF_OID - 1) / SIZEOF_OID) * SIZEOF_OID;
49 41538 : total_size = next_tree_size + next_levels * sizeof(oid);
50 :
51 41538 : if (total_size > BATcount(st)) {
52 222 : total_size = (((total_size) + 1023) & ~1023); /* align to a multiple of 1024 bytes */
53 222 : if (BATextend(st, total_size) != GDK_SUCCEED)
54 : return GDK_FAIL;
55 222 : BATsetcount(st, total_size);
56 222 : *segment_tree = (void*)Tloc(st, 0);
57 222 : *levels_offset = (oid*)((bte*)Tloc(st, 0) + next_tree_size); /* levels offset will be next to the segment tree */
58 : } else {
59 41316 : *levels_offset = (oid*)(*(bte**)segment_tree + next_tree_size); /* no reallocation, just update location of levels offset */
60 : }
61 : return GDK_SUCCEED;
62 : }
63 :
64 : #define NTILE_CALC(TPE, NEXT_VALUE, LNG_HGE, UPCAST, VALIDATION) \
65 : do { \
66 : UPCAST j = 0, ncnt = (UPCAST) (i - k); \
67 : for (; k < i; k++, j++) { \
68 : TPE val = NEXT_VALUE; \
69 : if (is_##TPE##_nil(val)) { \
70 : has_nils = true; \
71 : rb[k] = TPE##_nil; \
72 : } else { \
73 : UPCAST nval = (UPCAST) (LNG_HGE); \
74 : VALIDATION /* validation must come after null check */ \
75 : if (nval >= ncnt) { \
76 : rb[k] = (TPE)(j + 1); \
77 : } else { \
78 : UPCAST bsize = ncnt / nval; \
79 : UPCAST top = ncnt - nval * bsize; \
80 : UPCAST small = top * (bsize + 1); \
81 : if ((UPCAST) j < small) \
82 : rb[k] = (TPE)(1 + j / (bsize + 1)); \
83 : else \
84 : rb[k] = (TPE)(1 + top + (j - small) / bsize); \
85 : } \
86 : } \
87 : } \
88 : } while (0)
89 :
90 : #define ANALYTICAL_NTILE(IMP, TPE, NEXT_VALUE, LNG_HGE, UPCAST, VALIDATION) \
91 : do { \
92 : TPE *rb = (TPE*)Tloc(r, 0); \
93 : if (p) { \
94 : while (i < cnt) { \
95 : if (np[i]) { \
96 : ntile##IMP##TPE: \
97 : NTILE_CALC(TPE, NEXT_VALUE, LNG_HGE, UPCAST, VALIDATION); \
98 : } \
99 : if (!last) \
100 : i++; \
101 : } \
102 : } \
103 : if (!last) { \
104 : last = true; \
105 : i = cnt; \
106 : goto ntile##IMP##TPE; \
107 : } \
108 : } while (0)
109 :
110 : #define ANALYTICAL_NTILE_SINGLE_IMP(TPE, LNG_HGE, UPCAST) \
111 : do { \
112 : TPE ntl = *(TPE*) ntile; \
113 : if (!is_##TPE##_nil(ntl) && ntl <= 0) goto invalidntile; \
114 : ANALYTICAL_NTILE(SINGLE, TPE, ntl, LNG_HGE, UPCAST, ;); \
115 : } while (0)
116 :
117 : #define ANALYTICAL_NTILE_MULTI_IMP(TPE, LNG_HGE, UPCAST) \
118 : do { \
119 : const TPE *restrict nn = (TPE*)ni.base; \
120 : ANALYTICAL_NTILE(MULTI, TPE, nn[k], LNG_HGE, UPCAST, if (val <= 0) goto invalidntile;); \
121 : } while (0)
122 :
123 : gdk_return
124 62 : GDKanalyticalntile(BAT *r, BAT *b, BAT *p, BAT *n, int tpe, const void *restrict ntile)
125 : {
126 62 : BATiter bi = bat_iterator(b);
127 62 : BATiter pi = bat_iterator(p);
128 62 : BATiter ni = bat_iterator(n);
129 62 : lng i = 0, k = 0, cnt = (lng) BATcount(b);
130 62 : const bit *restrict np = pi.base;
131 62 : bool has_nils = false, last = false;
132 :
133 62 : assert((n && !ntile) || (!n && ntile));
134 :
135 62 : if (ntile) {
136 35 : switch (tpe) {
137 33 : case TYPE_bte:
138 674 : ANALYTICAL_NTILE_SINGLE_IMP(bte, val, BUN);
139 : break;
140 0 : case TYPE_sht:
141 0 : ANALYTICAL_NTILE_SINGLE_IMP(sht, val, BUN);
142 : break;
143 0 : case TYPE_int:
144 0 : ANALYTICAL_NTILE_SINGLE_IMP(int, val, BUN);
145 : break;
146 1 : case TYPE_lng:
147 : #if SIZEOF_OID == SIZEOF_INT
148 : ANALYTICAL_NTILE_SINGLE_IMP(lng, val, lng);
149 : #else
150 162 : ANALYTICAL_NTILE_SINGLE_IMP(lng, val, BUN);
151 : #endif
152 : break;
153 : #ifdef HAVE_HGE
154 1 : case TYPE_hge:
155 : #if SIZEOF_OID == SIZEOF_INT
156 : ANALYTICAL_NTILE_SINGLE_IMP(hge, (val > (hge) GDK_int_max) ? GDK_int_max : (lng) val, lng);
157 : #else
158 4 : ANALYTICAL_NTILE_SINGLE_IMP(hge, (val > (hge) GDK_lng_max) ? GDK_lng_max : (lng) val, BUN);
159 : #endif
160 : break;
161 : #endif
162 0 : default:
163 0 : goto nosupport;
164 : }
165 : } else {
166 27 : switch (tpe) {
167 1 : case TYPE_bte:
168 12 : ANALYTICAL_NTILE_MULTI_IMP(bte, val, BUN);
169 : break;
170 0 : case TYPE_sht:
171 0 : ANALYTICAL_NTILE_MULTI_IMP(sht, val, BUN);
172 : break;
173 26 : case TYPE_int:
174 420 : ANALYTICAL_NTILE_MULTI_IMP(int, val, BUN);
175 : break;
176 0 : case TYPE_lng:
177 : #if SIZEOF_OID == SIZEOF_INT
178 : ANALYTICAL_NTILE_MULTI_IMP(lng, val, lng);
179 : #else
180 0 : ANALYTICAL_NTILE_MULTI_IMP(lng, val, BUN);
181 : #endif
182 : break;
183 : #ifdef HAVE_HGE
184 0 : case TYPE_hge:
185 : #if SIZEOF_OID == SIZEOF_INT
186 : ANALYTICAL_NTILE_MULTI_IMP(hge, val > (hge) GDK_int_max ? GDK_int_max : (lng) val, lng);
187 : #else
188 0 : ANALYTICAL_NTILE_MULTI_IMP(hge, val > (hge) GDK_lng_max ? GDK_lng_max : (lng) val, BUN);
189 : #endif
190 : break;
191 : #endif
192 0 : default:
193 0 : goto nosupport;
194 : }
195 : }
196 62 : bat_iterator_end(&bi);
197 62 : bat_iterator_end(&pi);
198 62 : bat_iterator_end(&ni);
199 62 : BATsetcount(r, BATcount(b));
200 62 : r->tnonil = !has_nils;
201 62 : r->tnil = has_nils;
202 62 : return GDK_SUCCEED;
203 0 : nosupport:
204 0 : bat_iterator_end(&bi);
205 0 : bat_iterator_end(&pi);
206 0 : bat_iterator_end(&ni);
207 0 : GDKerror("42000!type %s not supported for the ntile type.\n", ATOMname(tpe));
208 0 : return GDK_FAIL;
209 0 : invalidntile:
210 0 : bat_iterator_end(&bi);
211 0 : bat_iterator_end(&pi);
212 0 : bat_iterator_end(&ni);
213 0 : GDKerror("42000!ntile must be greater than zero.\n");
214 0 : return GDK_FAIL;
215 : }
216 :
217 : #define ANALYTICAL_FIRST_FIXED(TPE) \
218 : do { \
219 : const TPE *bp = (TPE*)bi.base; \
220 : TPE *rb = (TPE*)Tloc(r, 0); \
221 : for (; k < cnt; k++) { \
222 : const TPE *bs = bp + start[k], *be = bp + end[k]; \
223 : TPE curval = (be > bs) ? *bs : TPE##_nil; \
224 : rb[k] = curval; \
225 : has_nils |= is_##TPE##_nil(curval); \
226 : } \
227 : } while (0)
228 :
229 : gdk_return
230 36 : GDKanalyticalfirst(BAT *r, BAT *b, BAT *s, BAT *e, int tpe)
231 : {
232 36 : BATiter bi = bat_iterator(b);
233 36 : BATiter si = bat_iterator(s);
234 36 : BATiter ei = bat_iterator(e);
235 36 : bool has_nils = false;
236 36 : oid k = 0, cnt = BATcount(b);
237 36 : const oid *restrict start = si.base, *restrict end = ei.base;
238 36 : const void *nil = ATOMnilptr(tpe);
239 36 : int (*atomcmp)(const void *, const void *) = ATOMcompare(tpe);
240 :
241 72 : switch (ATOMbasetype(tpe)) {
242 1 : case TYPE_bte:
243 11 : ANALYTICAL_FIRST_FIXED(bte);
244 : break;
245 0 : case TYPE_sht:
246 0 : ANALYTICAL_FIRST_FIXED(sht);
247 : break;
248 25 : case TYPE_int:
249 845627 : ANALYTICAL_FIRST_FIXED(int);
250 : break;
251 1 : case TYPE_lng:
252 12 : ANALYTICAL_FIRST_FIXED(lng);
253 : break;
254 : #ifdef HAVE_HGE
255 0 : case TYPE_hge:
256 0 : ANALYTICAL_FIRST_FIXED(hge);
257 : break;
258 : #endif
259 0 : case TYPE_flt:
260 0 : ANALYTICAL_FIRST_FIXED(flt);
261 : break;
262 2 : case TYPE_dbl:
263 14 : ANALYTICAL_FIRST_FIXED(dbl);
264 : break;
265 7 : default:{
266 7 : if (ATOMvarsized(tpe)) {
267 245752 : for (; k < cnt; k++) {
268 245745 : const void *curval = (end[k] > start[k]) ? BUNtvar(bi, start[k]) : nil;
269 245745 : if (tfastins_nocheckVAR(r, k, curval) != GDK_SUCCEED) {
270 0 : bat_iterator_end(&bi);
271 0 : bat_iterator_end(&si);
272 0 : bat_iterator_end(&ei);
273 0 : return GDK_FAIL;
274 : }
275 245745 : has_nils |= atomcmp(curval, nil) == 0;
276 : }
277 : } else {
278 0 : uint16_t width = r->twidth;
279 0 : uint8_t *restrict rcast = (uint8_t *) Tloc(r, 0);
280 0 : for (; k < cnt; k++) {
281 0 : const void *curval = (end[k] > start[k]) ? BUNtloc(bi, start[k]) : nil;
282 0 : memcpy(rcast, curval, width);
283 0 : rcast += width;
284 0 : has_nils |= atomcmp(curval, nil) == 0;
285 : }
286 : }
287 : }
288 : }
289 36 : bat_iterator_end(&bi);
290 36 : bat_iterator_end(&si);
291 36 : bat_iterator_end(&ei);
292 :
293 36 : BATsetcount(r, cnt);
294 36 : r->tnonil = !has_nils;
295 36 : r->tnil = has_nils;
296 36 : return GDK_SUCCEED;
297 : }
298 :
299 : #define ANALYTICAL_LAST_FIXED(TPE) \
300 : do { \
301 : const TPE *bp = (TPE*)bi.base; \
302 : TPE *rb = (TPE*)Tloc(r, 0); \
303 : for (; k < cnt; k++) { \
304 : const TPE *bs = bp + start[k], *be = bp + end[k]; \
305 : TPE curval = (be > bs) ? *(be - 1) : TPE##_nil; \
306 : rb[k] = curval; \
307 : has_nils |= is_##TPE##_nil(curval); \
308 : } \
309 : } while (0)
310 :
311 : gdk_return
312 31 : GDKanalyticallast(BAT *r, BAT *b, BAT *s, BAT *e, int tpe)
313 : {
314 31 : BATiter bi = bat_iterator(b);
315 31 : BATiter si = bat_iterator(s);
316 31 : BATiter ei = bat_iterator(e);
317 31 : bool has_nils = false;
318 31 : oid k = 0, cnt = BATcount(b);
319 31 : const oid *restrict start = si.base, *restrict end = ei.base;
320 31 : const void *nil = ATOMnilptr(tpe);
321 31 : int (*atomcmp)(const void *, const void *) = ATOMcompare(tpe);
322 :
323 62 : switch (ATOMbasetype(tpe)) {
324 1 : case TYPE_bte:
325 11 : ANALYTICAL_LAST_FIXED(bte);
326 : break;
327 0 : case TYPE_sht:
328 0 : ANALYTICAL_LAST_FIXED(sht);
329 : break;
330 22 : case TYPE_int:
331 339 : ANALYTICAL_LAST_FIXED(int);
332 : break;
333 1 : case TYPE_lng:
334 12 : ANALYTICAL_LAST_FIXED(lng);
335 : break;
336 : #ifdef HAVE_HGE
337 0 : case TYPE_hge:
338 0 : ANALYTICAL_LAST_FIXED(hge);
339 : break;
340 : #endif
341 0 : case TYPE_flt:
342 0 : ANALYTICAL_LAST_FIXED(flt);
343 : break;
344 2 : case TYPE_dbl:
345 14 : ANALYTICAL_LAST_FIXED(dbl);
346 : break;
347 5 : default:{
348 5 : if (ATOMvarsized(tpe)) {
349 50 : for (; k < cnt; k++) {
350 45 : const void *curval = (end[k] > start[k]) ? BUNtvar(bi, end[k] - 1) : nil;
351 45 : if (tfastins_nocheckVAR(r, k, curval) != GDK_SUCCEED) {
352 0 : bat_iterator_end(&bi);
353 0 : bat_iterator_end(&si);
354 0 : bat_iterator_end(&ei);
355 0 : return GDK_FAIL;
356 : }
357 45 : has_nils |= atomcmp(curval, nil) == 0;
358 : }
359 : } else {
360 0 : uint16_t width = r->twidth;
361 0 : uint8_t *restrict rcast = (uint8_t *) Tloc(r, 0);
362 0 : for (; k < cnt; k++) {
363 0 : const void *curval = (end[k] > start[k]) ? BUNtloc(bi, end[k] - 1) : nil;
364 0 : memcpy(rcast, curval, width);
365 0 : rcast += width;
366 0 : has_nils |= atomcmp(curval, nil) == 0;
367 : }
368 : }
369 : }
370 : }
371 31 : bat_iterator_end(&bi);
372 31 : bat_iterator_end(&si);
373 31 : bat_iterator_end(&ei);
374 31 : BATsetcount(r, cnt);
375 31 : r->tnonil = !has_nils;
376 31 : r->tnil = has_nils;
377 31 : return GDK_SUCCEED;
378 : }
379 :
380 : #define ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(TPE) \
381 : do { \
382 : const TPE *bp = (TPE*)bi.base; \
383 : TPE *rb = (TPE*)Tloc(r, 0); \
384 : if (is_lng_nil(nth)) { \
385 : has_nils = true; \
386 : for (; k < cnt; k++) \
387 : rb[k] = TPE##_nil; \
388 : } else { \
389 : nth--; \
390 : for (; k < cnt; k++) { \
391 : const TPE *bs = bp + start[k]; \
392 : const TPE *be = bp + end[k]; \
393 : TPE curval = (be > bs && nth < (lng)(end[k] - start[k])) ? *(bs + nth) : TPE##_nil; \
394 : rb[k] = curval; \
395 : has_nils |= is_##TPE##_nil(curval); \
396 : } \
397 : } \
398 : } while (0)
399 :
400 : #define ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(TPE) \
401 : do { \
402 : const TPE *bp = (TPE*)bi.base; \
403 : TPE curval, *rb = (TPE*)Tloc(r, 0); \
404 : for (; k < cnt; k++) { \
405 : lng lnth = tp[k]; \
406 : const TPE *bs = bp + start[k]; \
407 : const TPE *be = bp + end[k]; \
408 : if (!is_lng_nil(lnth) && lnth <= 0) goto invalidnth; \
409 : if (is_lng_nil(lnth) || be <= bs || lnth - 1 > (lng)(end[k] - start[k])) { \
410 : curval = TPE##_nil; \
411 : has_nils = true; \
412 : } else { \
413 : curval = *(bs + lnth - 1); \
414 : has_nils |= is_##TPE##_nil(curval); \
415 : } \
416 : rb[k] = curval; \
417 : } \
418 : } while (0)
419 :
420 : gdk_return
421 40 : GDKanalyticalnthvalue(BAT *r, BAT *b, BAT *s, BAT *e, BAT *t, lng *pnth, int tpe)
422 : {
423 40 : BATiter bi = bat_iterator(b);
424 40 : BATiter si = bat_iterator(s);
425 40 : BATiter ei = bat_iterator(e);
426 40 : BATiter ti = bat_iterator(t);
427 40 : bool has_nils = false;
428 40 : oid k = 0, cnt = bi.count;
429 40 : const oid *restrict start = si.base, *restrict end = ei.base;
430 40 : lng nth = pnth ? *pnth : 0;
431 40 : const lng *restrict tp = ti.base;
432 40 : const void *nil = ATOMnilptr(tpe);
433 40 : int (*atomcmp)(const void *, const void *) = ATOMcompare(tpe);
434 :
435 40 : if (t && t->ttype != TYPE_lng)
436 0 : goto nosupport;
437 :
438 40 : if (t) {
439 10 : switch (ATOMbasetype(tpe)) {
440 3 : case TYPE_bte:
441 33 : ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(bte);
442 : break;
443 0 : case TYPE_sht:
444 0 : ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(sht);
445 : break;
446 2 : case TYPE_int:
447 22 : ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(int);
448 : break;
449 0 : case TYPE_lng:
450 0 : ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(lng);
451 : break;
452 : #ifdef HAVE_HGE
453 0 : case TYPE_hge:
454 0 : ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(hge);
455 : break;
456 : #endif
457 0 : case TYPE_flt:
458 0 : ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(flt);
459 : break;
460 0 : case TYPE_dbl:
461 0 : ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(dbl);
462 : break;
463 0 : default:{
464 0 : const void *curval = nil;
465 0 : if (ATOMvarsized(tpe)) {
466 0 : for (; k < cnt; k++) {
467 0 : lng lnth = tp[k];
468 0 : if (!is_lng_nil(nth) && nth <= 0) goto invalidnth;
469 0 : if (is_lng_nil(lnth) || end[k] <= start[k] || lnth - 1 > (lng)(end[k] - start[k])) {
470 : curval = (void *) nil;
471 : has_nils = true;
472 : } else {
473 0 : curval = BUNtvar(bi, start[k] + (oid)(lnth - 1));
474 0 : has_nils |= atomcmp(curval, nil) == 0;
475 : }
476 0 : if (tfastins_nocheckVAR(r, k, curval) != GDK_SUCCEED) {
477 0 : bat_iterator_end(&bi);
478 0 : bat_iterator_end(&si);
479 0 : bat_iterator_end(&ei);
480 0 : bat_iterator_end(&ti);
481 0 : return GDK_FAIL;
482 : }
483 : }
484 : } else {
485 0 : uint8_t *restrict rcast = (uint8_t *) Tloc(r, 0);
486 0 : uint16_t width = r->twidth;
487 0 : for (; k < cnt; k++) {
488 0 : lng lnth = tp[k];
489 0 : if (!is_lng_nil(nth) && nth <= 0) goto invalidnth;
490 0 : if (is_lng_nil(lnth) || end[k] <= start[k] || lnth - 1 > (lng)(end[k] - start[k])) {
491 : curval = (void *) nil;
492 : has_nils = true;
493 : } else {
494 0 : curval = BUNtloc(bi, start[k] + (oid)(lnth - 1));
495 0 : has_nils |= atomcmp(curval, nil) == 0;
496 : }
497 0 : memcpy(rcast, curval, width);
498 0 : rcast += width;
499 : }
500 : }
501 : }
502 : }
503 : } else {
504 35 : if (!is_lng_nil(nth) && nth <= 0) {
505 0 : goto invalidnth;
506 : }
507 70 : switch (ATOMbasetype(tpe)) {
508 1 : case TYPE_bte:
509 11 : ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(bte);
510 : break;
511 0 : case TYPE_sht:
512 0 : ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(sht);
513 : break;
514 23 : case TYPE_int:
515 243 : ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(int);
516 : break;
517 0 : case TYPE_lng:
518 0 : ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(lng);
519 : break;
520 : #ifdef HAVE_HGE
521 0 : case TYPE_hge:
522 0 : ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(hge);
523 : break;
524 : #endif
525 0 : case TYPE_flt:
526 0 : ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(flt);
527 : break;
528 0 : case TYPE_dbl:
529 0 : ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(dbl);
530 : break;
531 11 : default:{
532 11 : if (ATOMvarsized(tpe)) {
533 11 : if (is_lng_nil(nth)) {
534 0 : has_nils = true;
535 0 : for (; k < cnt; k++)
536 0 : if (tfastins_nocheckVAR(r, k, nil) != GDK_SUCCEED) {
537 0 : bat_iterator_end(&bi);
538 0 : bat_iterator_end(&si);
539 0 : bat_iterator_end(&ei);
540 0 : bat_iterator_end(&ti);
541 0 : return GDK_FAIL;
542 : }
543 : } else {
544 11 : nth--;
545 112 : for (; k < cnt; k++) {
546 101 : const void *curval = (end[k] > start[k] && nth < (lng)(end[k] - start[k])) ? BUNtvar(bi, start[k] + (oid) nth) : nil;
547 101 : if (tfastins_nocheckVAR(r, k, curval) != GDK_SUCCEED) {
548 0 : bat_iterator_end(&bi);
549 0 : bat_iterator_end(&si);
550 0 : bat_iterator_end(&ei);
551 0 : bat_iterator_end(&ti);
552 0 : return GDK_FAIL;
553 : }
554 101 : has_nils |= atomcmp(curval, nil) == 0;
555 : }
556 : }
557 : } else {
558 0 : uint16_t width = r->twidth;
559 0 : uint8_t *restrict rcast = (uint8_t *) Tloc(r, 0);
560 0 : if (is_lng_nil(nth)) {
561 0 : has_nils = true;
562 0 : for (; k < cnt; k++) {
563 0 : memcpy(rcast, nil, width);
564 0 : rcast += width;
565 : }
566 : } else {
567 0 : nth--;
568 0 : for (; k < cnt; k++) {
569 0 : const void *curval = (end[k] > start[k] && nth < (lng)(end[k] - start[k])) ? BUNtloc(bi, start[k] + (oid) nth) : nil;
570 0 : memcpy(rcast, curval, width);
571 0 : rcast += width;
572 0 : has_nils |= atomcmp(curval, nil) == 0;
573 : }
574 : }
575 : }
576 : }
577 : }
578 : }
579 40 : bat_iterator_end(&bi);
580 40 : bat_iterator_end(&si);
581 40 : bat_iterator_end(&ei);
582 40 : bat_iterator_end(&ti);
583 :
584 40 : BATsetcount(r, cnt);
585 40 : r->tnonil = !has_nils;
586 40 : r->tnil = has_nils;
587 40 : return GDK_SUCCEED;
588 0 : nosupport:
589 0 : bat_iterator_end(&bi);
590 0 : bat_iterator_end(&si);
591 0 : bat_iterator_end(&ei);
592 0 : bat_iterator_end(&ti);
593 0 : GDKerror("42000!type %s not supported for the nth_value.\n", ATOMname(t->ttype));
594 0 : return GDK_FAIL;
595 0 : invalidnth:
596 0 : bat_iterator_end(&bi);
597 0 : bat_iterator_end(&si);
598 0 : bat_iterator_end(&ei);
599 0 : bat_iterator_end(&ti);
600 0 : GDKerror("42000!nth_value must be greater than zero.\n");
601 0 : return GDK_FAIL;
602 : }
603 :
604 : #define ANALYTICAL_LAG_CALC(TPE) \
605 : do { \
606 : for (i = 0; i < lag && rb < rp; i++, rb++) \
607 : *rb = def; \
608 : has_nils |= (lag > 0 && is_##TPE##_nil(def)); \
609 : for (; rb < rp; rb++, bp++) { \
610 : next = *bp; \
611 : *rb = next; \
612 : has_nils |= is_##TPE##_nil(next); \
613 : } \
614 : } while (0)
615 :
616 : #define ANALYTICAL_LAG_IMP(TPE) \
617 : do { \
618 : TPE *rp, *rb, *rend, \
619 : def = *((TPE *) default_value), next; \
620 : const TPE *bp, *nbp; \
621 : bp = (TPE*)bi.base; \
622 : rb = rp = (TPE*)Tloc(r, 0); \
623 : rend = rb + cnt; \
624 : if (lag == BUN_NONE) { \
625 : has_nils = true; \
626 : for (; rb < rend; rb++) \
627 : *rb = TPE##_nil; \
628 : } else if (p) { \
629 : pnp = np = (bit*)pi.base; \
630 : end = np + cnt; \
631 : for (; np < end; np++) { \
632 : if (*np) { \
633 : ncnt = (np - pnp); \
634 : rp += ncnt; \
635 : nbp = bp + ncnt; \
636 : ANALYTICAL_LAG_CALC(TPE); \
637 : bp = nbp; \
638 : pnp = np; \
639 : } \
640 : } \
641 : rp += (np - pnp); \
642 : ANALYTICAL_LAG_CALC(TPE); \
643 : } else { \
644 : rp += cnt; \
645 : ANALYTICAL_LAG_CALC(TPE); \
646 : } \
647 : } while (0)
648 :
649 : #define ANALYTICAL_LAG_OTHERS \
650 : do { \
651 : for (i = 0; i < lag && k < j; i++, k++) { \
652 : if (BUNappend(r, default_value, false) != GDK_SUCCEED) { \
653 : bat_iterator_end(&bi); \
654 : bat_iterator_end(&pi); \
655 : return GDK_FAIL; \
656 : } \
657 : } \
658 : has_nils |= (lag > 0 && atomcmp(default_value, nil) == 0); \
659 : for (l = k - lag; k < j; k++, l++) { \
660 : curval = BUNtail(bi, l); \
661 : if (BUNappend(r, curval, false) != GDK_SUCCEED) { \
662 : bat_iterator_end(&bi); \
663 : bat_iterator_end(&pi); \
664 : return GDK_FAIL; \
665 : } \
666 : has_nils |= atomcmp(curval, nil) == 0; \
667 : } \
668 : } while (0)
669 :
670 : gdk_return
671 30 : GDKanalyticallag(BAT *r, BAT *b, BAT *p, BUN lag, const void *restrict default_value, int tpe)
672 : {
673 30 : BATiter bi = bat_iterator(b);
674 30 : BATiter pi = bat_iterator(p);
675 30 : int (*atomcmp) (const void *, const void *);
676 30 : const void *restrict nil;
677 30 : BUN i = 0, j = 0, k = 0, l = 0, ncnt, cnt = BATcount(b);
678 30 : bit *np, *pnp, *end;
679 30 : bool has_nils = false;
680 :
681 30 : assert(default_value);
682 :
683 60 : switch (ATOMbasetype(tpe)) {
684 3 : case TYPE_bte:
685 33 : ANALYTICAL_LAG_IMP(bte);
686 : break;
687 0 : case TYPE_sht:
688 0 : ANALYTICAL_LAG_IMP(sht);
689 : break;
690 21 : case TYPE_int:
691 337 : ANALYTICAL_LAG_IMP(int);
692 : break;
693 1 : case TYPE_lng:
694 23 : ANALYTICAL_LAG_IMP(lng);
695 : break;
696 : #ifdef HAVE_HGE
697 0 : case TYPE_hge:
698 0 : ANALYTICAL_LAG_IMP(hge);
699 : break;
700 : #endif
701 0 : case TYPE_flt:
702 0 : ANALYTICAL_LAG_IMP(flt);
703 : break;
704 0 : case TYPE_dbl:
705 0 : ANALYTICAL_LAG_IMP(dbl);
706 : break;
707 5 : default:{
708 5 : const void *restrict curval;
709 5 : nil = ATOMnilptr(tpe);
710 5 : atomcmp = ATOMcompare(tpe);
711 5 : if (lag == BUN_NONE) {
712 0 : has_nils = true;
713 0 : for (j = 0; j < cnt; j++) {
714 0 : if (BUNappend(r, nil, false) != GDK_SUCCEED) {
715 0 : bat_iterator_end(&bi);
716 0 : bat_iterator_end(&pi);
717 0 : return GDK_FAIL;
718 : }
719 : }
720 5 : } else if (p) {
721 3 : pnp = np = (bit *) pi.base;
722 3 : end = np + cnt;
723 30 : for (; np < end; np++) {
724 27 : if (*np) {
725 9 : j += (np - pnp);
726 31 : ANALYTICAL_LAG_OTHERS;
727 : pnp = np;
728 : }
729 : }
730 3 : j += (np - pnp);
731 8 : ANALYTICAL_LAG_OTHERS;
732 : } else {
733 4 : j += cnt;
734 20 : ANALYTICAL_LAG_OTHERS;
735 : }
736 : }
737 : }
738 30 : bat_iterator_end(&bi);
739 30 : bat_iterator_end(&pi);
740 30 : BATsetcount(r, cnt);
741 30 : r->tnonil = !has_nils;
742 30 : r->tnil = has_nils;
743 30 : return GDK_SUCCEED;
744 : }
745 :
746 : #define LEAD_CALC(TPE) \
747 : do { \
748 : if (lead < ncnt) { \
749 : bp += lead; \
750 : l = ncnt - lead; \
751 : for (i = 0; i < l; i++, rb++, bp++) { \
752 : next = *bp; \
753 : *rb = next; \
754 : has_nils |= is_##TPE##_nil(next); \
755 : } \
756 : } else { \
757 : bp += ncnt; \
758 : } \
759 : for (;rb < rp; rb++) \
760 : *rb = def; \
761 : has_nils |= (lead > 0 && is_##TPE##_nil(def)); \
762 : } while (0)
763 :
764 : #define ANALYTICAL_LEAD_IMP(TPE) \
765 : do { \
766 : TPE *rp, *rb, *bp, *rend, \
767 : def = *((TPE *) default_value), next; \
768 : bp = (TPE*)bi.base; \
769 : rb = rp = (TPE*)Tloc(r, 0); \
770 : rend = rb + cnt; \
771 : if (lead == BUN_NONE) { \
772 : has_nils = true; \
773 : for (; rb < rend; rb++) \
774 : *rb = TPE##_nil; \
775 : } else if (p) { \
776 : pnp = np = (bit*)pi.base; \
777 : end = np + cnt; \
778 : for (; np < end; np++) { \
779 : if (*np) { \
780 : ncnt = (np - pnp); \
781 : rp += ncnt; \
782 : LEAD_CALC(TPE); \
783 : pnp = np; \
784 : } \
785 : } \
786 : ncnt = (np - pnp); \
787 : rp += ncnt; \
788 : LEAD_CALC(TPE); \
789 : } else { \
790 : ncnt = cnt; \
791 : rp += ncnt; \
792 : LEAD_CALC(TPE); \
793 : } \
794 : } while (0)
795 :
796 : #define ANALYTICAL_LEAD_OTHERS \
797 : do { \
798 : j += ncnt; \
799 : if (lead < ncnt) { \
800 : m = ncnt - lead; \
801 : for (i = 0,n = k + lead; i < m; i++, n++) { \
802 : curval = BUNtail(bi, n); \
803 : if (BUNappend(r, curval, false) != GDK_SUCCEED) { \
804 : bat_iterator_end(&bi); \
805 : bat_iterator_end(&pi); \
806 : return GDK_FAIL; \
807 : } \
808 : has_nils |= atomcmp(curval, nil) == 0; \
809 : } \
810 : k += i; \
811 : } \
812 : for (; k < j; k++) { \
813 : if (BUNappend(r, default_value, false) != GDK_SUCCEED) { \
814 : bat_iterator_end(&bi); \
815 : bat_iterator_end(&pi); \
816 : return GDK_FAIL; \
817 : } \
818 : } \
819 : has_nils |= (lead > 0 && atomcmp(default_value, nil) == 0); \
820 : } while (0)
821 :
822 : gdk_return
823 29 : GDKanalyticallead(BAT *r, BAT *b, BAT *p, BUN lead, const void *restrict default_value, int tpe)
824 : {
825 29 : BATiter bi = bat_iterator(b);
826 29 : BATiter pi = bat_iterator(p);
827 29 : int (*atomcmp) (const void *, const void *);
828 29 : const void *restrict nil;
829 29 : BUN i = 0, j = 0, k = 0, l = 0, ncnt, cnt = BATcount(b);
830 29 : bit *np, *pnp, *end;
831 29 : bool has_nils = false;
832 :
833 29 : assert(default_value);
834 :
835 58 : switch (ATOMbasetype(tpe)) {
836 4 : case TYPE_bte:
837 35 : ANALYTICAL_LEAD_IMP(bte);
838 : break;
839 0 : case TYPE_sht:
840 0 : ANALYTICAL_LEAD_IMP(sht);
841 : break;
842 18 : case TYPE_int:
843 296 : ANALYTICAL_LEAD_IMP(int);
844 : break;
845 1 : case TYPE_lng:
846 23 : ANALYTICAL_LEAD_IMP(lng);
847 : break;
848 : #ifdef HAVE_HGE
849 0 : case TYPE_hge:
850 0 : ANALYTICAL_LEAD_IMP(hge);
851 : break;
852 : #endif
853 0 : case TYPE_flt:
854 0 : ANALYTICAL_LEAD_IMP(flt);
855 : break;
856 0 : case TYPE_dbl:
857 0 : ANALYTICAL_LEAD_IMP(dbl);
858 : break;
859 6 : default:{
860 6 : BUN m = 0, n = 0;
861 6 : const void *restrict curval;
862 6 : nil = ATOMnilptr(tpe);
863 6 : atomcmp = ATOMcompare(tpe);
864 6 : if (lead == BUN_NONE) {
865 0 : has_nils = true;
866 0 : for (j = 0; j < cnt; j++) {
867 0 : if (BUNappend(r, nil, false) != GDK_SUCCEED) {
868 0 : bat_iterator_end(&bi);
869 0 : bat_iterator_end(&pi);
870 0 : return GDK_FAIL;
871 : }
872 : }
873 6 : } else if (p) {
874 4 : pnp = np = (bit *) pi.base;
875 4 : end = np + cnt;
876 42 : for (; np < end; np++) {
877 38 : if (*np) {
878 12 : ncnt = (np - pnp);
879 56 : ANALYTICAL_LEAD_OTHERS;
880 12 : pnp = np;
881 : }
882 : }
883 4 : ncnt = (np - pnp);
884 14 : ANALYTICAL_LEAD_OTHERS;
885 : } else {
886 2 : ncnt = cnt;
887 20 : ANALYTICAL_LEAD_OTHERS;
888 : }
889 : }
890 : }
891 29 : bat_iterator_end(&bi);
892 29 : bat_iterator_end(&pi);
893 29 : BATsetcount(r, cnt);
894 29 : r->tnonil = !has_nils;
895 29 : r->tnil = has_nils;
896 29 : return GDK_SUCCEED;
897 : }
898 :
899 : #define ANALYTICAL_MIN_MAX_CALC_FIXED_UNBOUNDED_TILL_CURRENT_ROW(TPE, MIN_MAX) \
900 : do { \
901 : TPE curval = TPE##_nil; \
902 : for (; k < i;) { \
903 : j = k; \
904 : do { \
905 : if (!is_##TPE##_nil(bp[k])) { \
906 : if (is_##TPE##_nil(curval)) \
907 : curval = bp[k]; \
908 : else \
909 : curval = MIN_MAX(bp[k], curval); \
910 : } \
911 : k++; \
912 : } while (k < i && !op[k]); \
913 : for (; j < k; j++) \
914 : rb[j] = curval; \
915 : has_nils |= is_##TPE##_nil(curval); \
916 : } \
917 : } while (0)
918 :
919 : #define ANALYTICAL_MIN_MAX_CALC_FIXED_CURRENT_ROW_TILL_UNBOUNDED(TPE, MIN_MAX) \
920 : do { \
921 : TPE curval = TPE##_nil; \
922 : l = i - 1; \
923 : for (j = l; ; j--) { \
924 : if (!is_##TPE##_nil(bp[j])) { \
925 : if (is_##TPE##_nil(curval)) \
926 : curval = bp[j]; \
927 : else \
928 : curval = MIN_MAX(bp[j], curval); \
929 : } \
930 : if (op[j] || j == k) { \
931 : for (; ; l--) { \
932 : rb[l] = curval; \
933 : if (l == j) \
934 : break; \
935 : } \
936 : has_nils |= is_##TPE##_nil(curval); \
937 : if (j == k) \
938 : break; \
939 : l = j - 1; \
940 : } \
941 : } \
942 : k = i; \
943 : } while (0)
944 :
945 : #define ANALYTICAL_MIN_MAX_CALC_FIXED_ALL_ROWS(TPE, MIN_MAX) \
946 : do { \
947 : TPE curval = TPE##_nil; \
948 : for (j = k; j < i; j++) { \
949 : TPE v = bp[j]; \
950 : if (!is_##TPE##_nil(v)) { \
951 : if (is_##TPE##_nil(curval)) \
952 : curval = v; \
953 : else \
954 : curval = MIN_MAX(v, curval); \
955 : } \
956 : } \
957 : for (; k < i; k++) \
958 : rb[k] = curval; \
959 : has_nils |= is_##TPE##_nil(curval); \
960 : } while (0)
961 :
962 : #define ANALYTICAL_MIN_MAX_CALC_FIXED_CURRENT_ROW(TPE, MIN_MAX) \
963 : do { \
964 : for (; k < i; k++) { \
965 : TPE v = bp[k]; \
966 : rb[k] = v; \
967 : has_nils |= is_##TPE##_nil(v); \
968 : } \
969 : } while (0)
970 :
971 : #define INIT_AGGREGATE_MIN_MAX_FIXED(TPE, MIN_MAX, NOTHING) \
972 : do { \
973 : computed = TPE##_nil; \
974 : } while (0)
975 : #define COMPUTE_LEVEL0_MIN_MAX_FIXED(X, TPE, MIN_MAX, NOTHING) \
976 : do { \
977 : computed = bp[j + X]; \
978 : } while (0)
979 : #define COMPUTE_LEVELN_MIN_MAX_FIXED(VAL, TPE, MIN_MAX, NOTHING) \
980 : do { \
981 : if (!is_##TPE##_nil(VAL)) { \
982 : if (is_##TPE##_nil(computed)) \
983 : computed = VAL; \
984 : else \
985 : computed = MIN_MAX(computed, VAL); \
986 : } \
987 : } while (0)
988 : #define FINALIZE_AGGREGATE_MIN_MAX_FIXED(TPE, MIN_MAX, NOTHING) \
989 : do { \
990 : rb[k] = computed; \
991 : has_nils |= is_##TPE##_nil(computed); \
992 : } while (0)
993 : #define ANALYTICAL_MIN_MAX_CALC_FIXED_OTHERS(TPE, MIN_MAX) \
994 : do { \
995 : oid ncount = i - k; \
996 : if ((res = GDKrebuild_segment_tree(ncount, sizeof(TPE), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
997 : goto cleanup; \
998 : populate_segment_tree(TPE, ncount, INIT_AGGREGATE_MIN_MAX_FIXED, COMPUTE_LEVEL0_MIN_MAX_FIXED, COMPUTE_LEVELN_MIN_MAX_FIXED, TPE, MIN_MAX, NOTHING); \
999 : for (; k < i; k++) \
1000 : compute_on_segment_tree(TPE, start[k] - j, end[k] - j, INIT_AGGREGATE_MIN_MAX_FIXED, COMPUTE_LEVELN_MIN_MAX_FIXED, FINALIZE_AGGREGATE_MIN_MAX_FIXED, TPE, MIN_MAX, NOTHING); \
1001 : j = k; \
1002 : } while (0)
1003 :
1004 : #define ANALYTICAL_MIN_MAX_CALC_OTHERS_UNBOUNDED_TILL_CURRENT_ROW(GT_LT) \
1005 : do { \
1006 : const void *curval = nil; \
1007 : if (ATOMvarsized(tpe)) { \
1008 : for (; k < i;) { \
1009 : j = k; \
1010 : do { \
1011 : const void *next = BUNtvar(bi, k); \
1012 : if (atomcmp(next, nil) != 0) { \
1013 : if (atomcmp(curval, nil) == 0) \
1014 : curval = next; \
1015 : else \
1016 : curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
1017 : } \
1018 : k++; \
1019 : } while (k < i && !op[k]); \
1020 : for (; j < k; j++) \
1021 : if ((res = tfastins_nocheckVAR(r, j, curval)) != GDK_SUCCEED) \
1022 : goto cleanup; \
1023 : has_nils |= atomcmp(curval, nil) == 0; \
1024 : } \
1025 : } else { \
1026 : for (; k < i;) { \
1027 : j = k; \
1028 : do { \
1029 : const void *next = BUNtloc(bi, k); \
1030 : if (atomcmp(next, nil) != 0) { \
1031 : if (atomcmp(curval, nil) == 0) \
1032 : curval = next; \
1033 : else \
1034 : curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
1035 : } \
1036 : k++; \
1037 : } while (k < i && !op[k]); \
1038 : for (; j < k; j++) { \
1039 : memcpy(rcast, curval, width); \
1040 : rcast += width; \
1041 : } \
1042 : has_nils |= atomcmp(curval, nil) == 0; \
1043 : } \
1044 : } \
1045 : } while (0)
1046 :
1047 : #define ANALYTICAL_MIN_MAX_CALC_OTHERS_CURRENT_ROW_TILL_UNBOUNDED(GT_LT) \
1048 : do { \
1049 : const void *curval = nil; \
1050 : l = i - 1; \
1051 : if (ATOMvarsized(tpe)) { \
1052 : for (j = l; ; j--) { \
1053 : const void *next = BUNtvar(bi, j); \
1054 : if (atomcmp(next, nil) != 0) { \
1055 : if (atomcmp(curval, nil) == 0) \
1056 : curval = next; \
1057 : else \
1058 : curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
1059 : } \
1060 : if (op[j] || j == k) { \
1061 : for (; ; l--) { \
1062 : if ((res = tfastins_nocheckVAR(r, l, curval)) != GDK_SUCCEED) \
1063 : goto cleanup; \
1064 : if (l == j) \
1065 : break; \
1066 : } \
1067 : has_nils |= atomcmp(curval, nil) == 0; \
1068 : if (j == k) \
1069 : break; \
1070 : l = j - 1; \
1071 : } \
1072 : } \
1073 : } else { \
1074 : for (j = l; ; j--) { \
1075 : const void *next = BUNtloc(bi, j); \
1076 : if (atomcmp(next, nil) != 0) { \
1077 : if (atomcmp(curval, nil) == 0) \
1078 : curval = next; \
1079 : else \
1080 : curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
1081 : } \
1082 : if (op[j] || j == k) { \
1083 : BUN x = l * width; \
1084 : for (; ; l--) { \
1085 : memcpy(rcast + x, curval, width); \
1086 : x -= width; \
1087 : if (l == j) \
1088 : break; \
1089 : } \
1090 : has_nils |= atomcmp(curval, nil) == 0; \
1091 : if (j == k) \
1092 : break; \
1093 : l = j - 1; \
1094 : } \
1095 : } \
1096 : } \
1097 : k = i; \
1098 : } while (0)
1099 :
1100 : #define ANALYTICAL_MIN_MAX_CALC_OTHERS_ALL_ROWS(GT_LT) \
1101 : do { \
1102 : const void *curval = (void*) nil; \
1103 : if (ATOMvarsized(tpe)) { \
1104 : for (j = k; j < i; j++) { \
1105 : const void *next = BUNtvar(bi, j); \
1106 : if (atomcmp(next, nil) != 0) { \
1107 : if (atomcmp(curval, nil) == 0) \
1108 : curval = next; \
1109 : else \
1110 : curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
1111 : } \
1112 : } \
1113 : for (; k < i; k++) \
1114 : if ((res = tfastins_nocheckVAR(r, k, curval)) != GDK_SUCCEED) \
1115 : goto cleanup; \
1116 : } else { \
1117 : for (j = k; j < i; j++) { \
1118 : const void *next = BUNtloc(bi, j); \
1119 : if (atomcmp(next, nil) != 0) { \
1120 : if (atomcmp(curval, nil) == 0) \
1121 : curval = next; \
1122 : else \
1123 : curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
1124 : } \
1125 : } \
1126 : for (; k < i; k++) { \
1127 : memcpy(rcast, curval, width); \
1128 : rcast += width; \
1129 : } \
1130 : } \
1131 : has_nils |= atomcmp(curval, nil) == 0; \
1132 : } while (0)
1133 :
1134 : #define ANALYTICAL_MIN_MAX_CALC_OTHERS_CURRENT_ROW(GT_LT) \
1135 : do { \
1136 : if (ATOMvarsized(tpe)) { \
1137 : for (; k < i; k++) { \
1138 : const void *next = BUNtvar(bi, k); \
1139 : if ((res = tfastins_nocheckVAR(r, k, next)) != GDK_SUCCEED) \
1140 : goto cleanup; \
1141 : has_nils |= atomcmp(next, nil) == 0; \
1142 : } \
1143 : } else { \
1144 : for (; k < i; k++) { \
1145 : const void *next = BUNtloc(bi, k); \
1146 : memcpy(rcast, next, width); \
1147 : rcast += width; \
1148 : has_nils |= atomcmp(next, nil) == 0; \
1149 : } \
1150 : } \
1151 : } while (0)
1152 :
1153 : #define INIT_AGGREGATE_MIN_MAX_OTHERS(GT_LT, NOTHING1, NOTHING2) \
1154 : do { \
1155 : computed = (void*) nil; \
1156 : } while (0)
1157 : #define COMPUTE_LEVEL0_MIN_MAX_OTHERS(X, GT_LT, NOTHING1, NOTHING2) \
1158 : do { \
1159 : computed = BUNtail(bi, j + X); \
1160 : } while (0)
1161 : #define COMPUTE_LEVELN_MIN_MAX_OTHERS(VAL, GT_LT, NOTHING1, NOTHING2) \
1162 : do { \
1163 : if (atomcmp(VAL, nil) != 0) { \
1164 : if (atomcmp(computed, nil) == 0) \
1165 : computed = VAL; \
1166 : else \
1167 : computed = atomcmp(VAL, computed) GT_LT 0 ? computed : VAL; \
1168 : } \
1169 : } while (0)
1170 : #define FINALIZE_AGGREGATE_MIN_MAX_OTHERS(GT_LT, NOTHING1, NOTHING2) \
1171 : do { \
1172 : if (ATOMvarsized(tpe)) { \
1173 : if ((res = tfastins_nocheckVAR(r, k, computed)) != GDK_SUCCEED) \
1174 : goto cleanup; \
1175 : } else { \
1176 : memcpy(rcast, computed, width); \
1177 : rcast += width; \
1178 : } \
1179 : has_nils |= atomcmp(computed, nil) == 0; \
1180 : } while (0)
1181 : #define ANALYTICAL_MIN_MAX_CALC_OTHERS_OTHERS(GT_LT) \
1182 : do { \
1183 : oid ncount = i - k; \
1184 : if ((res = GDKrebuild_segment_tree(ncount, sizeof(void*), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
1185 : goto cleanup; \
1186 : populate_segment_tree(void*, ncount, INIT_AGGREGATE_MIN_MAX_OTHERS, COMPUTE_LEVEL0_MIN_MAX_OTHERS, COMPUTE_LEVELN_MIN_MAX_OTHERS, GT_LT, NOTHING, NOTHING); \
1187 : for (; k < i; k++) \
1188 : compute_on_segment_tree(void*, start[k] - j, end[k] - j, INIT_AGGREGATE_MIN_MAX_OTHERS, COMPUTE_LEVELN_MIN_MAX_OTHERS, FINALIZE_AGGREGATE_MIN_MAX_OTHERS, GT_LT, NOTHING, NOTHING); \
1189 : j = k; \
1190 : } while (0)
1191 :
1192 : #define ANALYTICAL_MIN_MAX_PARTITIONS(TPE, MIN_MAX, IMP) \
1193 : do { \
1194 : TPE *restrict bp = (TPE*)bi.base, *rb = (TPE*)Tloc(r, 0); \
1195 : if (p) { \
1196 : while (i < cnt) { \
1197 : if (np[i]) { \
1198 : minmaxfixed##TPE##IMP: \
1199 : ANALYTICAL_MIN_MAX_CALC_FIXED_##IMP(TPE, MIN_MAX); \
1200 : } \
1201 : if (!last) \
1202 : i++; \
1203 : } \
1204 : } \
1205 : if (!last) { /* hack to reduce code explosion, there's no need to duplicate the code to iterate each partition */ \
1206 : last = true; \
1207 : i = cnt; \
1208 : goto minmaxfixed##TPE##IMP; \
1209 : } \
1210 : } while (0)
1211 :
1212 : #ifdef HAVE_HGE
1213 : #define ANALYTICAL_MIN_MAX_LIMIT(MIN_MAX, IMP) \
1214 : case TYPE_hge: \
1215 : ANALYTICAL_MIN_MAX_PARTITIONS(hge, MIN_MAX, IMP); \
1216 : break;
1217 : #else
1218 : #define ANALYTICAL_MIN_MAX_LIMIT(MIN_MAX, IMP)
1219 : #endif
1220 :
1221 : #define ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, IMP) \
1222 : do { \
1223 : switch (ATOMbasetype(tpe)) { \
1224 : case TYPE_bte: \
1225 : ANALYTICAL_MIN_MAX_PARTITIONS(bte, MIN_MAX, IMP); \
1226 : break; \
1227 : case TYPE_sht: \
1228 : ANALYTICAL_MIN_MAX_PARTITIONS(sht, MIN_MAX, IMP); \
1229 : break; \
1230 : case TYPE_int: \
1231 : ANALYTICAL_MIN_MAX_PARTITIONS(int, MIN_MAX, IMP); \
1232 : break; \
1233 : case TYPE_lng: \
1234 : ANALYTICAL_MIN_MAX_PARTITIONS(lng, MIN_MAX, IMP); \
1235 : break; \
1236 : ANALYTICAL_MIN_MAX_LIMIT(MIN_MAX, IMP) \
1237 : case TYPE_flt: \
1238 : ANALYTICAL_MIN_MAX_PARTITIONS(flt, MIN_MAX, IMP); \
1239 : break; \
1240 : case TYPE_dbl: \
1241 : ANALYTICAL_MIN_MAX_PARTITIONS(dbl, MIN_MAX, IMP); \
1242 : break; \
1243 : default: { \
1244 : if (p) { \
1245 : while (i < cnt) { \
1246 : if (np[i]) { \
1247 : minmaxvarsized##IMP: \
1248 : ANALYTICAL_MIN_MAX_CALC_OTHERS_##IMP(GT_LT); \
1249 : } \
1250 : if (!last) \
1251 : i++; \
1252 : } \
1253 : } \
1254 : if (!last) { \
1255 : last = true; \
1256 : i = cnt; \
1257 : goto minmaxvarsized##IMP; \
1258 : } \
1259 : } \
1260 : } \
1261 : } while (0)
1262 :
1263 : #define ANALYTICAL_MIN_MAX(OP, MIN_MAX, GT_LT) \
1264 : gdk_return \
1265 : GDKanalytical##OP(BAT *r, BAT *p, BAT *o, BAT *b, BAT *s, BAT *e, int tpe, int frame_type) \
1266 : { \
1267 : BATiter pi = bat_iterator(p); \
1268 : BATiter oi = bat_iterator(o); \
1269 : BATiter bi = bat_iterator(b); \
1270 : BATiter si = bat_iterator(s); \
1271 : BATiter ei = bat_iterator(e); \
1272 : bool has_nils = false, last = false; \
1273 : oid i = 1, j = 0, k = 0, l = 0, cnt = BATcount(b), *restrict start = si.base, *restrict end = ei.base, \
1274 : *levels_offset = NULL, nlevels = 0; \
1275 : bit *np = pi.base, *op = oi.base; \
1276 : const void *nil = ATOMnilptr(tpe); \
1277 : int (*atomcmp)(const void *, const void *) = ATOMcompare(tpe); \
1278 : void *segment_tree = NULL; \
1279 : gdk_return res = GDK_SUCCEED; \
1280 : uint16_t width = r->twidth; \
1281 : uint8_t *restrict rcast = (uint8_t *) Tloc(r, 0); \
1282 : BAT *st = NULL; \
1283 : \
1284 : assert(np == NULL || cnt == 0 || np[0] == 0); \
1285 : if (cnt > 0) { \
1286 : switch (frame_type) { \
1287 : case 3: /* unbounded until current row */ \
1288 : ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, UNBOUNDED_TILL_CURRENT_ROW); \
1289 : break; \
1290 : case 4: /* current row until unbounded */ \
1291 : ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, CURRENT_ROW_TILL_UNBOUNDED); \
1292 : break; \
1293 : case 5: /* all rows */ \
1294 : ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, ALL_ROWS); \
1295 : break; \
1296 : case 6: /* current row */ \
1297 : ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, CURRENT_ROW); \
1298 : break; \
1299 : default: \
1300 : if ((st = GDKinitialize_segment_tree()) == NULL) { \
1301 : res = GDK_FAIL; \
1302 : goto cleanup; \
1303 : } \
1304 : ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, OTHERS); \
1305 : break; \
1306 : } \
1307 : } \
1308 : \
1309 : BATsetcount(r, cnt); \
1310 : r->tnonil = !has_nils; \
1311 : r->tnil = has_nils; \
1312 : cleanup: \
1313 : bat_iterator_end(&pi); \
1314 : bat_iterator_end(&oi); \
1315 : bat_iterator_end(&bi); \
1316 : bat_iterator_end(&si); \
1317 : bat_iterator_end(&ei); \
1318 : BBPreclaim(st); \
1319 : return res; \
1320 : }
1321 :
1322 3344 : ANALYTICAL_MIN_MAX(min, MIN, >)
1323 14999655 : ANALYTICAL_MIN_MAX(max, MAX, <)
1324 :
1325 : /* Counting no nils for fixed sizes */
1326 : #define ANALYTICAL_COUNT_FIXED_UNBOUNDED_TILL_CURRENT_ROW(TPE) \
1327 : do { \
1328 : curval = 0; \
1329 : if (count_all) { \
1330 : for (; k < i;) { \
1331 : j = k; \
1332 : do { \
1333 : k++; \
1334 : } while (k < i && !op[k]); \
1335 : curval += k - j; \
1336 : for (; j < k; j++) \
1337 : rb[j] = curval; \
1338 : } \
1339 : } else { \
1340 : for (; k < i;) { \
1341 : j = k; \
1342 : do { \
1343 : curval += !is_##TPE##_nil(bp[k]); \
1344 : k++; \
1345 : } while (k < i && !op[k]); \
1346 : for (; j < k; j++) \
1347 : rb[j] = curval; \
1348 : } \
1349 : } \
1350 : } while (0)
1351 :
1352 : #define ANALYTICAL_COUNT_FIXED_CURRENT_ROW_TILL_UNBOUNDED(TPE) \
1353 : do { \
1354 : curval = 0; \
1355 : l = i - 1; \
1356 : if (count_all) { \
1357 : for (j = l; ; j--) { \
1358 : if (op[j] || j == k) { \
1359 : curval += l - j + 1; \
1360 : for (; ; l--) { \
1361 : rb[l] = curval; \
1362 : if (l == j) \
1363 : break; \
1364 : } \
1365 : if (j == k) \
1366 : break; \
1367 : l = j - 1; \
1368 : } \
1369 : } \
1370 : } else { \
1371 : for (j = l; ; j--) { \
1372 : curval += !is_##TPE##_nil(bp[j]); \
1373 : if (op[j] || j == k) { \
1374 : for (; ; l--) { \
1375 : rb[l] = curval; \
1376 : if (l == j) \
1377 : break; \
1378 : } \
1379 : if (j == k) \
1380 : break; \
1381 : l = j - 1; \
1382 : } \
1383 : } \
1384 : } \
1385 : k = i; \
1386 : } while (0)
1387 :
1388 : #define ANALYTICAL_COUNT_FIXED_ALL_ROWS(TPE) \
1389 : do { \
1390 : if (count_all) { \
1391 : curval = (lng)(i - k); \
1392 : for (; k < i; k++) \
1393 : rb[k] = curval; \
1394 : } else { \
1395 : curval = 0; \
1396 : for (; j < i; j++) \
1397 : curval += !is_##TPE##_nil(bp[j]); \
1398 : for (; k < i; k++) \
1399 : rb[k] = curval; \
1400 : } \
1401 : } while (0)
1402 :
1403 : #define ANALYTICAL_COUNT_FIXED_CURRENT_ROW(TPE) \
1404 : do { \
1405 : if (count_all) { \
1406 : for (; k < i; k++) \
1407 : rb[k] = 1; \
1408 : } else { \
1409 : for (; k < i; k++) \
1410 : rb[k] = !is_##TPE##_nil(bp[k]); \
1411 : } \
1412 : } while (0)
1413 :
1414 : #define INIT_AGGREGATE_COUNT(TPE, NOTHING1, NOTHING2) \
1415 : do { \
1416 : computed = 0; \
1417 : } while (0)
1418 : #define COMPUTE_LEVEL0_COUNT_FIXED(X, TPE, NOTHING1, NOTHING2) \
1419 : do { \
1420 : computed = !is_##TPE##_nil(bp[j + X]); \
1421 : } while (0)
1422 : #define COMPUTE_LEVELN_COUNT(VAL, NOTHING1, NOTHING2, NOTHING3) \
1423 : do { \
1424 : computed += VAL; \
1425 : } while (0)
1426 : #define FINALIZE_AGGREGATE_COUNT(NOTHING1, NOTHING2, NOTHING3) \
1427 : do { \
1428 : rb[k] = computed; \
1429 : } while (0)
1430 : #define ANALYTICAL_COUNT_FIXED_OTHERS(TPE) \
1431 : do { \
1432 : if (count_all) { /* no segment tree required for the global case (it scales in O(n)) */ \
1433 : for (; k < i; k++) \
1434 : rb[k] = (end[k] > start[k]) ? (lng)(end[k] - start[k]) : 0; \
1435 : } else { \
1436 : oid ncount = i - k; \
1437 : if ((res = GDKrebuild_segment_tree(ncount, sizeof(lng), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
1438 : goto cleanup; \
1439 : populate_segment_tree(lng, ncount, INIT_AGGREGATE_COUNT, COMPUTE_LEVEL0_COUNT_FIXED, COMPUTE_LEVELN_COUNT, TPE, NOTHING, NOTHING); \
1440 : for (; k < i; k++) \
1441 : compute_on_segment_tree(lng, start[k] - j, end[k] - j, INIT_AGGREGATE_COUNT, COMPUTE_LEVELN_COUNT, FINALIZE_AGGREGATE_COUNT, TPE, NOTHING, NOTHING); \
1442 : j = k; \
1443 : } \
1444 : } while (0)
1445 :
1446 : /* Counting no nils for other types */
1447 : #define ANALYTICAL_COUNT_OTHERS_UNBOUNDED_TILL_CURRENT_ROW \
1448 : do { \
1449 : curval = 0; \
1450 : if (count_all) { \
1451 : for (; k < i;) { \
1452 : j = k; \
1453 : do { \
1454 : k++; \
1455 : } while (k < i && !op[k]); \
1456 : curval += k - j; \
1457 : for (; j < k; j++) \
1458 : rb[j] = curval; \
1459 : } \
1460 : } else { \
1461 : for (; k < i; ) { \
1462 : j = k; \
1463 : do { \
1464 : curval += cmp(BUNtail(bi, k), nil) != 0; \
1465 : k++; \
1466 : } while (k < i && !op[k]); \
1467 : for (; j < k; j++) \
1468 : rb[j] = curval; \
1469 : } \
1470 : } \
1471 : } while (0)
1472 :
1473 : #define ANALYTICAL_COUNT_OTHERS_CURRENT_ROW_TILL_UNBOUNDED \
1474 : do { \
1475 : curval = 0; \
1476 : l = i - 1; \
1477 : if (count_all) { \
1478 : for (j = l; ; j--) { \
1479 : if (op[j] || j == k) { \
1480 : curval += l - j + 1; \
1481 : for (; ; l--) { \
1482 : rb[l] = curval; \
1483 : if (l == j) \
1484 : break; \
1485 : } \
1486 : if (j == k) \
1487 : break; \
1488 : l = j - 1; \
1489 : } \
1490 : } \
1491 : } else { \
1492 : for (j = l; ; j--) { \
1493 : curval += cmp(BUNtail(bi, j), nil) != 0; \
1494 : if (op[j] || j == k) { \
1495 : for (; ; l--) { \
1496 : rb[l] = curval; \
1497 : if (l == j) \
1498 : break; \
1499 : } \
1500 : if (j == k) \
1501 : break; \
1502 : l = j - 1; \
1503 : } \
1504 : } \
1505 : } \
1506 : k = i; \
1507 : } while (0)
1508 :
1509 : #define ANALYTICAL_COUNT_OTHERS_ALL_ROWS \
1510 : do { \
1511 : curval = 0; \
1512 : if (count_all) { \
1513 : curval = (lng)(i - k); \
1514 : } else { \
1515 : for (; j < i; j++) \
1516 : curval += cmp(BUNtail(bi, j), nil) != 0; \
1517 : } \
1518 : for (; k < i; k++) \
1519 : rb[k] = curval; \
1520 : } while (0)
1521 :
1522 : #define ANALYTICAL_COUNT_OTHERS_CURRENT_ROW \
1523 : do { \
1524 : if (count_all) { \
1525 : for (; k < i; k++) \
1526 : rb[k] = 1; \
1527 : } else { \
1528 : for (; k < i; k++) \
1529 : rb[k] = cmp(BUNtail(bi, k), nil) != 0; \
1530 : } \
1531 : } while (0)
1532 :
1533 : #define COMPUTE_LEVEL0_COUNT_OTHERS(X, NOTHING1, NOTHING2, NOTHING3) \
1534 : do { \
1535 : computed = cmp(BUNtail(bi, j + X), nil) != 0; \
1536 : } while (0)
1537 : #define ANALYTICAL_COUNT_OTHERS_OTHERS \
1538 : do { \
1539 : if (count_all) { /* no segment tree required for the global case (it scales in O(n)) */ \
1540 : for (; k < i; k++) \
1541 : rb[k] = (end[k] > start[k]) ? (lng)(end[k] - start[k]) : 0; \
1542 : } else { \
1543 : oid ncount = i - k; \
1544 : if ((res = GDKrebuild_segment_tree(ncount, sizeof(lng), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
1545 : goto cleanup; \
1546 : populate_segment_tree(lng, ncount, INIT_AGGREGATE_COUNT, COMPUTE_LEVEL0_COUNT_OTHERS, COMPUTE_LEVELN_COUNT, NOTHING, NOTHING, NOTHING); \
1547 : for (; k < i; k++) \
1548 : compute_on_segment_tree(lng, start[k] - j, end[k] - j, INIT_AGGREGATE_COUNT, COMPUTE_LEVELN_COUNT, FINALIZE_AGGREGATE_COUNT, NOTHING, NOTHING, NOTHING); \
1549 : j = k; \
1550 : } \
1551 : } while (0)
1552 :
1553 : /* Now do the count analytic function branches */
1554 : #define ANALYTICAL_COUNT_FIXED_PARTITIONS(TPE, IMP) \
1555 : do { \
1556 : TPE *restrict bp = (TPE*) bheap; \
1557 : if (p) { \
1558 : while (i < cnt) { \
1559 : if (np[i]) { \
1560 : count##TPE##IMP: \
1561 : ANALYTICAL_COUNT_FIXED_##IMP(TPE); \
1562 : } \
1563 : if (!last) \
1564 : i++; \
1565 : } \
1566 : } \
1567 : if (!last) { \
1568 : last = true; \
1569 : i = cnt; \
1570 : goto count##TPE##IMP; \
1571 : } \
1572 : } while (0)
1573 :
1574 : #ifdef HAVE_HGE
1575 : #define ANALYTICAL_COUNT_LIMIT(IMP) \
1576 : case TYPE_hge: \
1577 : ANALYTICAL_COUNT_FIXED_PARTITIONS(hge, IMP); \
1578 : break;
1579 : #else
1580 : #define ANALYTICAL_COUNT_LIMIT(IMP)
1581 : #endif
1582 :
1583 : #define ANALYTICAL_COUNT_BRANCHES(IMP) \
1584 : do { \
1585 : switch (ATOMbasetype(tpe)) { \
1586 : case TYPE_bte: \
1587 : ANALYTICAL_COUNT_FIXED_PARTITIONS(bte, IMP); \
1588 : break; \
1589 : case TYPE_sht: \
1590 : ANALYTICAL_COUNT_FIXED_PARTITIONS(sht, IMP); \
1591 : break; \
1592 : case TYPE_int: \
1593 : ANALYTICAL_COUNT_FIXED_PARTITIONS(int, IMP); \
1594 : break; \
1595 : case TYPE_lng: \
1596 : ANALYTICAL_COUNT_FIXED_PARTITIONS(lng, IMP); \
1597 : break; \
1598 : ANALYTICAL_COUNT_LIMIT(IMP) \
1599 : case TYPE_flt: \
1600 : ANALYTICAL_COUNT_FIXED_PARTITIONS(flt, IMP); \
1601 : break; \
1602 : case TYPE_dbl: \
1603 : ANALYTICAL_COUNT_FIXED_PARTITIONS(dbl, IMP); \
1604 : break; \
1605 : default: { \
1606 : if (p) { \
1607 : while (i < cnt) { \
1608 : if (np[i]) { \
1609 : countothers##IMP: \
1610 : ANALYTICAL_COUNT_OTHERS_##IMP; \
1611 : } \
1612 : if (!last) \
1613 : i++; \
1614 : } \
1615 : } \
1616 : if (!last) { \
1617 : last = true; \
1618 : i = cnt; \
1619 : goto countothers##IMP; \
1620 : } \
1621 : } \
1622 : } \
1623 : } while (0)
1624 :
1625 : gdk_return
1626 159 : GDKanalyticalcount(BAT *r, BAT *p, BAT *o, BAT *b, BAT *s, BAT *e, bit ignore_nils, int tpe, int frame_type)
1627 : {
1628 159 : BATiter pi = bat_iterator(p);
1629 159 : BATiter oi = bat_iterator(o);
1630 159 : BATiter bi = bat_iterator(b);
1631 159 : BATiter si = bat_iterator(s);
1632 159 : BATiter ei = bat_iterator(e);
1633 159 : oid i = 1, j = 0, k = 0, l = 0, cnt = BATcount(b), *restrict start = si.base, *restrict end = ei.base,
1634 159 : *levels_offset = NULL, nlevels = 0;
1635 159 : lng curval = 0, *rb = (lng *) Tloc(r, 0);
1636 159 : bit *np = pi.base, *op = oi.base;
1637 159 : const void *restrict nil = ATOMnilptr(tpe);
1638 159 : int (*cmp) (const void *, const void *) = ATOMcompare(tpe);
1639 159 : const void *restrict bheap = bi.base;
1640 159 : bool count_all = !ignore_nils || bi.nonil, last = false;
1641 159 : void *segment_tree = NULL;
1642 159 : gdk_return res = GDK_SUCCEED;
1643 159 : BAT *st = NULL;
1644 :
1645 159 : assert(np == NULL || cnt == 0 || np[0] == 0);
1646 159 : if (cnt > 0) {
1647 159 : switch (frame_type) {
1648 38 : case 3: /* unbounded until current row */
1649 968 : ANALYTICAL_COUNT_BRANCHES(UNBOUNDED_TILL_CURRENT_ROW);
1650 : break;
1651 3 : case 4: /* current row until unbounded */
1652 43 : ANALYTICAL_COUNT_BRANCHES(CURRENT_ROW_TILL_UNBOUNDED);
1653 : break;
1654 32 : case 5: /* all rows */
1655 631 : ANALYTICAL_COUNT_BRANCHES(ALL_ROWS);
1656 : break;
1657 8 : case 6: /* current row */
1658 95 : ANALYTICAL_COUNT_BRANCHES(CURRENT_ROW);
1659 : break;
1660 78 : default:
1661 78 : if (!count_all && (st = GDKinitialize_segment_tree()) == NULL) {
1662 0 : res = GDK_FAIL;
1663 0 : goto cleanup;
1664 : }
1665 2615 : ANALYTICAL_COUNT_BRANCHES(OTHERS);
1666 : break;
1667 : }
1668 : }
1669 :
1670 159 : BATsetcount(r, cnt);
1671 159 : r->tnonil = true;
1672 159 : r->tnil = false;
1673 159 : cleanup:
1674 159 : bat_iterator_end(&pi);
1675 159 : bat_iterator_end(&oi);
1676 159 : bat_iterator_end(&bi);
1677 159 : bat_iterator_end(&si);
1678 159 : bat_iterator_end(&ei);
1679 159 : BBPreclaim(st);
1680 159 : return res;
1681 : }
1682 :
1683 : /* sum on fixed size integers */
1684 : #define ANALYTICAL_SUM_IMP_NUM_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2) \
1685 : do { \
1686 : TPE2 curval = TPE2##_nil; \
1687 : for (; k < i;) { \
1688 : j = k; \
1689 : do { \
1690 : if (!is_##TPE1##_nil(bp[k])) { \
1691 : if (is_##TPE2##_nil(curval)) \
1692 : curval = (TPE2) bp[k]; \
1693 : else \
1694 : ADD_WITH_CHECK(bp[k], curval, TPE2, curval, GDK_##TPE2##_max, goto calc_overflow); \
1695 : } \
1696 : k++; \
1697 : } while (k < i && !op[k]); \
1698 : for (; j < k; j++) \
1699 : rb[j] = curval; \
1700 : has_nils |= is_##TPE2##_nil(curval); \
1701 : } \
1702 : } while (0)
1703 :
1704 : #define ANALYTICAL_SUM_IMP_NUM_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2) \
1705 : do { \
1706 : TPE2 curval = TPE2##_nil; \
1707 : l = i - 1; \
1708 : for (j = l; ; j--) { \
1709 : if (!is_##TPE1##_nil(bp[j])) { \
1710 : if (is_##TPE2##_nil(curval)) \
1711 : curval = (TPE2) bp[j]; \
1712 : else \
1713 : ADD_WITH_CHECK(bp[j], curval, TPE2, curval, GDK_##TPE2##_max, goto calc_overflow); \
1714 : } \
1715 : if (op[j] || j == k) { \
1716 : for (; ; l--) { \
1717 : rb[l] = curval; \
1718 : if (l == j) \
1719 : break; \
1720 : } \
1721 : has_nils |= is_##TPE2##_nil(curval); \
1722 : if (j == k) \
1723 : break; \
1724 : l = j - 1; \
1725 : } \
1726 : } \
1727 : k = i; \
1728 : } while (0)
1729 :
1730 : #define ANALYTICAL_SUM_IMP_NUM_ALL_ROWS(TPE1, TPE2) \
1731 : do { \
1732 : TPE2 curval = TPE2##_nil; \
1733 : for (; j < i; j++) { \
1734 : TPE1 v = bp[j]; \
1735 : if (!is_##TPE1##_nil(v)) { \
1736 : if (is_##TPE2##_nil(curval)) \
1737 : curval = (TPE2) v; \
1738 : else \
1739 : ADDI_WITH_CHECK(v, curval, TPE2, curval, GDK_##TPE2##_max, goto calc_overflow); \
1740 : } \
1741 : } \
1742 : for (; k < i; k++) \
1743 : rb[k] = curval; \
1744 : has_nils |= is_##TPE2##_nil(curval); \
1745 : } while (0)
1746 :
1747 : #define ANALYTICAL_SUM_IMP_NUM_CURRENT_ROW(TPE1, TPE2) \
1748 : do { \
1749 : for (; k < i; k++) { \
1750 : TPE1 v = bp[k]; \
1751 : if (is_##TPE1##_nil(v)) { \
1752 : rb[k] = TPE2##_nil; \
1753 : has_nils = true; \
1754 : } else { \
1755 : rb[k] = (TPE2) v; \
1756 : } \
1757 : } \
1758 : } while (0)
1759 :
1760 : #define INIT_AGGREGATE_SUM(NOTHING1, TPE2, NOTHING2) \
1761 : do { \
1762 : computed = TPE2##_nil; \
1763 : } while (0)
1764 : #define COMPUTE_LEVEL0_SUM(X, TPE1, TPE2, NOTHING) \
1765 : do { \
1766 : TPE1 v = bp[j + X]; \
1767 : computed = is_##TPE1##_nil(v) ? TPE2##_nil : (TPE2) v; \
1768 : } while (0)
1769 : #define COMPUTE_LEVELN_SUM_NUM(VAL, NOTHING1, TPE2, NOTHING2) \
1770 : do { \
1771 : if (!is_##TPE2##_nil(VAL)) { \
1772 : if (is_##TPE2##_nil(computed)) \
1773 : computed = VAL; \
1774 : else \
1775 : ADD_WITH_CHECK(VAL, computed, TPE2, computed, GDK_##TPE2##_max, goto calc_overflow); \
1776 : } \
1777 : } while (0)
1778 : #define FINALIZE_AGGREGATE_SUM(NOTHING1, TPE2, NOTHING2) \
1779 : do { \
1780 : rb[k] = computed; \
1781 : has_nils |= is_##TPE2##_nil(computed); \
1782 : } while (0)
1783 : #define ANALYTICAL_SUM_IMP_NUM_OTHERS(TPE1, TPE2) \
1784 : do { \
1785 : oid ncount = i - k; \
1786 : if ((res = GDKrebuild_segment_tree(ncount, sizeof(TPE2), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
1787 : goto cleanup; \
1788 : populate_segment_tree(TPE2, ncount, INIT_AGGREGATE_SUM, COMPUTE_LEVEL0_SUM, COMPUTE_LEVELN_SUM_NUM, TPE1, TPE2, NOTHING); \
1789 : for (; k < i; k++) \
1790 : compute_on_segment_tree(TPE2, start[k] - j, end[k] - j, INIT_AGGREGATE_SUM, COMPUTE_LEVELN_SUM_NUM, FINALIZE_AGGREGATE_SUM, TPE1, TPE2, NOTHING); \
1791 : j = k; \
1792 : } while (0)
1793 :
1794 : /* sum on floating-points */
1795 : /* TODO go through a version of dofsum which returns the current partials for all the cases */
1796 : #define ANALYTICAL_SUM_IMP_FP_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2) ANALYTICAL_SUM_IMP_NUM_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2)
1797 : #define ANALYTICAL_SUM_IMP_FP_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2) ANALYTICAL_SUM_IMP_NUM_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2)
1798 :
1799 : #define ANALYTICAL_SUM_IMP_FP_ALL_ROWS(TPE1, TPE2) \
1800 : do { \
1801 : TPE1 *bs = bp + k; \
1802 : BUN parcel = i - k; \
1803 : TPE2 curval = TPE2##_nil; \
1804 : if (dofsum(bs, 0, \
1805 : &(struct canditer){.tpe = cand_dense, .ncand = parcel,}, \
1806 : &curval, 1, TYPE_##TPE1, \
1807 : TYPE_##TPE2, NULL, 0, 0, true, \
1808 : true) == BUN_NONE) { \
1809 : goto bailout; \
1810 : } \
1811 : for (; k < i; k++) \
1812 : rb[k] = curval; \
1813 : has_nils |= is_##TPE2##_nil(curval); \
1814 : } while (0)
1815 :
1816 : #define ANALYTICAL_SUM_IMP_FP_CURRENT_ROW(TPE1, TPE2) ANALYTICAL_SUM_IMP_NUM_CURRENT_ROW(TPE1, TPE2)
1817 : #define ANALYTICAL_SUM_IMP_FP_OTHERS(TPE1, TPE2) ANALYTICAL_SUM_IMP_NUM_OTHERS(TPE1, TPE2)
1818 :
1819 : #define ANALYTICAL_SUM_CALC(TPE1, TPE2, IMP) \
1820 : do { \
1821 : TPE1 *restrict bp = (TPE1*)bi.base; \
1822 : TPE2 *rb = (TPE2*)Tloc(r, 0); \
1823 : if (p) { \
1824 : while (i < cnt) { \
1825 : if (np[i]) { \
1826 : sum##TPE1##TPE2##IMP: \
1827 : IMP(TPE1, TPE2); \
1828 : } \
1829 : if (!last) \
1830 : i++; \
1831 : } \
1832 : } \
1833 : if (!last) { \
1834 : last = true; \
1835 : i = cnt; \
1836 : goto sum##TPE1##TPE2##IMP; \
1837 : } \
1838 : } while (0)
1839 :
1840 : #ifdef HAVE_HGE
1841 : #define ANALYTICAL_SUM_LIMIT(IMP) \
1842 : case TYPE_hge:{ \
1843 : switch (tp1) { \
1844 : case TYPE_bte: \
1845 : ANALYTICAL_SUM_CALC(bte, hge, ANALYTICAL_SUM_IMP_NUM_##IMP); \
1846 : break; \
1847 : case TYPE_sht: \
1848 : ANALYTICAL_SUM_CALC(sht, hge, ANALYTICAL_SUM_IMP_NUM_##IMP); \
1849 : break; \
1850 : case TYPE_int: \
1851 : ANALYTICAL_SUM_CALC(int, hge, ANALYTICAL_SUM_IMP_NUM_##IMP); \
1852 : break; \
1853 : case TYPE_lng: \
1854 : ANALYTICAL_SUM_CALC(lng, hge, ANALYTICAL_SUM_IMP_NUM_##IMP); \
1855 : break; \
1856 : case TYPE_hge: \
1857 : ANALYTICAL_SUM_CALC(hge, hge, ANALYTICAL_SUM_IMP_NUM_##IMP); \
1858 : break; \
1859 : default: \
1860 : goto nosupport; \
1861 : } \
1862 : break; \
1863 : }
1864 : #else
1865 : #define ANALYTICAL_SUM_LIMIT(IMP)
1866 : #endif
1867 :
1868 : #define ANALYTICAL_SUM_BRANCHES(IMP) \
1869 : do { \
1870 : switch (tp2) { \
1871 : case TYPE_bte:{ \
1872 : switch (tp1) { \
1873 : case TYPE_bte: \
1874 : ANALYTICAL_SUM_CALC(bte, bte, ANALYTICAL_SUM_IMP_NUM_##IMP); \
1875 : break; \
1876 : default: \
1877 : goto nosupport; \
1878 : } \
1879 : break; \
1880 : } \
1881 : case TYPE_sht:{ \
1882 : switch (tp1) { \
1883 : case TYPE_bte: \
1884 : ANALYTICAL_SUM_CALC(bte, sht, ANALYTICAL_SUM_IMP_NUM_##IMP); \
1885 : break; \
1886 : case TYPE_sht: \
1887 : ANALYTICAL_SUM_CALC(sht, sht, ANALYTICAL_SUM_IMP_NUM_##IMP); \
1888 : break; \
1889 : default: \
1890 : goto nosupport; \
1891 : } \
1892 : break; \
1893 : } \
1894 : case TYPE_int:{ \
1895 : switch (tp1) { \
1896 : case TYPE_bte: \
1897 : ANALYTICAL_SUM_CALC(bte, int, ANALYTICAL_SUM_IMP_NUM_##IMP); \
1898 : break; \
1899 : case TYPE_sht: \
1900 : ANALYTICAL_SUM_CALC(sht, int, ANALYTICAL_SUM_IMP_NUM_##IMP); \
1901 : break; \
1902 : case TYPE_int: \
1903 : ANALYTICAL_SUM_CALC(int, int, ANALYTICAL_SUM_IMP_NUM_##IMP); \
1904 : break; \
1905 : default: \
1906 : goto nosupport; \
1907 : } \
1908 : break; \
1909 : } \
1910 : case TYPE_lng:{ \
1911 : switch (tp1) { \
1912 : case TYPE_bte: \
1913 : ANALYTICAL_SUM_CALC(bte, lng, ANALYTICAL_SUM_IMP_NUM_##IMP); \
1914 : break; \
1915 : case TYPE_sht: \
1916 : ANALYTICAL_SUM_CALC(sht, lng, ANALYTICAL_SUM_IMP_NUM_##IMP); \
1917 : break; \
1918 : case TYPE_int: \
1919 : ANALYTICAL_SUM_CALC(int, lng, ANALYTICAL_SUM_IMP_NUM_##IMP); \
1920 : break; \
1921 : case TYPE_lng: \
1922 : ANALYTICAL_SUM_CALC(lng, lng, ANALYTICAL_SUM_IMP_NUM_##IMP); \
1923 : break; \
1924 : default: \
1925 : goto nosupport; \
1926 : } \
1927 : break; \
1928 : } \
1929 : ANALYTICAL_SUM_LIMIT(IMP) \
1930 : case TYPE_flt:{ \
1931 : switch (tp1) { \
1932 : case TYPE_flt: \
1933 : ANALYTICAL_SUM_CALC(flt, flt, ANALYTICAL_SUM_IMP_FP_##IMP); \
1934 : break; \
1935 : default: \
1936 : goto nosupport; \
1937 : } \
1938 : break; \
1939 : } \
1940 : case TYPE_dbl:{ \
1941 : switch (tp1) { \
1942 : case TYPE_flt: \
1943 : ANALYTICAL_SUM_CALC(flt, dbl, ANALYTICAL_SUM_IMP_FP_##IMP); \
1944 : break; \
1945 : case TYPE_dbl: \
1946 : ANALYTICAL_SUM_CALC(dbl, dbl, ANALYTICAL_SUM_IMP_FP_##IMP); \
1947 : break; \
1948 : default: \
1949 : goto nosupport; \
1950 : } \
1951 : break; \
1952 : } \
1953 : default: \
1954 : goto nosupport; \
1955 : } \
1956 : } while (0)
1957 :
1958 : gdk_return
1959 130 : GDKanalyticalsum(BAT *r, BAT *p, BAT *o, BAT *b, BAT *s, BAT *e, int tp1, int tp2, int frame_type)
1960 : {
1961 130 : BATiter pi = bat_iterator(p);
1962 130 : BATiter oi = bat_iterator(o);
1963 130 : BATiter bi = bat_iterator(b);
1964 130 : BATiter si = bat_iterator(s);
1965 130 : BATiter ei = bat_iterator(e);
1966 130 : bool has_nils = false, last = false;
1967 130 : oid i = 1, j = 0, k = 0, l = 0, cnt = BATcount(b), *restrict start = si.base, *restrict end = ei.base,
1968 130 : *levels_offset = NULL, nlevels = 0;
1969 130 : bit *np = pi.base, *op = oi.base;
1970 130 : void *segment_tree = NULL;
1971 130 : gdk_return res = GDK_SUCCEED;
1972 130 : BAT *st = NULL;
1973 :
1974 130 : assert(np == NULL || cnt == 0 || np[0] == 0);
1975 130 : if (cnt > 0) {
1976 128 : switch (frame_type) {
1977 47 : case 3: /* unbounded until current row */
1978 1251 : ANALYTICAL_SUM_BRANCHES(UNBOUNDED_TILL_CURRENT_ROW);
1979 : break;
1980 0 : case 4: /* current row until unbounded */
1981 0 : ANALYTICAL_SUM_BRANCHES(CURRENT_ROW_TILL_UNBOUNDED);
1982 : break;
1983 32 : case 5: /* all rows */
1984 19602 : ANALYTICAL_SUM_BRANCHES(ALL_ROWS);
1985 : break;
1986 2 : case 6: /* current row */
1987 33 : ANALYTICAL_SUM_BRANCHES(CURRENT_ROW);
1988 : break;
1989 47 : default:
1990 47 : if ((st = GDKinitialize_segment_tree()) == NULL) {
1991 0 : res = GDK_FAIL;
1992 0 : goto cleanup;
1993 : }
1994 9011931 : ANALYTICAL_SUM_BRANCHES(OTHERS);
1995 : break;
1996 : }
1997 : }
1998 :
1999 130 : BATsetcount(r, cnt);
2000 130 : r->tnonil = !has_nils;
2001 130 : r->tnil = has_nils;
2002 130 : goto cleanup; /* all these gotos seem confusing but it cleans up the ending of the operator */
2003 0 : bailout:
2004 0 : GDKerror("42000!error while calculating floating-point sum\n");
2005 0 : res = GDK_FAIL;
2006 0 : goto cleanup;
2007 0 : calc_overflow:
2008 0 : GDKerror("22003!overflow in calculation.\n");
2009 0 : res = GDK_FAIL;
2010 130 : cleanup:
2011 130 : bat_iterator_end(&pi);
2012 130 : bat_iterator_end(&oi);
2013 130 : bat_iterator_end(&bi);
2014 130 : bat_iterator_end(&si);
2015 130 : bat_iterator_end(&ei);
2016 130 : BBPreclaim(st);
2017 130 : return res;
2018 0 : nosupport:
2019 0 : GDKerror("42000!type combination (sum(%s)->%s) not supported.\n", ATOMname(tp1), ATOMname(tp2));
2020 0 : res = GDK_FAIL;
2021 0 : goto cleanup;
2022 : }
2023 :
2024 : /* product on integers */
2025 : #define PROD_NUM(TPE1, TPE2, TPE3, ARG) \
2026 : do { \
2027 : if (!is_##TPE1##_nil(ARG)) { \
2028 : if (is_##TPE2##_nil(curval)) \
2029 : curval = (TPE2) ARG; \
2030 : else \
2031 : MULI4_WITH_CHECK(ARG, curval, TPE2, curval, GDK_##TPE2##_max, TPE3, goto calc_overflow); \
2032 : } \
2033 : } while(0)
2034 :
2035 : #define ANALYTICAL_PROD_CALC_NUM_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2, TPE3) \
2036 : do { \
2037 : TPE2 curval = TPE2##_nil; \
2038 : for (; k < i;) { \
2039 : j = k; \
2040 : do { \
2041 : PROD_NUM(TPE1, TPE2, TPE3, bp[k]); \
2042 : k++; \
2043 : } while (k < i && !op[k]); \
2044 : for (; j < k; j++) \
2045 : rb[j] = curval; \
2046 : has_nils |= is_##TPE2##_nil(curval); \
2047 : } \
2048 : } while (0)
2049 :
2050 : #define ANALYTICAL_PROD_CALC_NUM_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2, TPE3) \
2051 : do { \
2052 : TPE2 curval = TPE2##_nil; \
2053 : l = i - 1; \
2054 : for (j = l; ; j--) { \
2055 : PROD_NUM(TPE1, TPE2, TPE3, bp[j]); \
2056 : if (op[j] || j == k) { \
2057 : for (; ; l--) { \
2058 : rb[l] = curval; \
2059 : if (l == j) \
2060 : break; \
2061 : } \
2062 : has_nils |= is_##TPE2##_nil(curval); \
2063 : if (j == k) \
2064 : break; \
2065 : l = j - 1; \
2066 : } \
2067 : } \
2068 : k = i; \
2069 : } while (0)
2070 :
2071 : #define ANALYTICAL_PROD_CALC_NUM_ALL_ROWS(TPE1, TPE2, TPE3) \
2072 : do { \
2073 : TPE2 curval = TPE2##_nil; \
2074 : for (; j < i; j++) { \
2075 : TPE1 v = bp[j]; \
2076 : PROD_NUM(TPE1, TPE2, TPE3, v); \
2077 : } \
2078 : for (; k < i; k++) \
2079 : rb[k] = curval; \
2080 : has_nils |= is_##TPE2##_nil(curval); \
2081 : } while (0)
2082 :
2083 : #define ANALYTICAL_PROD_CALC_NUM_CURRENT_ROW(TPE1, TPE2, TPE3) \
2084 : do { \
2085 : for (; k < i; k++) { \
2086 : TPE1 v = bp[k]; \
2087 : if (is_##TPE1##_nil(v)) { \
2088 : rb[k] = TPE2##_nil; \
2089 : has_nils = true; \
2090 : } else { \
2091 : rb[k] = (TPE2) v; \
2092 : } \
2093 : } \
2094 : } while (0)
2095 :
2096 : #define INIT_AGGREGATE_PROD(NOTHING1, TPE2, NOTHING2) \
2097 : do { \
2098 : computed = TPE2##_nil; \
2099 : } while (0)
2100 : #define COMPUTE_LEVEL0_PROD(X, TPE1, TPE2, NOTHING) \
2101 : do { \
2102 : TPE1 v = bp[j + X]; \
2103 : computed = is_##TPE1##_nil(v) ? TPE2##_nil : (TPE2) v; \
2104 : } while (0)
2105 : #define COMPUTE_LEVELN_PROD_NUM(VAL, NOTHING, TPE2, TPE3) \
2106 : do { \
2107 : if (!is_##TPE2##_nil(VAL)) { \
2108 : if (is_##TPE2##_nil(computed)) \
2109 : computed = VAL; \
2110 : else \
2111 : MULI4_WITH_CHECK(VAL, computed, TPE2, computed, GDK_##TPE2##_max, TPE3, goto calc_overflow); \
2112 : } \
2113 : } while (0)
2114 : #define FINALIZE_AGGREGATE_PROD(NOTHING1, TPE2, NOTHING2) \
2115 : do { \
2116 : rb[k] = computed; \
2117 : has_nils |= is_##TPE2##_nil(computed); \
2118 : } while (0)
2119 : #define ANALYTICAL_PROD_CALC_NUM_OTHERS(TPE1, TPE2, TPE3) \
2120 : do { \
2121 : oid ncount = i - k; \
2122 : if ((res = GDKrebuild_segment_tree(ncount, sizeof(TPE2), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
2123 : goto cleanup; \
2124 : populate_segment_tree(TPE2, ncount, INIT_AGGREGATE_PROD, COMPUTE_LEVEL0_PROD, COMPUTE_LEVELN_PROD_NUM, TPE1, TPE2, TPE3); \
2125 : for (; k < i; k++) \
2126 : compute_on_segment_tree(TPE2, start[k] - j, end[k] - j, INIT_AGGREGATE_PROD, COMPUTE_LEVELN_PROD_NUM, FINALIZE_AGGREGATE_PROD, TPE1, TPE2, TPE3); \
2127 : j = k; \
2128 : } while (0)
2129 :
2130 : /* product on integers while checking for overflows on the output */
2131 : #define PROD_NUM_LIMIT(TPE1, TPE2, REAL_IMP, ARG) \
2132 : do { \
2133 : if (!is_##TPE1##_nil(ARG)) { \
2134 : if (is_##TPE2##_nil(curval)) \
2135 : curval = (TPE2) ARG; \
2136 : else \
2137 : REAL_IMP(ARG, curval, curval, GDK_##TPE2##_max, goto calc_overflow); \
2138 : } \
2139 : } while(0)
2140 :
2141 : #define ANALYTICAL_PROD_CALC_NUM_LIMIT_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2, REAL_IMP) \
2142 : do { \
2143 : TPE2 curval = TPE2##_nil; \
2144 : for (; k < i;) { \
2145 : j = k; \
2146 : do { \
2147 : PROD_NUM_LIMIT(TPE1, TPE2, REAL_IMP, bp[k]); \
2148 : k++; \
2149 : } while (k < i && !op[k]); \
2150 : for (; j < k; j++) \
2151 : rb[j] = curval; \
2152 : has_nils |= is_##TPE2##_nil(curval); \
2153 : } \
2154 : } while (0)
2155 :
2156 : #define ANALYTICAL_PROD_CALC_NUM_LIMIT_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2, REAL_IMP) \
2157 : do { \
2158 : TPE2 curval = TPE2##_nil; \
2159 : l = i - 1; \
2160 : for (j = l; ; j--) { \
2161 : PROD_NUM_LIMIT(TPE1, TPE2, REAL_IMP, bp[j]); \
2162 : if (op[j] || j == k) { \
2163 : for (; ; l--) { \
2164 : rb[l] = curval; \
2165 : if (l == j) \
2166 : break; \
2167 : } \
2168 : has_nils |= is_##TPE2##_nil(curval); \
2169 : if (j == k) \
2170 : break; \
2171 : l = j - 1; \
2172 : } \
2173 : } \
2174 : k = i; \
2175 : } while (0)
2176 :
2177 : #define ANALYTICAL_PROD_CALC_NUM_LIMIT_ALL_ROWS(TPE1, TPE2, REAL_IMP) \
2178 : do { \
2179 : TPE2 curval = TPE2##_nil; \
2180 : for (; j < i; j++) { \
2181 : TPE1 v = bp[j]; \
2182 : PROD_NUM_LIMIT(TPE1, TPE2, REAL_IMP, v); \
2183 : } \
2184 : for (; k < i; k++) \
2185 : rb[k] = curval; \
2186 : has_nils |= is_##TPE2##_nil(curval); \
2187 : } while (0)
2188 :
2189 : #define ANALYTICAL_PROD_CALC_NUM_LIMIT_CURRENT_ROW(TPE1, TPE2, REAL_IMP) \
2190 : do { \
2191 : for (; k < i; k++) { \
2192 : TPE1 v = bp[k]; \
2193 : if (is_##TPE1##_nil(v)) { \
2194 : rb[k] = TPE2##_nil; \
2195 : has_nils = true; \
2196 : } else { \
2197 : rb[k] = (TPE2) v; \
2198 : } \
2199 : } \
2200 : } while (0)
2201 :
2202 : #define COMPUTE_LEVELN_PROD_NUM_LIMIT(VAL, NOTHING, TPE2, REAL_IMP) \
2203 : do { \
2204 : if (!is_##TPE2##_nil(VAL)) { \
2205 : if (is_##TPE2##_nil(computed)) \
2206 : computed = VAL; \
2207 : else \
2208 : REAL_IMP(VAL, computed, computed, GDK_##TPE2##_max, goto calc_overflow); \
2209 : } \
2210 : } while (0)
2211 : #define ANALYTICAL_PROD_CALC_NUM_LIMIT_OTHERS(TPE1, TPE2, REAL_IMP) \
2212 : do { \
2213 : oid ncount = i - k; \
2214 : if ((res = GDKrebuild_segment_tree(ncount, sizeof(TPE2), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
2215 : goto cleanup; \
2216 : populate_segment_tree(TPE2, ncount, INIT_AGGREGATE_PROD, COMPUTE_LEVEL0_PROD, COMPUTE_LEVELN_PROD_NUM_LIMIT, TPE1, TPE2, REAL_IMP); \
2217 : for (; k < i; k++) \
2218 : compute_on_segment_tree(TPE2, start[k] - j, end[k] - j, INIT_AGGREGATE_PROD, COMPUTE_LEVELN_PROD_NUM_LIMIT, FINALIZE_AGGREGATE_PROD, TPE1, TPE2, REAL_IMP); \
2219 : j = k; \
2220 : } while (0)
2221 :
2222 : /* product on floating-points */
2223 : #define PROD_FP(TPE1, TPE2, ARG) \
2224 : do { \
2225 : if (!is_##TPE1##_nil(ARG)) { \
2226 : if (is_##TPE2##_nil(curval)) { \
2227 : curval = (TPE2) ARG; \
2228 : } else if (ABSOLUTE(curval) > 1 && GDK_##TPE2##_max / ABSOLUTE(ARG) < ABSOLUTE(curval)) { \
2229 : goto calc_overflow; \
2230 : } else { \
2231 : curval *= ARG; \
2232 : } \
2233 : } \
2234 : } while(0)
2235 :
2236 : #define ANALYTICAL_PROD_CALC_FP_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2, ARG3) /* ARG3 is ignored here */ \
2237 : do { \
2238 : TPE2 curval = TPE2##_nil; \
2239 : for (; k < i;) { \
2240 : j = k; \
2241 : do { \
2242 : PROD_FP(TPE1, TPE2, bp[k]); \
2243 : k++; \
2244 : } while (k < i && !op[k]); \
2245 : for (; j < k; j++) \
2246 : rb[j] = curval; \
2247 : has_nils |= is_##TPE2##_nil(curval); \
2248 : } \
2249 : } while (0)
2250 :
2251 : #define ANALYTICAL_PROD_CALC_FP_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2, ARG3) /* ARG3 is ignored here */ \
2252 : do { \
2253 : TPE2 curval = TPE2##_nil; \
2254 : l = i - 1; \
2255 : for (j = l; ; j--) { \
2256 : PROD_FP(TPE1, TPE2, bp[j]); \
2257 : if (op[j] || j == k) { \
2258 : for (; ; l--) { \
2259 : rb[l] = curval; \
2260 : if (l == j) \
2261 : break; \
2262 : } \
2263 : has_nils |= is_##TPE2##_nil(curval); \
2264 : if (j == k) \
2265 : break; \
2266 : l = j - 1; \
2267 : } \
2268 : } \
2269 : k = i; \
2270 : } while (0)
2271 :
2272 : #define ANALYTICAL_PROD_CALC_FP_ALL_ROWS(TPE1, TPE2, ARG3) /* ARG3 is ignored here */ \
2273 : do { \
2274 : TPE2 curval = TPE2##_nil; \
2275 : for (; j < i; j++) { \
2276 : TPE1 v = bp[j]; \
2277 : PROD_FP(TPE1, TPE2, v); \
2278 : } \
2279 : for (; k < i; k++) \
2280 : rb[k] = curval; \
2281 : has_nils |= is_##TPE2##_nil(curval); \
2282 : } while (0)
2283 :
2284 : #define ANALYTICAL_PROD_CALC_FP_CURRENT_ROW(TPE1, TPE2, ARG3) /* ARG3 is ignored here */ \
2285 : do { \
2286 : for (; k < i; k++) { \
2287 : TPE1 v = bp[k]; \
2288 : if (is_##TPE1##_nil(v)) { \
2289 : rb[k] = TPE2##_nil; \
2290 : has_nils = true; \
2291 : } else { \
2292 : rb[k] = (TPE2) v; \
2293 : } \
2294 : } \
2295 : } while (0)
2296 :
2297 : #define COMPUTE_LEVELN_PROD_FP(VAL, NOTHING1, TPE2, NOTHING2) \
2298 : do { \
2299 : if (!is_##TPE2##_nil(VAL)) { \
2300 : if (is_##TPE2##_nil(computed)) { \
2301 : computed = VAL; \
2302 : } else if (ABSOLUTE(computed) > 1 && GDK_##TPE2##_max / ABSOLUTE(VAL) < ABSOLUTE(computed)) { \
2303 : goto calc_overflow; \
2304 : } else { \
2305 : computed *= VAL; \
2306 : } \
2307 : } \
2308 : } while (0)
2309 : #define ANALYTICAL_PROD_CALC_FP_OTHERS(TPE1, TPE2, ARG3) /* ARG3 is ignored here */ \
2310 : do { \
2311 : oid ncount = i - k; \
2312 : if ((res = GDKrebuild_segment_tree(ncount, sizeof(TPE2), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
2313 : goto cleanup; \
2314 : populate_segment_tree(TPE2, ncount, INIT_AGGREGATE_PROD, COMPUTE_LEVEL0_PROD, COMPUTE_LEVELN_PROD_FP, TPE1, TPE2, ARG3); \
2315 : for (; k < i; k++) \
2316 : compute_on_segment_tree(TPE2, start[k] - j, end[k] - j, INIT_AGGREGATE_PROD, COMPUTE_LEVELN_PROD_FP, FINALIZE_AGGREGATE_PROD, TPE1, TPE2, ARG3); \
2317 : j = k; \
2318 : } while (0)
2319 :
2320 : #define ANALYTICAL_PROD_CALC_NUM_PARTITIONS(TPE1, TPE2, TPE3_OR_REAL_IMP, IMP) \
2321 : do { \
2322 : TPE1 *restrict bp = (TPE1*)bi.base; \
2323 : TPE2 *rb = (TPE2*)Tloc(r, 0); \
2324 : if (p) { \
2325 : while (i < cnt) { \
2326 : if (np[i]) { \
2327 : prod##TPE1##TPE2##IMP: \
2328 : IMP(TPE1, TPE2, TPE3_OR_REAL_IMP); \
2329 : } \
2330 : if (!last) \
2331 : i++; \
2332 : } \
2333 : } \
2334 : if (!last) { \
2335 : last = true; \
2336 : i = cnt; \
2337 : goto prod##TPE1##TPE2##IMP; \
2338 : } \
2339 : } while (0)
2340 :
2341 : #ifdef HAVE_HGE
2342 : #define ANALYTICAL_PROD_LIMIT(IMP) \
2343 : case TYPE_lng:{ \
2344 : switch (tp1) { \
2345 : case TYPE_bte: \
2346 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, lng, hge, ANALYTICAL_PROD_CALC_NUM_##IMP); \
2347 : break; \
2348 : case TYPE_sht: \
2349 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(sht, lng, hge, ANALYTICAL_PROD_CALC_NUM_##IMP); \
2350 : break; \
2351 : case TYPE_int: \
2352 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(int, lng, hge, ANALYTICAL_PROD_CALC_NUM_##IMP); \
2353 : break; \
2354 : case TYPE_lng: \
2355 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(lng, lng, hge, ANALYTICAL_PROD_CALC_NUM_##IMP); \
2356 : break; \
2357 : default: \
2358 : goto nosupport; \
2359 : } \
2360 : break; \
2361 : } \
2362 : case TYPE_hge:{ \
2363 : switch (tp1) { \
2364 : case TYPE_bte: \
2365 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, hge, HGEMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
2366 : break; \
2367 : case TYPE_sht: \
2368 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(sht, hge, HGEMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
2369 : break; \
2370 : case TYPE_int: \
2371 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(int, hge, HGEMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
2372 : break; \
2373 : case TYPE_lng: \
2374 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(lng, hge, HGEMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
2375 : break; \
2376 : case TYPE_hge: \
2377 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(hge, hge, HGEMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
2378 : break; \
2379 : default: \
2380 : goto nosupport; \
2381 : } \
2382 : break; \
2383 : }
2384 : #else
2385 : #define ANALYTICAL_PROD_LIMIT(IMP) \
2386 : case TYPE_lng:{ \
2387 : switch (tp1) { \
2388 : case TYPE_bte: \
2389 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, lng, LNGMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
2390 : break; \
2391 : case TYPE_sht: \
2392 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(sht, lng, LNGMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
2393 : break; \
2394 : case TYPE_int: \
2395 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(int, lng, LNGMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
2396 : break; \
2397 : case TYPE_lng: \
2398 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(lng, lng, LNGMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
2399 : break; \
2400 : default: \
2401 : goto nosupport; \
2402 : } \
2403 : break; \
2404 : }
2405 : #endif
2406 :
2407 : #define ANALYTICAL_PROD_BRANCHES(IMP) \
2408 : do { \
2409 : switch (tp2) { \
2410 : case TYPE_bte:{ \
2411 : switch (tp1) { \
2412 : case TYPE_bte: \
2413 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, bte, sht, ANALYTICAL_PROD_CALC_NUM_##IMP); \
2414 : break; \
2415 : default: \
2416 : goto nosupport; \
2417 : } \
2418 : break; \
2419 : } \
2420 : case TYPE_sht:{ \
2421 : switch (tp1) { \
2422 : case TYPE_bte: \
2423 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, sht, int, ANALYTICAL_PROD_CALC_NUM_##IMP); \
2424 : break; \
2425 : case TYPE_sht: \
2426 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(sht, sht, int, ANALYTICAL_PROD_CALC_NUM_##IMP); \
2427 : break; \
2428 : default: \
2429 : goto nosupport; \
2430 : } \
2431 : break; \
2432 : } \
2433 : case TYPE_int:{ \
2434 : switch (tp1) { \
2435 : case TYPE_bte: \
2436 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, int, lng, ANALYTICAL_PROD_CALC_NUM_##IMP); \
2437 : break; \
2438 : case TYPE_sht: \
2439 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(sht, int, lng, ANALYTICAL_PROD_CALC_NUM_##IMP); \
2440 : break; \
2441 : case TYPE_int: \
2442 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(int, int, lng, ANALYTICAL_PROD_CALC_NUM_##IMP); \
2443 : break; \
2444 : default: \
2445 : goto nosupport; \
2446 : } \
2447 : break; \
2448 : } \
2449 : ANALYTICAL_PROD_LIMIT(IMP) \
2450 : case TYPE_flt:{ \
2451 : switch (tp1) { \
2452 : case TYPE_flt: \
2453 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(flt, flt, ;, ANALYTICAL_PROD_CALC_FP_##IMP); \
2454 : break; \
2455 : default: \
2456 : goto nosupport; \
2457 : } \
2458 : break; \
2459 : } \
2460 : case TYPE_dbl:{ \
2461 : switch (tp1) { \
2462 : case TYPE_flt: \
2463 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(flt, dbl, ;, ANALYTICAL_PROD_CALC_FP_##IMP); \
2464 : break; \
2465 : case TYPE_dbl: \
2466 : ANALYTICAL_PROD_CALC_NUM_PARTITIONS(dbl, dbl, ;, ANALYTICAL_PROD_CALC_FP_##IMP); \
2467 : break; \
2468 : default: \
2469 : goto nosupport; \
2470 : } \
2471 : break; \
2472 : } \
2473 : default: \
2474 : goto nosupport; \
2475 : } \
2476 : } while (0)
2477 :
2478 : gdk_return
2479 31 : GDKanalyticalprod(BAT *r, BAT *p, BAT *o, BAT *b, BAT *s, BAT *e, int tp1, int tp2, int frame_type)
2480 : {
2481 31 : BATiter pi = bat_iterator(p);
2482 31 : BATiter oi = bat_iterator(o);
2483 31 : BATiter bi = bat_iterator(b);
2484 31 : BATiter si = bat_iterator(s);
2485 31 : BATiter ei = bat_iterator(e);
2486 31 : bool has_nils = false, last = false;
2487 31 : oid i = 1, j = 0, k = 0, l = 0, cnt = BATcount(b), *restrict start = si.base, *restrict end = ei.base,
2488 31 : *levels_offset = NULL, nlevels = 0;
2489 31 : bit *np = pi.base, *op = oi.base;
2490 31 : void *segment_tree = NULL;
2491 31 : gdk_return res = GDK_SUCCEED;
2492 31 : BAT *st = NULL;
2493 :
2494 31 : assert(np == NULL || cnt == 0 || np[0] == 0);
2495 31 : if (cnt > 0) {
2496 31 : switch (frame_type) {
2497 12 : case 3: /* unbounded until current row */
2498 394 : ANALYTICAL_PROD_BRANCHES(UNBOUNDED_TILL_CURRENT_ROW);
2499 : break;
2500 0 : case 4: /* current row until unbounded */
2501 0 : ANALYTICAL_PROD_BRANCHES(CURRENT_ROW_TILL_UNBOUNDED);
2502 : break;
2503 7 : case 5: /* all rows */
2504 187 : ANALYTICAL_PROD_BRANCHES(ALL_ROWS);
2505 : break;
2506 0 : case 6: /* current row */
2507 0 : ANALYTICAL_PROD_BRANCHES(CURRENT_ROW);
2508 : break;
2509 12 : default:
2510 12 : if ((st = GDKinitialize_segment_tree()) == NULL) {
2511 0 : res = GDK_FAIL;
2512 0 : goto cleanup;
2513 : }
2514 1070 : ANALYTICAL_PROD_BRANCHES(OTHERS);
2515 : break;
2516 : }
2517 : }
2518 :
2519 31 : BATsetcount(r, cnt);
2520 31 : r->tnonil = !has_nils;
2521 31 : r->tnil = has_nils;
2522 31 : goto cleanup; /* all these gotos seem confusing but it cleans up the ending of the operator */
2523 0 : calc_overflow:
2524 0 : GDKerror("22003!overflow in calculation.\n");
2525 0 : res = GDK_FAIL;
2526 31 : cleanup:
2527 31 : bat_iterator_end(&pi);
2528 31 : bat_iterator_end(&oi);
2529 31 : bat_iterator_end(&bi);
2530 31 : bat_iterator_end(&si);
2531 31 : bat_iterator_end(&ei);
2532 31 : BBPreclaim(st);
2533 31 : return res;
2534 0 : nosupport:
2535 0 : GDKerror("42000!type combination (prod(%s)->%s) not supported.\n", ATOMname(tp1), ATOMname(tp2));
2536 0 : res = GDK_FAIL;
2537 0 : goto cleanup;
2538 : }
|