home *** CD-ROM | disk | FTP | other *** search
- /*
- * File: oset.c
- * Contents: compl, diff, inter, unions
- */
-
- #include "../h/config.h"
- #include "../h/rt.h"
- #include "rproto.h"
-
-
- /*
- * ~x - complement cset x.
- */
-
- OpDcl(compl,1,"~")
- {
- register int i;
- union block *bp;
- int *cs, csbuf[CsetSize];
-
- if (blkreq((word)sizeof(struct b_cset)) == Error)
- RunErr(0, NULL);
-
- /*
- * Arg1 must be a cset.
- */
- if (cvcset(&Arg1, &cs, csbuf) == CvtFail)
- RunErr(104, &Arg1);
-
- /*
- * Allocate a new cset and then copy each cset word from Arg1
- * into the new cset words, complementing each bit.
- */
- bp = (union block *)alccset();
- for (i = 0; i < CsetSize; i++)
- bp->cset.bits[i] = ~cs[i];
- Arg0.dword = D_Cset;
- BlkLoc(Arg0) = bp;
- Return;
- }
-
- /*
- * x -- y - difference of csets x and y or of sets x and y.
- */
-
- OpDcl(diff,2,"--")
- {
- register word i;
- word slotnum;
- register union block *srcp, *tstp, *dstp, **hook;
- int *cs1, *cs2, csbuf1[CsetSize], csbuf2[CsetSize], res;
- struct b_slots *seg;
- struct b_selem *ep;
-
- if (Qual(Arg1) || Qual(Arg2))
- goto skipsets;
- if (Arg1.dword == D_Set && Arg2.dword != D_Set)
- RunErr(119, &Arg2);
- if (Arg2.dword == D_Set && Arg1.dword != D_Set)
- RunErr(119, &Arg1);
- if (Arg1.dword == D_Set && Arg2.dword == D_Set) {
- /*
- * Both Arg1 and Arg2 are sets - do set difference. Make a new set
- * based on the size of Arg1.
- */
- dstp = hmake(T_Set, (word)0, BlkLoc(Arg1)->set.size);
- if (dstp == NULL)
- RunErr(0, NULL);
- /*
- * For each element in set Arg1 if it is not in set Arg2
- * copy it directly into the result set.
- */
- srcp = BlkLoc(Arg1);
- tstp = BlkLoc(Arg2);
- 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);
- addmem(&dstp->set, alcselem(&ep->setmem, ep->hashnum), hook);
- }
- ep = (struct b_selem *)ep->clink;
- }
- }
- Arg0.dword = D_Set;
- BlkLoc(Arg0) = dstp;
- if (TooSparse(dstp))
- hshrink(&Arg0);
- }
- else {
- skipsets:
- if (blkreq((word)sizeof(struct b_cset)) == Error)
- RunErr(0, NULL);
-
- /*
- * Arg1 and Arg2 must be csets.
- */
- if (cvcset(&Arg1, &cs1, csbuf1) == CvtFail)
- RunErr(120, &Arg1);
- if (cvcset(&Arg2, &cs2, csbuf2) == CvtFail)
- RunErr(120, &Arg2);
-
- /*
- * 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.
- */
- dstp = (union block *)alccset();
- for (i = 0; i < CsetSize; i++) {
- dstp->cset.bits[i] = cs1[i] & ~cs2[i];
- }
-
- Arg0.dword = D_Cset;
- BlkLoc(Arg0) = dstp;
- }
- Return;
- }
-
- /*
- * x ** y - intersection of csets x and y or of sets x and y.
- */
-
- OpDcl(inter,2,"**")
- {
- register word i;
- word slotnum;
- register union block *srcp, *tstp, *dstp, **hook;
- int *cs1, *cs2, csbuf1[CsetSize], csbuf2[CsetSize], res;
- struct b_slots *seg;
- struct b_selem *ep;
-
- if (Qual(Arg1) || Qual(Arg2))
- goto skipsets;
- if (Arg1.dword == D_Set && Arg2.dword != D_Set)
- RunErr(119, &Arg2);
- if (Arg2.dword == D_Set && Arg1.dword != D_Set)
- RunErr(119, &Arg1);
- if (Arg1.dword == D_Set && Arg2.dword == D_Set) {
- /*
- * Both Arg1 and Arg2 are sets - do set intersection.
- * Make a new set the size of the smaller argument set.
- */
- dstp = hmake(T_Set, (word)0,
- Min(BlkLoc(Arg1)->set.size, BlkLoc(Arg2)->set.size));
- if (dstp == NULL)
- RunErr(0, NULL);
- /*
- * 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.
- */
- if (BlkLoc(Arg1)->set.size <= BlkLoc(Arg2)->set.size) {
- srcp = BlkLoc(Arg1);
- tstp = BlkLoc(Arg2);
- }
- else {
- srcp = BlkLoc(Arg2);
- tstp = BlkLoc(Arg1);
- }
- 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);
- addmem(&dstp->set, alcselem(&ep->setmem, ep->hashnum), hook);
- }
- ep = (struct b_selem *)ep->clink;
- }
- }
- Arg0.dword = D_Set;
- BlkLoc(Arg0) = dstp;
- if (TooSparse(dstp))
- hshrink(&Arg0);
- }
- else {
- skipsets:
- if (blkreq((word)sizeof(struct b_cset)) == Error)
- RunErr(0, NULL);
-
- /*
- * Arg1 and Arg2 must be csets.
- */
- if (cvcset(&Arg1, &cs1, csbuf1) == CvtFail)
- RunErr(120, &Arg1);
- if (cvcset(&Arg2, &cs2, csbuf2) == CvtFail)
- RunErr(120, &Arg2);
-
- /*
- * Allocate a new cset and in each word of it, compute the value
- * of the bitwise intersection of the corresponding words in the
- * Arg1 and Arg2 csets.
- */
- dstp = (union block *)alccset();
- for (i = 0; i < CsetSize; i++) {
- dstp->cset.bits[i] = cs1[i] & cs2[i];
- }
-
- Arg0.dword = D_Cset;
- BlkLoc(Arg0) = dstp;
- }
- Return;
- }
-
- /*
- * x ++ y - union of csets x and y or of sets x and y.
- */
-
- OpDcl(unions,2,"++")
- {
- register word i;
- word slotnum;
- register union block *srcp, *tstp, *dstp, **hook;
- int *cs1, *cs2, csbuf1[CsetSize], csbuf2[CsetSize], res;
- struct b_slots *seg;
- struct b_selem *ep;
- dptr srcd, tstd;
-
- if (Qual(Arg1) || Qual(Arg2))
- goto skipsets;
- if (Arg1.dword == D_Set && Arg2.dword != D_Set)
- RunErr(119, &Arg2);
- if (Arg2.dword == D_Set && Arg1.dword != D_Set)
- RunErr(119, &Arg1);
- if (Arg1.dword == D_Set && Arg2.dword == D_Set) {
- /*
- * Both Arg1 and Arg2 are sets - do set union. Copy the larger set
- * and ensure there's room for *Arg1 + *Arg2 elements.
- */
- if (BlkLoc(Arg1)->set.size >= BlkLoc(Arg2)->set.size) {
- srcd = &Arg1;
- tstd = &Arg2;
- }
- else {
- srcd = &Arg2;
- tstd = &Arg1;
- }
- if (cpset(srcd, &Arg0, BlkLoc(Arg1)->set.size + BlkLoc(Arg2)->set.size)
- == Error)
- RunErr(0, NULL);
- /*
- * Copy each element from the smaller set into the result set,
- * if it is not already there.
- */
- srcp = BlkLoc(*srcd);
- tstp = BlkLoc(*tstd);
- dstp = BlkLoc(Arg0);
- for (i = 0; i < HSegs && (seg = tstp->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)
- addmem(&dstp->set, alcselem(&ep->setmem, ep->hashnum), hook);
- ep = (struct b_selem *)ep->clink;
- }
- }
- if (TooCrowded(dstp)) /* if the union got too big, enlarge */
- hgrow(&Arg0);
- }
- else {
- skipsets:
-
- if (blkreq((word)sizeof(struct b_cset)) == Error)
- RunErr(0, NULL);
-
- /*
- * Arg1 and Arg2 must be csets.
- */
- if (cvcset(&Arg1, &cs1, csbuf1) == CvtFail)
- RunErr(120, &Arg1);
- if (cvcset(&Arg2, &cs2, csbuf2) == CvtFail)
- RunErr(120, &Arg2);
-
- /*
- * Allocate a new cset and in each word of it, compute the value
- * of the bitwise union of the corresponding words in the
- * Arg1 and Arg2 csets.
- */
- dstp = (union block *)alccset();
- for (i = 0; i < CsetSize; i++) {
- dstp->cset.bits[i] = cs1[i] | cs2[i];
- }
-
- Arg0.dword = D_Cset;
- BlkLoc(Arg0) = dstp;
- }
- Return;
- }
-