diff options
Diffstat (limited to 'src/runtime/oset.r')
-rw-r--r-- | src/runtime/oset.r | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/src/runtime/oset.r b/src/runtime/oset.r new file mode 100644 index 0000000..7808e80 --- /dev/null +++ b/src/runtime/oset.r @@ -0,0 +1,299 @@ +/* + * File: oset.r + * Contents: compl, diff, inter, union + */ + +"~x - complement cset x." + +operator{1} ~ compl(x) + /* + * x must be a cset. + */ + if !cnv:tmp_cset(x) then + runerr(104, x) + + abstract { + return cset + } + body { + register int i; + struct b_cset *cp, *cpx; + + /* + * Allocate a new cset and then copy each cset word from x + * into the new cset words, complementing each bit. + */ + Protect(cp = alccset(), runerr(0)); + cpx = (struct b_cset *)BlkLoc(x); /* must come after alccset() */ + for (i = 0; i < CsetSize; i++) + cp->bits[i] = ~cpx->bits[i]; + return cset(cp); + } +end + + +"x -- y - difference of csets x and y or of sets x and y." + +operator{1} -- diff(x,y) + if is:set(x) && is:set(y) then { + abstract { + return type(x) + } + body { + int res; + register int i; + register word slotnum; + tended union block *srcp, *tstp, *dstp; + tended struct b_slots *seg; + tended struct b_selem *ep; + struct b_selem *np; + union block **hook; + + /* + * Make a new set based on the size of x. + */ + dstp = hmake(T_Set, (word)0, BlkLoc(x)->set.size); + if (dstp == NULL) + runerr(0); + /* + * For each element in set x if it is not in set y + * copy it directly into the result set. + * + * np always has a new element ready for use. We get one in advance, + * and stay one ahead, because hook can't be tended. + */ + srcp = BlkLoc(x); + tstp = BlkLoc(y); + Protect(np = alcselem(&nulldesc, (uword)0), runerr(0)); + + for (i = 0; i < HSegs && (seg = srcp->set.hdir[i]) != NULL; i++) + for (slotnum = segsize[i] - 1; slotnum >= 0; slotnum--) { + ep = (struct b_selem *)seg->hslots[slotnum]; + while (ep != NULL) { + memb(tstp, &ep->setmem, ep->hashnum, &res); + if (res == 0) { + hook = memb(dstp, &ep->setmem, ep->hashnum, &res); + np->setmem = ep->setmem; + np->hashnum = ep->hashnum; + addmem(&dstp->set, np, hook); + Protect(np = alcselem(&nulldesc, (uword)0), runerr(0)); + } + ep = (struct b_selem *)ep->clink; + } + } + deallocate((union block *)np); + if (TooSparse(dstp)) + hshrink(dstp); + Desc_EVValD(dstp, E_Screate, D_Set); + return set(dstp); + } + } + else { + if !cnv:tmp_cset(x) then + runerr(120, x) + if !cnv:tmp_cset(y) then + runerr(120, y) + abstract { + return cset + } + /* + * Allocate a new cset and in each word of it, compute the value + * of the bitwise difference of the corresponding words in the + * Arg1 and Arg2 csets. + */ + body { + struct b_cset *cp, *cpx, *cpy; + register int i; + + Protect(cp = alccset(), runerr(0)); + cpx = (struct b_cset *)BlkLoc(x); /* must come after alccset() */ + cpy = (struct b_cset *)BlkLoc(y); /* must come after alccset() */ + for (i = 0; i < CsetSize; i++) + cp->bits[i] = cpx->bits[i] & ~cpy->bits[i]; + return cset(cp); + } + } +end + + +"x ** y - intersection of csets x and y or of sets x and y." + +operator{1} ** inter(x,y) + if is:set(x) && is:set(y) then { + abstract { + return new set(store[type(x).set_elem] ** store[type(y).set_elem]) + } + body { + int res; + register int i; + register word slotnum; + tended union block *srcp, *tstp, *dstp; + tended struct b_slots *seg; + tended struct b_selem *ep; + struct b_selem *np; + union block **hook; + + /* + * Make a new set the size of the smaller argument set. + */ + dstp = hmake(T_Set, (word)0, + Min(BlkLoc(x)->set.size, BlkLoc(y)->set.size)); + if (dstp == NULL) + runerr(0); + /* + * Using the smaller of the two sets as the source + * copy directly into the result each of its elements + * that are also members of the other set. + * + * np always has a new element ready for use. We get one in advance, + * and stay one ahead, because hook can't be tended. + */ + if (BlkLoc(x)->set.size <= BlkLoc(y)->set.size) { + srcp = BlkLoc(x); + tstp = BlkLoc(y); + } + else { + srcp = BlkLoc(y); + tstp = BlkLoc(x); + } + Protect(np = alcselem(&nulldesc, (uword)0), runerr(0)); + for (i = 0; i < HSegs && (seg = srcp->set.hdir[i]) != NULL; i++) + for (slotnum = segsize[i] - 1; slotnum >= 0; slotnum--) { + ep = (struct b_selem *)seg->hslots[slotnum]; + while (ep != NULL) { + memb(tstp, &ep->setmem, ep->hashnum, &res); + if (res != 0) { + hook = memb(dstp, &ep->setmem, ep->hashnum, &res); + np->setmem = ep->setmem; + np->hashnum = ep->hashnum; + addmem(&dstp->set, np, hook); + Protect(np = alcselem(&nulldesc, (uword)0), runerr(0)); + } + ep = (struct b_selem *)ep->clink; + } + } + deallocate((union block *)np); + if (TooSparse(dstp)) + hshrink(dstp); + Desc_EVValD(dstp, E_Screate, D_Set); + return set(dstp); + } + } + else { + + if !cnv:tmp_cset(x) then + runerr(120, x) + if !cnv:tmp_cset(y) then + runerr(120, y) + abstract { + return cset + } + + /* + * Allocate a new cset and in each word of it, compute the value + * of the bitwise intersection of the corresponding words in the + * x and y csets. + */ + body { + struct b_cset *cp, *cpx, *cpy; + register int i; + + Protect(cp = alccset(), runerr(0)); + cpx = (struct b_cset *)BlkLoc(x); /* must come after alccset() */ + cpy = (struct b_cset *)BlkLoc(y); /* must come after alccset() */ + for (i = 0; i < CsetSize; i++) { + cp->bits[i] = cpx->bits[i] & cpy->bits[i]; + } + return cset(cp); + } + } +end + + +"x ++ y - union of csets x and y or of sets x and y." + +operator{1} ++ union(x,y) + if is:set(x) && is:set(y) then { + abstract { + return new set(store[type(x).set_elem] ++ store[type(y).set_elem]) + } + body { + int res; + register int i; + register word slotnum; + struct descrip d; + tended union block *dstp; + tended struct b_slots *seg; + tended struct b_selem *ep; + struct b_selem *np; + union block **hook; + + /* + * Ensure that x is the larger set; if not, swap. + */ + if (BlkLoc(y)->set.size > BlkLoc(x)->set.size) { + d = x; + x = y; + y = d; + } + /* + * Copy x and ensure there's room for *x + *y elements. + */ + if (cpset(&x, &result, BlkLoc(x)->set.size + BlkLoc(y)->set.size) + == Error) + runerr(0); + /* + * Copy each element from y into the result, if not already there. + * + * np always has a new element ready for use. We get one in advance, + * and stay one ahead, because hook can't be tended. + */ + dstp = BlkLoc(result); + Protect(np = alcselem(&nulldesc, (uword)0), runerr(0)); + for (i = 0; i < HSegs && (seg = BlkLoc(y)->set.hdir[i]) != NULL; i++) + for (slotnum = segsize[i] - 1; slotnum >= 0; slotnum--) { + ep = (struct b_selem *)seg->hslots[slotnum]; + while (ep != NULL) { + hook = memb(dstp, &ep->setmem, ep->hashnum, &res); + if (res == 0) { + np->setmem = ep->setmem; + np->hashnum = ep->hashnum; + addmem(&dstp->set, np, hook); + Protect(np = alcselem(&nulldesc, (uword)0), runerr(0)); + } + ep = (struct b_selem *)ep->clink; + } + } + deallocate((union block *)np); + if (TooCrowded(dstp)) /* if the union got too big, enlarge */ + hgrow(dstp); + return result; + } + } + else { + if !cnv:tmp_cset(x) then + runerr(120, x) + if !cnv:tmp_cset(y) then + runerr(120, y) + abstract { + return cset + } + + /* + * Allocate a new cset and in each word of it, compute the value + * of the bitwise union of the corresponding words in the + * x and y csets. + */ + body { + struct b_cset *cp, *cpx, *cpy; + register int i; + + Protect(cp = alccset(), runerr(0)); + cpx = (struct b_cset *)BlkLoc(x); /* must come after alccset() */ + cpy = (struct b_cset *)BlkLoc(y); /* must come after alccset() */ + for (i = 0; i < CsetSize; i++) + cp->bits[i] = cpx->bits[i] | cpy->bits[i]; + return cset(cp); + } + } +end |