/* * @- * The operator below is only working for a very limited * case. It also re-uses oids, which may become a semantic * problem quickly. */ str DCdeleteUpperSlice(int *ret, int *bid, int *pos) { BAT *b; int *readerT, *writerT; BUN size, i; (void) ret; if ((b = BATdescriptor(*bid)) == NULL) throw(MAL, "dc.deleteUpperSlice", "Cannot access input BAT"); /* check for a failure */ assert(b != NULL); /* remove Hashes etc */ if (b->H->hash) HASHremove(b); if (b->T->hash) HASHremove(BATmirror(b)); size = BATcount(b); writerT = (int *) Tloc(b, BUNfirst(b)); readerT = (int *) Tloc(b, BUNfirst(b)) + *pos; for (i = *pos; i < size; i++) *writerT++ = *readerT++; b->batInserted -= *pos; BATsetcount(b, (BUN) (writerT - (int *) Tloc(b, BUNfirst(b)))); BBPunfix(*bid); b->batDirty = TRUE; return MAL_SUCCEED; }
static BAT * MATproject_hge( BAT *map, BAT **bats, int len, int ttpe ) { BAT *res; int i; BUN j, cnt = BATcount(map); hge *resT, **batsT; bte *mapT; res = BATnew(TYPE_void, ttpe, cnt, TRANSIENT); batsT = (hge**)GDKmalloc(sizeof(hge*) * len); if (res == NULL || batsT == NULL) { if (res) BBPreclaim(res); if (batsT) GDKfree(batsT); return NULL; } BATseqbase(res, map->hseqbase); resT = (hge*)Tloc(res, 0); mapT = (bte*)Tloc(map, 0); for (i=0; i<len; i++) batsT[i] = (hge*)Tloc(bats[i], 0); for (j=0; j<cnt; j++) resT[j] = *batsT[mapT[j]]++; BATsetcount(res, j); res->hrevsorted = j <= 1; GDKfree(batsT); return res; }
str DCselectInsert(int *ret, int *res, int *bid, lng *low, lng *hgh) { BAT *b, *r; lng *readerH, *writerH; lng *readerT, *writerT; BUN size, i; (void) ret; if ((b = BATdescriptor(*bid)) == NULL) throw(MAL, "dc.selectInsert", "Cannot access input BAT"); if ((r = BATdescriptor(*res)) == NULL) throw(MAL, "dc.selectInsert", "Cannot access result BAT"); size = BATcount(b); if (size > BATcapacity(r) - BATcount(r)) { BUN ncap; BUN grows; BUN needed = size - (BATcapacity(r) - BATcount(r)); ncap = BATcapacity(r) + needed; grows = BATgrows(r); if (ncap > grows) grows = ncap; if (BATextend(r, grows) == NULL) throw(MAL, "dc.selectInsert", "Failed to make room for the new values"); } /*printf("in dc.selectInsert size is "OIDFMT,size);*/ writerH = (lng *) Hloc(r, BUNfirst(r)); writerT = (lng *) Tloc(r, BUNfirst(r)); readerH = (lng *) Hloc(b, BUNfirst(b)); readerT = (lng *) Tloc(b, BUNfirst(b)); for (i = 0; i < size; i++) { if (*readerT >= *low && *readerT <= *hgh) { *writerH = *readerH; *writerT = *readerT; writerH++; writerT++; } readerH++; readerT++; } BATsetcount(r, (BUN) (writerT - (lng *) Tloc(r, BUNfirst(r)))); BBPunfix(*bid); BBPunfix(*res); return MAL_SUCCEED; }
/* * @- * The operator below is only working for a very limited cases. */ str DCreplaceTailBasedOnHead(int *ret, int *res, int *bid) { BAT *b, *r; oid *readerH_b; int *writerT_r, *readerT_b; BUN size_b, size_r, i; (void) ret; if ((b = BATdescriptor(*bid)) == NULL) throw(MAL, "dc.replaceTailBasedOnHead", "Cannot access input BAT"); /* check for a failure */ assert(b != NULL); if ((r = BATdescriptor(*res)) == NULL) throw(MAL, "dc.replaceTailBasedOnHead", "Cannot access result BAT"); /* check for a failure */ assert(r != NULL); /* remove Hashes etc */ if (r->H->hash) HASHremove(r); if (r->T->hash) HASHremove(BATmirror(r)); size_r = BATcount(r); size_b = BATcount(b); if ((b->htype == TYPE_void) && (size_b == size_r)) { writerT_r = (int *) Tloc(r, BUNfirst(r)); readerT_b = (int *) Tloc(b, BUNfirst(b)); for (i = 0; i < size_r; i++) { *writerT_r = *readerT_b; writerT_r++; readerT_b++; } } else if ((b->htype != TYPE_void) && (size_b < size_r)) { readerH_b = (oid *) Hloc(b, BUNfirst(b)); readerT_b = (int *) Tloc(b, BUNfirst(b)); for (i = 0; i < size_b; i++) { writerT_r = (int *) Tloc(r, BUNfirst(r)) + *readerH_b; *writerT_r = *readerT_b; readerH_b++; readerT_b++; } } BBPunfix(*bid); BBPunfix(*res); r->batDirty = TRUE; return MAL_SUCCEED; }
static BAT * MATsort_bte( BAT **map, BAT **bats, int len, BUN cnt, int rev ) { BAT *res; int i; bte *resT, **batsT, *in; bte *mapT; BUN len1, len2; bte *map_in = NULL; res = BATnew(TYPE_void, bats[0]->ttype, cnt, TRANSIENT); *map = BATnew(TYPE_void, TYPE_bte, cnt, TRANSIENT); if (res == NULL || *map == NULL) { BBPreclaim(res); BBPreclaim(*map); *map = NULL; return NULL; } BATseqbase(res, 0); BATseqbase(*map, 0); resT = (bte*)Tloc(res, 0); mapT = (bte*)Tloc(*map, 0); batsT = (bte**)GDKmalloc(sizeof(bte*) * len); for (i=0; i<len; i++) batsT[i] = (bte*)Tloc(bats[i], 0); /* merge */ in = batsT[0]; len1 = BATcount(bats[0]); map_in = NULL; /* TODO: change into a tree version */ for (i=1; i<len; i++) { len2 = BATcount(bats[i]); if (rev) { MATsortloop_bte_rev( resT+cnt-len1-len2, mapT+cnt-len1-len2, in, map_in, len1, batsT[i], i, len2); } else { MATsortloop_bte_( resT+cnt-len1-len2, mapT+cnt-len1-len2, in, map_in, len1, batsT[i], i, len2); } in = resT+cnt-len1-len2; map_in = mapT+cnt-len1-len2; len1 += len2; } BATsetcount(res, len1); BATsetcount(*map, len1); res->hrevsorted = len1 <= 1; (*map)->hrevsorted = len1 <= 1; GDKfree(batsT); return res; }
static BAT * MATproject_any( BAT *map, BAT **bats, int len ) { BAT *res; int i; BUN j, cnt = BATcount(map); BATiter *bats_i; BUN *batsT; bte *mapT; res = BATnew(TYPE_void, bats[0]->ttype, cnt, TRANSIENT); batsT = (BUN*)GDKmalloc(sizeof(BUN) * len); bats_i = (BATiter*)GDKmalloc(sizeof(BATiter) * len); if (res == NULL || batsT == NULL || bats_i == NULL) { if (res) BBPreclaim(res); if (batsT) GDKfree(batsT); if (bats_i) GDKfree(bats_i); return NULL; } BATseqbase(res, map->hseqbase); mapT = (bte*)Tloc(map, 0); for (i=0; i<len; i++) { batsT[i] = 0; bats_i[i] = bat_iterator(bats[i]); } for (j=0; j<cnt; j++) BUNappend(res, BUNtail(bats_i[mapT[j]], batsT[mapT[j]]++), FALSE); GDKfree(batsT); GDKfree(bats_i); return res; }
static BAT * MATsort_any( BAT **map, BAT **bats, int len, BUN cnt, int rev ) { BAT *res = 0, *in; int i; bte *mapT; BUN len1, len2; bte *map_in = NULL; *map = BATnew(TYPE_void, TYPE_bte, cnt, TRANSIENT); if (*map == NULL) return NULL; BATseqbase(*map, 0); mapT = (bte*)Tloc(*map, 0); /* merge */ /* TODO: change into a tree version */ in = bats[0]; len1 = BATcount(in); for (i=1; i<len; i++) { len2 = BATcount(bats[i]); if (rev) { res = MATsortloop_rev( mapT+cnt-len1-len2, in, map_in, len1, bats[i], i, len2); } else { res = MATsortloop_( mapT+cnt-len1-len2, in, map_in, len1, bats[i], i, len2); } if (i != 1) BBPunfix(in->batCacheid); if (res == NULL) return NULL; in = res; map_in = mapT+cnt-len1-len2; len1 += len2; } BATsetcount(*map, len1); (*map)->hrevsorted = len1 <= 1; return res; }
str MKEYbathash(bat *res, const bat *bid) { BAT *b, *dst; wrd *r; BUN n; if ((b = BATdescriptor(*bid)) == NULL) throw(SQL, "mkey.bathash", RUNTIME_OBJECT_MISSING); assert(BAThvoid(b) || BAThrestricted(b)); n = BATcount(b); dst = BATnew(TYPE_void, TYPE_wrd, n, TRANSIENT); if (dst == NULL) { BBPunfix(b->batCacheid); throw(SQL, "mkey.bathash", MAL_MALLOC_FAIL); } BATseqbase(dst, b->hseqbase); BATsetcount(dst, n); r = (wrd *) Tloc(dst, BUNfirst(dst)); switch (ATOMstorage(b->ttype)) { case TYPE_void: { oid o = b->tseqbase; if (o == oid_nil) while (n-- > 0) *r++ = wrd_nil; else while (n-- > 0) *r++ = (wrd) o++; break; } case TYPE_bte: { bte *v = (bte *) Tloc(b, BUNfirst(b)); while (n-- > 0) { *r++ = MKEYHASH_bte(v); v++; } break; } case TYPE_sht: { sht *v = (sht *) Tloc(b, BUNfirst(b)); while (n-- > 0) { *r++ = MKEYHASH_sht(v); v++; } break; } case TYPE_int: case TYPE_flt: { int *v = (int *) Tloc(b, BUNfirst(b)); while (n-- > 0) { *r++ = MKEYHASH_int(v); v++; } break; } case TYPE_lng: case TYPE_dbl: { lng *v = (lng *) Tloc(b, BUNfirst(b)); while (n-- > 0) { *r++ = MKEYHASH_lng(v); v++; } break; } #ifdef HAVE_HGE case TYPE_hge: { hge *v = (hge *) Tloc(b, BUNfirst(b)); while (n-- > 0) { *r++ = MKEYHASH_hge(v); v++; } break; } #endif default: { BATiter bi = bat_iterator(b); BUN (*hash)(const void *) = BATatoms[b->ttype].atomHash; int (*cmp)(const void *, const void *) = ATOMcompare(b->ttype); void *nil = ATOMnilptr(b->ttype); BUN i; const void *v; BATloop(b, i, n) { v = BUNtail(bi, i); if ((*cmp)(v, nil) == 0) *r++ = wrd_nil; else *r++ = (wrd) (*hash)(v); } break; } }
/* BATsample implements sampling for void headed BATs */ BAT * BATsample(BAT *b, BUN n) { BAT *bn; BUN cnt, slen; BUN rescnt; struct oidtreenode *tree = NULL; BATcheck(b, "BATsample", NULL); assert(BAThdense(b)); ERRORcheck(n > BUN_MAX, "BATsample: sample size larger than BUN_MAX\n", NULL); ALGODEBUG fprintf(stderr, "#BATsample: sample " BUNFMT " elements.\n", n); cnt = BATcount(b); /* empty sample size */ if (n == 0) { bn = BATnew(TYPE_void, TYPE_void, 0, TRANSIENT); if (bn == NULL) { GDKerror("BATsample: memory allocation error"); return NULL; } BATsetcount(bn, 0); BATseqbase(bn, 0); BATseqbase(BATmirror(bn), 0); /* sample size is larger than the input BAT, return all oids */ } else if (cnt <= n) { bn = BATnew(TYPE_void, TYPE_void, cnt, TRANSIENT); if (bn == NULL) { GDKerror("BATsample: memory allocation error"); return NULL; } BATsetcount(bn, cnt); BATseqbase(bn, 0); BATseqbase(BATmirror(bn), b->H->seq); } else { oid minoid = b->hseqbase; oid maxoid = b->hseqbase + cnt; /* if someone samples more than half of our tree, we * do the antiset */ bit antiset = n > cnt / 2; slen = n; if (antiset) n = cnt - n; tree = GDKmalloc(n * sizeof(struct oidtreenode)); if (tree == NULL) { GDKerror("#BATsample: memory allocation error"); return NULL; } bn = BATnew(TYPE_void, TYPE_oid, slen, TRANSIENT); if (bn == NULL) { GDKfree(tree); GDKerror("#BATsample: memory allocation error"); return NULL; } /* while we do not have enough sample OIDs yet */ for (rescnt = 0; rescnt < n; rescnt++) { oid candoid; do { /* generate a new random OID */ candoid = (oid) (minoid + DRAND * (maxoid - minoid)); /* if that candidate OID was already * generated, try again */ } while (!OIDTreeMaybeInsert(tree, candoid, rescnt)); } if (!antiset) { OIDTreeToBAT(tree, bn); } else { OIDTreeToBATAntiset(tree, bn, minoid, maxoid); } GDKfree(tree); BATsetcount(bn, slen); bn->trevsorted = bn->batCount <= 1; bn->tsorted = 1; bn->tkey = 1; bn->tdense = bn->batCount <= 1; if (bn->batCount == 1) bn->tseqbase = *(oid *) Tloc(bn, BUNfirst(bn)); bn->hdense = 1; bn->hseqbase = 0; bn->hkey = 1; bn->hrevsorted = bn->batCount <= 1; bn->hsorted = 1; } return bn; }
static str AGGRsubgroupedExt(bat *retval1, bat *retval2, bat *bid, bat *gid, bat *eid, bat *sid, int skip_nils, int abort_on_error, int tp, BAT *(*grpfunc1)(BAT *, BAT *, BAT *, BAT *, int, int, int), gdk_return (*grpfunc2)(BAT **, BAT **, BAT *, BAT *, BAT *, BAT *, int, int, int), BAT *(*quantilefunc)(BAT *, BAT *, BAT *, BAT *, int, double, int, int), bat *quantile, const char *malfunc) { BAT *b, *g, *e, *s, *bn = NULL, *cnts, *q = NULL; double qvalue; /* one of grpfunc1, grpfunc2 and quantilefunc is non-NULL and the others are */ assert((grpfunc1 && grpfunc2 == NULL && quantilefunc == NULL) || (grpfunc1 == NULL && grpfunc2 && quantilefunc == NULL) || (grpfunc1 == NULL && grpfunc2 == NULL && quantilefunc) ); /* if retval2 is non-NULL, we must have grpfunc2 */ assert(retval2 == NULL || grpfunc2 != NULL); b = BATdescriptor(*bid); g = gid ? BATdescriptor(*gid) : NULL; e = eid ? BATdescriptor(*eid) : NULL; q = quantile ? BATdescriptor(*quantile) : NULL; if (b == NULL || (gid != NULL && g == NULL) || (eid != NULL && e == NULL)) { if (b) BBPreleaseref(b->batCacheid); if (g) BBPreleaseref(g->batCacheid); if (e) BBPreleaseref(e->batCacheid); throw(MAL, malfunc, RUNTIME_OBJECT_MISSING); } if (tp == TYPE_any && (grpfunc1 == BATgroupmedian || quantilefunc == BATgroupquantile)) tp = b->ttype; if (sid) { s = BATdescriptor(*sid); if (s == NULL) { BBPreleaseref(b->batCacheid); if (g) BBPreleaseref(g->batCacheid); if (e) BBPreleaseref(e->batCacheid); throw(MAL, malfunc, RUNTIME_OBJECT_MISSING); } } else { if (!BAThdense(b)) { /* XXX backward compatibility code: ignore non-dense head, but * only if no candidate list */ s = BATmirror(BATmark(BATmirror(b), 0)); BBPreleaseref(b->batCacheid); b = s; } s = NULL; } if (grpfunc1) bn = (*grpfunc1)(b, g, e, s, tp, skip_nils, abort_on_error); if (quantilefunc) { assert(BATcount(q)>0); assert(q->ttype == TYPE_dbl); qvalue = ((const double *)Tloc(q, BUNfirst(q)))[0]; if (qvalue < 0|| qvalue > 1) { char *s; s = createException(MAL, malfunc, "quantile value of %f is not in range [0,1]", qvalue); return s; } bn = (*quantilefunc)(b, g, e, s, tp, qvalue, skip_nils, abort_on_error); } if (grpfunc2 && (*grpfunc2)(&bn, retval2 ? &cnts : NULL, b, g, e, s, tp, skip_nils, abort_on_error) == GDK_FAIL) bn = NULL; BBPreleaseref(b->batCacheid); if (g) BBPreleaseref(g->batCacheid); if (e) BBPreleaseref(e->batCacheid); if (s) BBPreleaseref(s->batCacheid); if (bn == NULL) { char *errbuf = GDKerrbuf; char *s; if (errbuf && *errbuf) { if (strncmp(errbuf, "!ERROR: ", 8) == 0) errbuf += 8; if (strchr(errbuf, '!') == errbuf + 5) { s = createException(MAL, malfunc, "%s", errbuf); } else if ((s = strchr(errbuf, ':')) != NULL && s[1] == ' ') { s = createException(MAL, malfunc, "%s", s + 2); } else { s = createException(MAL, malfunc, "%s", errbuf); } *GDKerrbuf = 0; return s; } throw(MAL, malfunc, OPERATION_FAILED); } *retval1 = bn->batCacheid; BBPkeepref(bn->batCacheid); if (retval2) { *retval2 = cnts->batCacheid; BBPkeepref(cnts->batCacheid); } return MAL_SUCCEED; }
/* * grouped aggregates */ static str AGGRgrouped(bat *retval1, bat *retval2, BAT *b, BAT *g, BAT *e, int tp, BAT *(*grpfunc1)(BAT *, BAT *, BAT *, BAT *, int, int, int), gdk_return (*grpfunc2)(BAT **, BAT **, BAT *, BAT *, BAT *, BAT *, int, int, int), BAT *(*quantilefunc)(BAT *, BAT *, BAT *, BAT *, int, double, int, int), BAT *quantile, int skip_nils, const char *malfunc) { BAT *bn, *cnts = NULL, *t, *map; double qvalue; /* one of grpfunc1, grpfunc2 and quantilefunc is non-NULL and the others are */ assert((grpfunc1 != NULL && grpfunc2 == NULL && quantilefunc == NULL) || (grpfunc1 == NULL && grpfunc2 != NULL && quantilefunc == NULL) || (grpfunc1 == NULL && grpfunc2 == NULL && quantilefunc != NULL) ); /* if retval2 is non-NULL, we must have grpfunc2 */ assert(retval2 == NULL || grpfunc2 != NULL); assert(quantile == NULL || quantilefunc != NULL); if (b == NULL || g == NULL || e == NULL) { if (b) BBPreleaseref(b->batCacheid); if (g) BBPreleaseref(g->batCacheid); if (e) BBPreleaseref(e->batCacheid); throw(MAL, malfunc, RUNTIME_OBJECT_MISSING); } if (tp == TYPE_any && (grpfunc1 == BATgroupmedian || quantilefunc == BATgroupquantile)) tp = b->ttype; if (!BAThdense(b) || !BAThdense(g)) { /* if b or g don't have a dense head, replace the head with a * dense sequence */ t = BATjoin(BATmirror(b), g, MIN(BATcount(b), BATcount(g))); BBPreleaseref(b->batCacheid); BBPreleaseref(g->batCacheid); b = BATmirror(BATmark(t, 0)); g = BATmirror(BATmark(BATmirror(t), 0)); BBPreleaseref(t->batCacheid); } if (b->hseqbase != g->hseqbase || BATcount(b) != BATcount(g)) { /* b and g are not aligned: align them by creating a view on * one or the other */ oid min; /* lowest common oid */ oid max; /* highest common oid */ min = b->hseqbase; if (min < g->hseqbase) min = g->hseqbase; max = b->hseqbase + BATcount(b); if (g->hseqbase + BATcount(g) < max) max = g->hseqbase + BATcount(g); if (b->hseqbase != min || b->hseqbase + BATcount(b) != max) { if (min >= max) min = max = b->hseqbase; t = BATslice(b, BUNfirst(b) + (BUN) (min - b->hseqbase), BUNfirst(b) + (BUN) (max - b->hseqbase)); BBPreleaseref(b->batCacheid); b = t; } if (g->hseqbase != min || g->hseqbase + BATcount(g) != max) { if (min >= max) min = max = g->hseqbase; t = BATslice(g, BUNfirst(g) + (BUN) (min - g->hseqbase), BUNfirst(g) + (BUN) (max - g->hseqbase)); BBPreleaseref(g->batCacheid); g = t; } } if (!BAThdense(e)) { /* if e doesn't have a dense head, renumber the group ids with * a dense sequence at the cost of some left joins */ map = BATmark(e, 0); /* [gid,newgid(dense)] */ BBPreleaseref(e->batCacheid); e = BATmirror(map); /* [newgid(dense),gid] */ t = BATleftjoin(g, map, BATcount(g)); /* [oid,newgid] */ BBPreleaseref(g->batCacheid); g = t; } else { map = NULL; } if (grpfunc1) bn = (*grpfunc1)(b, g, e, NULL, tp, skip_nils, 1); if (quantilefunc) { assert(BATcount(quantile)>0); assert(quantile->ttype == TYPE_dbl); qvalue = ((const double *)Tloc(quantile, BUNfirst(quantile)))[0]; if (qvalue < 0|| qvalue > 1) { char *s; s = createException(MAL, malfunc, "quantile value of %f is not in range [0,1]", qvalue); return s; } bn = (*quantilefunc)(b, g, e, NULL, tp, qvalue, skip_nils, 1); } if (grpfunc2 && (*grpfunc2)(&bn, retval2 ? &cnts : NULL, b, g, e, NULL, tp, skip_nils, 1) == GDK_FAIL) bn = NULL; if (bn != NULL && (grpfunc1 == BATgroupmin || grpfunc1 == BATgroupmax)) { t = BATproject(bn, b); BBPreleaseref(bn->batCacheid); bn = t; } BBPreleaseref(b->batCacheid); BBPreleaseref(g->batCacheid); if (map == NULL) /* if map!=NULL, e is mirror of map */ BBPreleaseref(e->batCacheid); if (bn == NULL) { char *errbuf = GDKerrbuf; char *s; if (map) BBPreleaseref(map->batCacheid); if (errbuf && *errbuf) { if (strncmp(errbuf, "!ERROR: ", 8) == 0) errbuf += 8; if (strchr(errbuf, '!') == errbuf + 5) { s = createException(MAL, malfunc, "%s", errbuf); } else if ((s = strchr(errbuf, ':')) != NULL && s[1] == ' ') { s = createException(MAL, malfunc, "%s", s + 2); } else { s = createException(MAL, malfunc, "%s", errbuf); } *GDKerrbuf = 0; return s; } throw(MAL, malfunc, OPERATION_FAILED); } if (map) { t = BATleftjoin(map, bn, BATcount(bn)); BBPreleaseref(bn->batCacheid); bn = t; if (cnts) { t = BATleftjoin(map, cnts, BATcount(cnts)); BBPreleaseref(cnts->batCacheid); cnts = t; } BBPreleaseref(map->batCacheid); } *retval1 = bn->batCacheid; BBPkeepref(bn->batCacheid); if (retval2) { *retval2 = cnts->batCacheid; BBPkeepref(cnts->batCacheid); } return MAL_SUCCEED; }
// merging multiple OID lists, optimized for empty bats // Further improvement should come from multi-bat merging. str MATmergepack(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p) { int i,j= 0, *ret = (int*) getArgReference(stk,p,0); int top=0; oid **o_end, **o_src, *o, *oo, onxt; BAT *b, *bn, *bm, **bats; BUN cap = 0; (void)cntxt; (void)mb; bats = (BAT**) GDKzalloc(sizeof(BAT*) * p->argc); o_end = (oid**) GDKzalloc(sizeof(oid*) * p->argc); o_src = (oid**) GDKzalloc(sizeof(oid*) * p->argc); if ( bats ==0 || o_end == 0 || o_src == 0){ if (bats) GDKfree(bats); if (o_src) GDKfree(o_src); if (o_end) GDKfree(o_end); throw(MAL,"mat.mergepack",MAL_MALLOC_FAIL); } for (i = 1; i < p->argc; i++) { int bid = stk->stk[getArg(p,i)].val.ival; b = BATdescriptor(abs(bid)); if (b ){ cap += BATcount(b); if ( BATcount(b) ){ // pre-sort the arguments onxt = *(oid*) Tloc(b,BUNfirst(b)); for( j =top; j > 0 && onxt < *o_src[j-1]; j--){ o_src[j] = o_src[j-1]; o_end[j] = o_end[j-1]; bats[j] = bats[j-1]; } o_src[j] = (oid*) Tloc(b,BUNfirst(b)); o_end[j] = o_src[j] + BATcount(b); bats[j] = b; top++; } } } bn = BATnew(TYPE_void, TYPE_oid, cap, TRANSIENT); if (bn == NULL){ GDKfree(bats); GDKfree(o_src); GDKfree(o_end); throw(MAL, "mat.pack", MAL_MALLOC_FAIL); } if ( cap == 0){ BATseqbase(bn, 0); BATseqbase(BATmirror(bn), 0); BBPkeepref(*ret = bn->batCacheid); GDKfree(bats); GDKfree(o_src); GDKfree(o_end); return MAL_SUCCEED; } BATseqbase(bn, bats[0]->hseqbase); // UNROLL THE MULTI-BAT MERGE o = (oid*) Tloc(bn,BUNfirst(bn)); while( top){ *o++ = *o_src[0]; o_src[0]++; if( o_src[0] == o_end[0]){ // remove this one for(j=0; j< top; j++){ o_src[j]= o_src[j+1]; o_end[j]= o_end[j+1]; bats[j] = bats[j+1]; } top--; } else{ // resort priority queue onxt= *o_src[0]; for( j=1; j< top && onxt > *o_src[j]; j++){ oo = o_src[j]; o_src[j]= o_src[j-1]; o_src[j-1]= oo; oo = o_end[j]; o_end[j]= o_end[j-1]; o_end[j-1]= oo; bm = bats[j]; bats[j]=bats[j-1]; bats[j-1] = bm; } } } for( i=0; i< top; i++) BBPunfix(bats[i]->batCacheid); BATsetcount(bn, (BUN) (o - (oid *) Tloc(bn, BUNfirst(bn)))); BATseqbase(bn, 0); BATsettrivprop(bn); GDKfree(bats); GDKfree(o_src); GDKfree(o_end); /* properties */ bn->trevsorted = 0; bn->tsorted = 1; bn->tkey = 1; bn->T->nil = 0; bn->T->nonil = 1; BBPkeepref(*ret = bn->batCacheid); return MAL_SUCCEED; }
str BKCreuseBATmap(bat *ret, const bat *bid, const bat *did) { BAT *b, *d, *bn, *bs; oid bidx, oidx = 0, *o, *ol; oid *r; gdk_return res; if ((b = BATdescriptor(*bid)) == NULL) { throw(MAL, "bat.shrinkMap", RUNTIME_OBJECT_MISSING); } if ( b->htype != TYPE_void) { BBPunfix(b->batCacheid); throw(MAL, "bat.shrinkMap", SEMANTIC_TYPE_MISMATCH); } if ((d = BATdescriptor(*did)) == NULL) { BBPunfix(b->batCacheid); throw(MAL, "bat.shrinkMap", RUNTIME_OBJECT_MISSING); } bn= BATnew(TYPE_void, TYPE_oid, BATcount(b) - BATcount(d), TRANSIENT); if (bn == NULL) { BBPunfix(b->batCacheid); BBPunfix(d->batCacheid); throw(MAL, "bat.shrinkMap", MAL_MALLOC_FAIL ); } res = BATsubsort(&bs, NULL, NULL, d, NULL, NULL, 0, 0); BBPunfix(d->batCacheid); if (res != GDK_SUCCEED) { BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); throw(MAL, "bat.shrinkMap", MAL_MALLOC_FAIL ); } oidx = b->hseqbase; bidx = oidx + BATcount(b)-1; o = (oid*)Tloc(bs, BUNfirst(bs)); ol = (oid*)Tloc(bs, BUNlast(bs)); r = (oid*)Tloc(bn, BUNfirst(bn)); for (; oidx <= bidx; oidx++) { if ( *o == oidx ){ while ( ol > o && ol[-1] == bidx) { bidx--; ol--; } *r++ = bidx; o += (o < ol); bidx--; } else { *r++ = oidx; } } BATsetcount(bn, BATcount(b)-BATcount(bs)); BATseqbase(bn, b->hseqbase); bn->tsorted = 0; bn->trevsorted = 0; bn->tdense = 0; if (!(bn->batDirty&2)) BATsetaccess(bn, BAT_READ); BBPunfix(b->batCacheid); BBPunfix(bs->batCacheid); BBPkeepref(*ret= bn->batCacheid); return MAL_SUCCEED; }
str BKCreuseBAT(bat *ret, const bat *bid, const bat *did) { BAT *b, *d, *bn, *bs; oid oidx = 0, bidx, *o, *ol; gdk_return res; if ((b = BATdescriptor(*bid)) == NULL) { throw(MAL, "bat.reuse", RUNTIME_OBJECT_MISSING); } if ( b->htype != TYPE_void) { BBPunfix(b->batCacheid); throw(MAL, "bat.reuse", SEMANTIC_TYPE_MISMATCH); } if ((d = BATdescriptor(*did)) == NULL) { BBPunfix(b->batCacheid); throw(MAL, "bat.reuse", RUNTIME_OBJECT_MISSING); } bn= BATnew(b->htype, b->ttype, BATcount(b) - BATcount(d), TRANSIENT); if (bn == NULL) { BBPunfix(b->batCacheid); BBPunfix(d->batCacheid); throw(MAL, "bat.reuse", MAL_MALLOC_FAIL ); } res = BATsubsort(&bs, NULL, NULL, d, NULL, NULL, 0, 0); BBPunfix(d->batCacheid); if (res != GDK_SUCCEED) { BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); throw(MAL, "bat.reuse", MAL_MALLOC_FAIL ); } oidx = b->hseqbase; bidx = oidx + BATcount(b)-1; o = (oid*)Tloc(bs, BUNfirst(bs)); ol= (oid*)Tloc(bs, BUNlast(bs)); switch(ATOMstorage(b->ttype) ){ case TYPE_bte: reuseloop(bte); break; case TYPE_sht: reuseloop(sht); break; case TYPE_int: reuseloop(int); break; case TYPE_lng: reuseloop(lng); break; #ifdef HAVE_HGE case TYPE_hge: reuseloop(hge); break; #endif case TYPE_flt: reuseloop(flt); break; case TYPE_dbl: reuseloop(dbl); break; case TYPE_oid: reuseloop(oid); break; case TYPE_str: /* to be done based on its index width */ default: if (ATOMvarsized(bn->ttype)) { BUN p = BUNfirst(b); BUN q = BUNlast(b); BATiter bi = bat_iterator(b); for (;p<q; oidx++, p++) { if ( *o == oidx ){ while ( ol > o && ol[-1] == bidx) { bidx--; q--; ol--; } BUNappend(bn, BUNtail(bi, --q), FALSE); o += (o < ol); bidx--; } else { BUNappend(bn, BUNtail(bi, p), FALSE); } } } else { switch( b->T->width){ case 1:reuseloop(bte); break; case 2:reuseloop(sht); break; case 4:reuseloop(int); break; case 8:reuseloop(lng); break; #ifdef HAVE_HGE case 16:reuseloop(hge); break; #endif default: throw(MAL, "bat.shrink", "Illegal argument type"); } } } BATsetcount(bn, BATcount(b) - BATcount(bs)); BATseqbase(bn, b->hseqbase); bn->tsorted = 0; bn->trevsorted = 0; bn->tdense = 0; bn->tkey = b->tkey; if (!(bn->batDirty&2)) BATsetaccess(bn, BAT_READ); BBPunfix(b->batCacheid); BBPunfix(bs->batCacheid); BBPkeepref(*ret= bn->batCacheid); return MAL_SUCCEED; }