/* * 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; }