/* * The nextChunk version advances the reader, * which also means that the view descriptor is already available. * The granule size may differ in each call. */ str ITRnextChunk(lng *res, int *vid, int *bid, lng *granule) { BAT *b, *view; BUN i; if ((b = BATdescriptor(*bid)) == NULL) { throw(MAL, "iterator.nextChunk", INTERNAL_BAT_ACCESS); } if ((view = BATdescriptor(*vid)) == NULL) { BBPunfix(b->batCacheid); throw(MAL, "iterator.nextChunk", INTERNAL_BAT_ACCESS); } i = (BUN) (*res + BATcount(view)); if (i >= BUNlast(b)) { *res = lng_nil; *vid = 0; BBPunfix(view->batCacheid); BBPunfix(b->batCacheid); return MAL_SUCCEED; } /* printf("set bat chunk bound to " BUNFMT " - " BUNFMT " \n", i, i+(BUN) *granule-1); */ VIEWbounds(b, view, i, i + (BUN) * granule); BATseqbase(view, b->hseqbase == oid_nil ? oid_nil : b->hseqbase + i - BUNfirst(b)); BBPkeepref(*vid = view->batCacheid); BBPunfix(b->batCacheid); *res = i; return MAL_SUCCEED; }
str ITRbunNext(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { BATiter bi; BAT *b; oid *head; bat *bid; ValPtr tail; (void) cntxt; (void) mb; head = (oid *) getArgReference(stk, pci, 0); tail = getArgReference(stk,pci,1); bid = (bat *) getArgReference(stk, pci, 2); if ((b = BATdescriptor(*bid)) == NULL) { throw(MAL, "iterator.nextChunk", INTERNAL_BAT_ACCESS); } *head = (BUN)*head + 1; if (*head >= BUNlast(b)) { *head = oid_nil; BBPunfix(b->batCacheid); return MAL_SUCCEED; } bi = bat_iterator(b); VALinit(tail, b->ttype, BUNtail(bi, *(BUN*) head)); BBPunfix(b->batCacheid); return MAL_SUCCEED; }
BUN append_inserted(BAT *b, BAT *i ) { BUN nr = 0, r; BATiter ii = bat_iterator(i); for (r = i->batInserted; r < BUNlast(i); r++) { BUNappend(b, BUNtail(ii,r), TRUE); nr++; } return nr; }
BUN copy_inserted(BAT *b, BAT *i ) { BUN nr = 0; BUN r; BATiter ii = bat_iterator(i); for (r = i->batInserted; r < BUNlast(i); r++) { BUNins(b, BUNhead(ii,r), BUNtail(ii,r), TRUE); nr++; } return nr; }
/* * The prime routine for the BAT layer is to create a new hash index. * Its argument is the element type and the maximum number of BUNs be * stored under the hash function. */ BAT * BAThash(BAT *b, BUN masksize) { BAT *o = NULL; lng t0,t1; (void) t0; (void) t1; if (VIEWhparent(b)) { bat p = VIEWhparent(b); o = b; b = BATdescriptor(p); if (!ALIGNsynced(o, b) || BUNfirst(o) != BUNfirst(b)) { BBPunfix(b->batCacheid); b = o; o = NULL; } } MT_lock_set(&GDKhashLock(ABS(b->batCacheid)), "BAThash"); if (b->H->hash == NULL) { unsigned int tpe = ATOMstorage(b->htype); BUN cnt = BATcount(b); BUN mask; BUN p = BUNfirst(b), q = BUNlast(b), r; Hash *h = NULL; Heap *hp = NULL; str nme = BBP_physical(b->batCacheid); BATiter bi = bat_iterator(b); ALGODEBUG fprintf(stderr, "#BAThash: create hash(" BUNFMT ");\n", BATcount(b)); /* cnt = 0, hopefully there is a proper capacity from * which we can derive enough information */ if (!cnt) cnt = BATcapacity(b); if (b->htype == TYPE_void) { if (b->hseqbase == oid_nil) { MT_lock_unset(&GDKhashLock(ABS(b->batCacheid)), "BAThash"); ALGODEBUG fprintf(stderr, "#BAThash: cannot create hash-table on void-NIL column.\n"); return NULL; } ALGODEBUG fprintf(stderr, "#BAThash: creating hash-table on void column..\n"); tpe = TYPE_void; } /* determine hash mask size p = first; then no dynamic * scheme */ if (masksize > 0) { mask = HASHmask(masksize); } else if (ATOMsize(ATOMstorage(tpe)) == 1) { mask = (1 << 8); } else if (ATOMsize(ATOMstorage(tpe)) == 2) { mask = (1 << 12); } else if (b->hkey) { mask = HASHmask(cnt); } else { /* dynamic hash: we start with * HASHmask(cnt/64); if there are too many * collisions we try HASHmask(cnt/16), then * HASHmask(cnt/4), and finally * HASHmask(cnt). */ mask = HASHmask(cnt >> 6); p += (cnt >> 2); /* try out on first 25% of b */ if (p > q) p = q; } if (mask < 1024) mask = 1024; t0 = GDKusec(); do { BUN nslots = mask >> 3; /* 1/8 full is too full */ r = BUNfirst(b); if (hp) { HEAPfree(hp); GDKfree(hp); } if (h) { ALGODEBUG fprintf(stderr, "#BAThash: retry hash construction\n"); GDKfree(h); } /* create the hash structures */ hp = (Heap *) GDKzalloc(sizeof(Heap)); if (hp && (hp->filename = GDKmalloc(strlen(nme) + 12)) != NULL) sprintf(hp->filename, "%s.%chash", nme, b->batCacheid > 0 ? 'h' : 't'); if (hp == NULL || hp->filename == NULL || (h = HASHnew(hp, ATOMtype(b->htype), BATcapacity(b), mask)) == NULL) { MT_lock_unset(&GDKhashLock(ABS(b->batCacheid)), "BAThash"); if (hp != NULL) { GDKfree(hp->filename); GDKfree(hp); } return NULL; } switch (tpe) { case TYPE_bte: starthash(bte); break; case TYPE_sht: starthash(sht); break; case TYPE_int: case TYPE_flt: starthash(int); break; case TYPE_dbl: case TYPE_lng: starthash(lng); break; default: for (; r < p; r++) { ptr v = BUNhead(bi, r); BUN c = (BUN) heap_hash_any(b->H->vheap, h, v); if ( HASHget(h,c) == HASHnil(h) && nslots-- == 0) break; /* mask too full */ HASHputlink(h,r, HASHget(h,c)); HASHput(h,c, r); } break; } } while (r < p && mask < cnt && (mask <<= 2)); /* finish the hashtable with the current mask */ p = r; switch (tpe) { case TYPE_bte: finishhash(bte); break; case TYPE_sht: finishhash(sht); break; case TYPE_int: case TYPE_flt: finishhash(int); break; case TYPE_dbl: case TYPE_lng: finishhash(lng); break; default: for (; p < q; p++) { ptr v = BUNhead(bi, p); BUN c = (BUN) heap_hash_any(b->H->vheap, h, v); HASHputlink(h,p, HASHget(h,c)); HASHput(h,c,p); } break; } b->H->hash = h; t1 = GDKusec(); ALGODEBUG fprintf(stderr, "#BAThash: hash construction "LLFMT" usec\n", t1-t0); ALGODEBUG HASHcollisions(b,b->H->hash); }
gdk_return BATmaterializeh(BAT *b) { int ht; BUN cnt; Heap head; BUN p, q; oid h, *x; bte tshift; BATcheck(b, "BATmaterialize", GDK_FAIL); assert(!isVIEW(b)); ht = b->htype; cnt = BATcapacity(b); head = b->H->heap; p = BUNfirst(b); q = BUNlast(b); assert(cnt >= q - p); ALGODEBUG fprintf(stderr, "#BATmaterialize(%d);\n", (int) b->batCacheid); if (!BAThdense(b) || ht != TYPE_void) { /* no voids */ return GDK_SUCCEED; } ht = TYPE_oid; /* cleanup possible ACC's */ HASHdestroy(b); IMPSdestroy(b); b->H->heap.filename = NULL; if (HEAPalloc(&b->H->heap, cnt, sizeof(oid)) != GDK_SUCCEED) { b->H->heap = head; return GDK_FAIL; } /* point of no return */ b->htype = ht; tshift = b->T->shift; BATsetdims(b); if (b->ttype) { b->T->shift = tshift; /* restore in case it got changed */ b->T->width = 1 << tshift; } b->batDirty = TRUE; b->batDirtydesc = TRUE; b->H->heap.dirty = TRUE; /* set the correct dense info */ b->hdense = TRUE; /* So now generate [h..h+cnt-1] */ h = b->hseqbase; x = (oid *) b->H->heap.base; for (; p < q; p++) *x++ = h++; cnt = h - b->hseqbase; BATsetcount(b, cnt); /* cleanup the old heaps */ HEAPfree(&head, 0); return GDK_SUCCEED; }
str BATXMLforest(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { bat *ret = getArgReference_bat(stk, pci, 0); BAT *bn; BATiter *bi; BUN *p, *q; str buf; int i; size_t offset, len, size = BUFSIZ; const char *err = OPERATION_FAILED; (void) mb; (void) cntxt; buf = GDKmalloc(size); bi = GDKmalloc(sizeof(BATiter) * pci->argc); p = GDKmalloc(sizeof(BUN) * pci->argc); q = GDKmalloc(sizeof(BUN) * pci->argc); if (buf == NULL || bi == NULL || p == NULL || q == NULL) { if (buf) GDKfree(buf); if (bi) GDKfree(bi); if (p) GDKfree(p); if (q) GDKfree(q); throw(MAL, "xml.forest", MAL_MALLOC_FAIL); } /* collect the admin for the xml elements */ for (i = pci->retc; i < pci->argc; i++) { if ((bi[i].b = BATdescriptor(*getArgReference_bat(stk, pci, i))) == NULL) break; p[i] = BUNfirst(bi[i].b); q[i] = BUNlast(bi[i].b); } /* check for errors */ if (i != pci->argc) { for (i--; i >= pci->retc; i--) if (bi[i].b) BBPunfix(bi[i].b->batCacheid); GDKfree(bi); GDKfree(p); GDKfree(q); GDKfree(buf); throw(MAL, "xml.forest", INTERNAL_BAT_ACCESS); } prepareResult(bn, bi[pci->retc].b, TYPE_xml, "forest", for (i = pci->retc; i < pci->argc; i++) BBPunfix(bi[i].b->batCacheid); GDKfree(bi); GDKfree(p); GDKfree(q); GDKfree(buf)); while (p[pci->retc] < q[pci->retc]) { const char *t; /* fetch the elements */ offset = 0; strcpy(buf, str_nil); for (i = pci->retc; i < pci->argc; i++) { int n; t = (const char *) BUNtail(bi[i], p[i]); if (strNil(t)) continue; if ((len = strlen(t)) >= size - offset) { size += len + 128; buf = GDKrealloc(buf, size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } if (offset == 0) n = snprintf(buf, size, "%s", t); else if (buf[0] != *t) { err = "incompatible values in forest"; goto bunins_failed; } else if (buf[0] == 'A') n = snprintf(buf + offset, size - offset, " %s", t + 1); else if (buf[0] == 'C') n = snprintf(buf + offset, size - offset, "%s", t + 1); else { err = "can only combine attributes and element content"; goto bunins_failed; } offset += n; } bunfastapp(bn, buf); if (offset == 0) bn->T->nonil = 0; for (i = pci->retc; i < pci->argc; i++) if (bi[i].b) p[i]++; } GDKfree(buf); finalizeResult(ret, bn, bi[pci->retc].b); GDKfree(bi); GDKfree(p); GDKfree(q); return MAL_SUCCEED; bunins_failed: for (i = pci->retc; i < pci->argc; i++) if (bi[i].b) BBPunfix(bi[i].b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); GDKfree(bi); GDKfree(p); GDKfree(q); throw(MAL, "xml.forest", "%s", err); }
str BATXMLconcat(bat *ret, const bat *bid, const bat *rid) { BAT *b, *r = 0, *bn; BUN p, q, rp = 0; size_t len, size = BUFSIZ; str buf = GDKmalloc(size); BATiter bi, ri; const char *err = OPERATION_FAILED; if (buf == NULL) throw(MAL, "xml.concat", MAL_MALLOC_FAIL); b = BATdescriptor(*bid); r = BATdescriptor(*rid); if (b == NULL || r == NULL) { GDKfree(buf); if (b) BBPunfix(b->batCacheid); if (r) BBPunfix(r->batCacheid); throw(MAL, "xml.concat", INTERNAL_BAT_ACCESS); } p = BUNfirst(b); q = BUNlast(b); rp = BUNfirst(r); prepareResult(bn, b, TYPE_xml, "concat", GDKfree(buf); BBPunfix(r->batCacheid)); bi = bat_iterator(b); ri = bat_iterator(r); while (p < q) { const char *t = (const char *) BUNtail(bi, p); const char *v = (const char *) BUNtail(ri, rp); len = strlen(t) + strlen(v) + 1; if (len >= size) { GDKfree(buf); size = len + 128; buf = GDKmalloc(size); if (buf == NULL) { err= MAL_MALLOC_FAIL; goto bunins_failed; } } if (strNil(t)) { if (strNil(v)) { strcpy(buf, str_nil); bn->T->nonil = 0; } else strcpy(buf, v); } else { if (strNil(v)) strcpy(buf, t); else if (*t != *v) { err = "arguments not compatible"; goto bunins_failed; } else if (*t == 'A') snprintf(buf, size, "A%s %s", t + 1, v + 1); else if (*t == 'C') snprintf(buf, size, "C%s%s", t + 1, v + 1); else { err = "can only concatenate attributes and element content"; goto bunins_failed; } } bunfastapp(bn, buf); rp++; p++; } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(r->batCacheid); BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.concat", "%s", err); }
/* * The prime routine for the BAT layer is to create a new hash index. * Its argument is the element type and the maximum number of BUNs be * stored under the hash function. */ gdk_return BAThash(BAT *b, BUN masksize) { BAT *o = NULL; lng t0 = 0, t1 = 0; if (BATcheckhash(b)) { if (o != NULL) { o->T->hash = b->T->hash; BBPunfix(b->batCacheid); } return GDK_SUCCEED; } MT_lock_set(&GDKhashLock(abs(b->batCacheid)), "BAThash"); if (b->T->hash == NULL) { unsigned int tpe = ATOMbasetype(b->ttype); BUN cnt = BATcount(b); BUN mask, maxmask = 0; BUN p = BUNfirst(b), q = BUNlast(b), r; Hash *h = NULL; Heap *hp; const char *nme = BBP_physical(b->batCacheid); const char *ext = b->batCacheid > 0 ? "thash" : "hhash"; BATiter bi = bat_iterator(b); #ifdef PERSISTENTHASH int fd; #endif ALGODEBUG fprintf(stderr, "#BAThash: create hash(" BUNFMT ");\n", BATcount(b)); if ((hp = GDKzalloc(sizeof(*hp))) == NULL || (hp->farmid = BBPselectfarm(b->batRole, b->ttype, hashheap)) < 0 || (hp->filename = GDKmalloc(strlen(nme) + 12)) == NULL) { MT_lock_unset(&GDKhashLock(abs(b->batCacheid)), "BAThash"); GDKfree(hp); return GDK_FAIL; } sprintf(hp->filename, "%s.%s", nme, ext); /* cnt = 0, hopefully there is a proper capacity from * which we can derive enough information */ if (!cnt) cnt = BATcapacity(b); if (b->ttype == TYPE_void) { if (b->tseqbase == oid_nil) { MT_lock_unset(&GDKhashLock(abs(b->batCacheid)), "BAThash"); ALGODEBUG fprintf(stderr, "#BAThash: cannot create hash-table on void-NIL column.\n"); GDKfree(hp->filename); GDKfree(hp); return GDK_FAIL; } ALGODEBUG fprintf(stderr, "#BAThash: creating hash-table on void column..\n"); tpe = TYPE_void; } /* determine hash mask size p = first; then no dynamic * scheme */ if (masksize > 0) { mask = HASHmask(masksize); } else if (ATOMsize(tpe) == 1) { mask = (1 << 8); } else if (ATOMsize(tpe) == 2) { mask = (1 << 16); } else if (b->tkey) { mask = HASHmask(cnt); } else { /* dynamic hash: we start with * HASHmask(cnt)/64; if there are too many * collisions we try HASHmask(cnt)/16, then * HASHmask(cnt)/4, and finally * HASHmask(cnt). */ maxmask = HASHmask(cnt); mask = maxmask >> 6; p += (cnt >> 2); /* try out on first 25% of b */ if (p > q) p = q; } t0 = GDKusec(); do { BUN nslots = mask >> 3; /* 1/8 full is too full */ r = BUNfirst(b); if (h) { char *fnme; bte farmid; ALGODEBUG fprintf(stderr, "#BAThash: retry hash construction\n"); fnme = GDKstrdup(hp->filename); farmid = hp->farmid; HEAPfree(hp, 1); memset(hp, 0, sizeof(*hp)); hp->filename = fnme; hp->farmid = farmid; GDKfree(h); h = NULL; } /* create the hash structures */ if ((h = HASHnew(hp, ATOMtype(b->ttype), BATcapacity(b), mask, BATcount(b))) == NULL) { MT_lock_unset(&GDKhashLock(abs(b->batCacheid)), "BAThash"); GDKfree(hp->filename); GDKfree(hp); return GDK_FAIL; } switch (tpe) { case TYPE_bte: starthash(bte); break; case TYPE_sht: starthash(sht); break; case TYPE_int: case TYPE_flt: #if SIZEOF_OID == SIZEOF_INT case TYPE_oid: #endif #if SIZEOF_WRD == SIZEOF_INT case TYPE_wrd: #endif starthash(int); break; case TYPE_dbl: case TYPE_lng: #if SIZEOF_OID == SIZEOF_LNG case TYPE_oid: #endif #if SIZEOF_WRD == SIZEOF_LNG case TYPE_wrd: #endif starthash(lng); break; #ifdef HAVE_HGE case TYPE_hge: starthash(hge); break; #endif default: for (; r < p; r++) { ptr v = BUNtail(bi, r); BUN c = (BUN) heap_hash_any(b->T->vheap, h, v); if (HASHget(h, c) == HASHnil(h) && nslots-- == 0) break; /* mask too full */ HASHputlink(h, r, HASHget(h, c)); HASHput(h, c, r); } break; } } while (r < p && mask < maxmask && (mask <<= 2)); /* finish the hashtable with the current mask */ p = r; switch (tpe) { case TYPE_bte: finishhash(bte); break; case TYPE_sht: finishhash(sht); break; case TYPE_int: case TYPE_flt: #if SIZEOF_OID == SIZEOF_INT case TYPE_oid: #endif #if SIZEOF_WRD == SIZEOF_INT case TYPE_wrd: #endif finishhash(int); break; case TYPE_dbl: case TYPE_lng: #if SIZEOF_OID == SIZEOF_LNG case TYPE_oid: #endif #if SIZEOF_WRD == SIZEOF_LNG case TYPE_wrd: #endif finishhash(lng); break; #ifdef HAVE_HGE case TYPE_hge: finishhash(hge); break; #endif default: for (; p < q; p++) { ptr v = BUNtail(bi, p); BUN c = (BUN) heap_hash_any(b->T->vheap, h, v); HASHputlink(h, p, HASHget(h, c)); HASHput(h, c, p); } break; } #ifdef PERSISTENTHASH if ((BBP_status(b->batCacheid) & BBPEXISTING) && b->batInserted == b->batCount && HEAPsave(hp, nme, ext) == GDK_SUCCEED && (fd = GDKfdlocate(hp->farmid, nme, "rb+", ext)) >= 0) { ALGODEBUG fprintf(stderr, "#BAThash: persisting hash %d\n", b->batCacheid); ((size_t *) hp->base)[0] |= 1 << 24; if (write(fd, hp->base, SIZEOF_SIZE_T) < 0) perror("write hash"); if (!(GDKdebug & FORCEMITOMASK)) { #if defined(NATIVE_WIN32) _commit(fd); #elif defined(HAVE_FDATASYNC) fdatasync(fd); #elif defined(HAVE_FSYNC) fsync(fd); #endif } close(fd); } else ALGODEBUG fprintf(stderr, "#BAThash: NOT persisting hash %d\n", b->batCacheid); #endif b->T->hash = h; t1 = GDKusec(); ALGODEBUG fprintf(stderr, "#BAThash: hash construction " LLFMT " usec\n", t1 - t0); ALGODEBUG HASHcollisions(b, b->T->hash); }
static BUN SORTfndwhich(BAT *b, const void *v, enum find_which which) { BUN lo, hi, mid; int cmp; BUN cur; BATiter bi; BUN diff, end; int tp; if (b == NULL || (!b->tsorted && !b->trevsorted)) return BUN_NONE; lo = BUNfirst(b); hi = BUNlast(b); if (BATtdense(b)) { /* no need for binary search on dense column */ if (*(const oid *) v < b->tseqbase || *(const oid *) v == oid_nil) return which == FIND_ANY ? BUN_NONE : lo; if (*(const oid *) v >= b->tseqbase + BATcount(b)) return which == FIND_ANY ? BUN_NONE : hi; cur = (BUN) (*(const oid *) v - b->tseqbase) + lo; return cur + (which == FIND_LAST); } if (b->ttype == TYPE_void) { assert(b->tseqbase == oid_nil); switch (which) { case FIND_FIRST: if (*(const oid *) v == oid_nil) return lo; case FIND_LAST: return hi; default: if (lo < hi && *(const oid *) v == oid_nil) return lo; return BUN_NONE; } } cmp = 1; cur = BUN_NONE; bi = bat_iterator(b); /* only use storage type if comparison functions are equal */ tp = ATOMbasetype(b->ttype); switch (which) { case FIND_FIRST: end = lo; if (lo >= hi || (b->tsorted ? atom_GE(BUNtail(bi, lo), v, b->ttype) : atom_LE(BUNtail(bi, lo), v, b->ttype))) { /* shortcut: if BAT is empty or first (and * hence all) tail value is >= v (if sorted) * or <= v (if revsorted), we're done */ return lo; } break; case FIND_LAST: end = hi; if (lo >= hi || (b->tsorted ? atom_LE(BUNtail(bi, hi - 1), v, b->ttype) : atom_GE(BUNtail(bi, hi - 1), v, b->ttype))) { /* shortcut: if BAT is empty or first (and * hence all) tail value is <= v (if sorted) * or >= v (if revsorted), we're done */ return hi; } break; default: /* case FIND_ANY -- stupid compiler */ end = 0; /* not used in this case */ if (lo >= hi) { /* empty BAT: value not found */ return BUN_NONE; } break; } if (b->tsorted) { switch (tp) { case TYPE_bte: SORTfndloop(bte, simple_CMP, BUNtloc); break; case TYPE_sht: SORTfndloop(sht, simple_CMP, BUNtloc); break; case TYPE_int: SORTfndloop(int, simple_CMP, BUNtloc); break; case TYPE_lng: SORTfndloop(lng, simple_CMP, BUNtloc); break; #ifdef HAVE_HGE case TYPE_hge: SORTfndloop(hge, simple_CMP, BUNtloc); break; #endif case TYPE_flt: SORTfndloop(flt, simple_CMP, BUNtloc); break; case TYPE_dbl: SORTfndloop(dbl, simple_CMP, BUNtloc); break; default: if (b->tvarsized) SORTfndloop(b->ttype, atom_CMP, BUNtvar); else SORTfndloop(b->ttype, atom_CMP, BUNtloc); break; } } else { switch (tp) { case TYPE_bte: SORTfndloop(bte, -simple_CMP, BUNtloc); break; case TYPE_sht: SORTfndloop(sht, -simple_CMP, BUNtloc); break; case TYPE_int: SORTfndloop(int, -simple_CMP, BUNtloc); break; case TYPE_lng: SORTfndloop(lng, -simple_CMP, BUNtloc); break; #ifdef HAVE_HGE case TYPE_hge: SORTfndloop(hge, -simple_CMP, BUNtloc); break; #endif case TYPE_flt: SORTfndloop(flt, -simple_CMP, BUNtloc); break; case TYPE_dbl: SORTfndloop(dbl, -simple_CMP, BUNtloc); break; default: if (b->tvarsized) SORTfndloop(b->ttype, -atom_CMP, BUNtvar); else SORTfndloop(b->ttype, -atom_CMP, BUNtloc); break; } } switch (which) { case FIND_FIRST: if (cmp == 0 && b->tkey == 0) { /* shift over multiple equals */ for (diff = cur - end; diff; diff >>= 1) { while (cur >= end + diff && atom_EQ(BUNtail(bi, cur - diff), v, b->ttype)) cur -= diff; } } break; case FIND_LAST: if (cmp == 0 && b->tkey == 0) { /* shift over multiple equals */ for (diff = (end - cur) >> 1; diff; diff >>= 1) { while (cur + diff < end && atom_EQ(BUNtail(bi, cur + diff), v, b->ttype)) cur += diff; } } cur += (cmp == 0); break; default: /* case FIND_ANY -- stupid compiler */ if (cmp) { /* not found */ cur = BUN_NONE; } break; } return cur; }
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; }