ack/util/ego/share/lset.c
1987-03-10 11:49:39 +00:00

214 lines
3.7 KiB
C

/* $Header$ */
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* L O N G S E T S
*
* L S E T . C
*/
#include "types.h"
#include "lset.h"
#include "alloc.h"
#include "debug.h"
/* A 'long' set is represented as a linear list of 'elemholder'
* records. Every such record contains a pointer to an element
* of the set and to the next elemholder. An empty set is
* represented as a null pointer.
* An element of a long set must be of some pointer type or,
* in any case, must have the size of a pointer. Note that
* the strict typing rules are not obeyed here.
* This package implements the usual operations on sets.
* The name of every operation is preceeded by a 'L' to
* distinguish it from the operation on 'compact' (bitvector)
* sets with a similar name.
*/
lset Lempty_set()
{
return ((lset) 0);
}
bool Lis_elem(x,s)
register Lelem_t x;
register lset s;
{
/* Search the list to see if x is an element of s */
while (s != (elem_p) 0) {
if (s->e_elem == x) {
return TRUE;
}
s = s->e_next;
}
return FALSE;
}
Ladd(x,s_p)
Lelem_t x;
lset *s_p;
{
/* add x to a set. Note that the set is given as in-out
* parameter, because it may be changed.
*/
elem_p t;
if (!Lis_elem(x,*s_p)) {
t = newelem(); /* allocate a new elemholder */
t->e_elem = x;
t->e_next = *s_p; /* insert it at the head of the list */
*s_p = t;
}
}
Lremove(x,s_p)
Lelem_t x;
lset *s_p;
{
/* Remove x from a set. If x was not an element of
* the set, nothing happens.
*/
register elem_p *epp, ep;
lset s;
s = *s_p;
epp = &s;
while ((ep = *epp) != (elem_p) 0) {
if (ep->e_elem == x) {
*epp = ep->e_next;
oldelem(ep);
break;
} else {
epp = &ep->e_next;
}
}
*s_p = s;
}
/* The operations first, next and elem can be used to iterate
* over a set. For example:
* for (i = Lfirst(s); i != (Lindex) 0; i = Lnext(i,s) {
* x = Lelem(i);
* use x
* }
* which is like:
* 'for all elements x of s do'
* use x
*/
Lindex Lfirst(s)
lset s;
{
return ((Lindex) s);
/* Note that an index for long sets is just
* a pointer to an elemholder.
*/
}
Lindex Lnext(i,s)
Lindex i;
lset s;
{
assert(i != (Lindex) 0);
return (i->e_next);
}
Lelem_t Lelem(i)
Lindex i;
{
return (i->e_elem);
}
Ljoin(s1,s2_p)
lset s1,*s2_p;
{
/* Join two sets, assign the result to the second set
* and delete the first set (i.e. the value of the
* first set becomes undefined).
*/
register elem_p *epp, ep;
lset s2;
/* First all elements of s1 that are also an element of s2
* are removed from the s1 list. The two resulting lists
* (for s1 and s2) are linked (s1 first).
* Note the usage of epp, which points to a pointer that
* points to the next elemholder record of the list.
*/
s2 = *s2_p;
epp = &s1;
while ((ep = *epp) != (elem_p) 0) {
if (Lis_elem(ep->e_elem,s2)) {
/* remove an element */
*epp = ep->e_next;
oldelem(ep);
} else {
epp = &ep->e_next;
}
}
*epp = s2; /* last record of s1 (or s1 itself) now points
* to first record of s2.
*/
*s2_p = s1;
}
Ldeleteset(s)
lset s;
{
register elem_p ep, next;
for (ep = s; ep != (elem_p) 0; ep = next) {
next = ep->e_next;
oldelem(ep);
}
}
bool Lis_subset(s1,s2)
lset s1,s2;
{
/* See if s1 is a subset of s2 */
register Lindex i;
for (i = Lfirst(s1); i != (Lindex) 0; i = Lnext(i,s1)) {
if (!Lis_elem(Lelem(i),s2)) return FALSE;
}
return TRUE;
}
short Lnrelems(s)
lset s;
{
/* Compute the number of elements of a set */
register elem_p ep;
register short cnt;
cnt = 0;
for (ep = s; ep != (elem_p) 0; ep = ep->e_next) {
cnt++;
}
return cnt;
}