/*************************** bv-bool-ops.c ***************************** Purpose: Implementation of boolean operations as bit vectors. Provenance: Written and tested by S. Wartik, April 1991. Notes: None. **/ #include "bv.h" static boolean error_occurred; /* TRUE iff an error occurred on the */ /* last call to a boolean operator. */ /************************************************************************** Create(lower, upper, s) Returns: void Purpose: Create a set capable of containing values in the range [lower,upper]. Plan: Set the values of "s" to the parameters. Notes: This routine must be called before any of the other routines (save error_occurred()) will work. **/ void Create(lower, upper, s) int lower, upper; /* in: gives the set's domain. */ set *s; /* out: the set. */ { if ( lower > upper || (upper - lower) >= MAX_ELEMENTS ) { error_occurred = TRUE; return; } s->lower = lower; s->upper = upper; error_occurred = FALSE; } /************************************************************************** Clear(s) Returns: void Purpose: Indicate that set s is empty. Plan: Set all bits of s to 0. Notes: The Create() function does not automatically clear a set; this routine must be called to do so. **/ void Clear(s) set *s; /* out: the set to be cleared. */ { register int i, Number_Of_Bytes; Number_Of_Bytes = (s->upper - s->lower)/WORDSIZE + 1; for ( i = 0; i < Number_Of_Bytes; i++ ) s->bits[i] = 0; error_occurred = FALSE; } /************************************************************************** Insert(s, e) Returns: void Purpose: Insert element e into set s. Plan: Determine the bit in s to which e corresponds, and set that bit to 1. Notes: e may already be in s. **/ void Insert(s, e) set *s; /* in out: the set to receive the element. */ elementType e; /* in: the element to be inserted. */ { if ( e < s->lower || e > s->upper ) { error_occurred = TRUE; return; } s->bits[(e-s->lower)/WORDSIZE] |= 01 << ((e-s->lower)%WORDSIZE); error_occurred = FALSE; } /************************************************************************** Delete(s, e) Returns: void Purpose: Delete element e from set s. Plan: Determine the bit in s to which e corresponds, and set that bit to 0. Notes: e doesn't have to be in s. **/ void Delete(s, e) set *s; /* in out: the set from which to delete. */ elementType e; /* in: the element to delete. */ { if ( e < s->lower || e > s->upper ) { error_occurred = TRUE; return; } s->bits[(e-s->lower)/WORDSIZE] &= ~(01 << ((e-s->lower)%WORDSIZE)); error_occurred = FALSE; } /************************************************************************** Empty(s) Returns: boolean Purpose: Determine whether a set is empty: return TRUE iff it is. Plan: Any non-zero bit indicates the set is not empty; test for that. Notes: None. **/ boolean Empty(s) set *s; /* in: the set whose emptiness is to be checked. */ { register int i, Number_Of_Bytes; error_occurred = FALSE; Number_Of_Bytes = (s->upper - s->lower)/WORDSIZE + 1; for ( i = 0; i < Number_Of_Bytes; i++ ) if ( s->bits[i] ) return FALSE; return TRUE; } /************************************************************************** Member(s, e) Returns: boolean Purpose: Determine if e is a member of s: return TRUE iff it is. Plan: Check the bit to which e corresponds. Notes: None. **/ boolean Member(s, e) set *s; elementType e; { if ( error_occurred = (e < s->lower || e > s->upper) ) return FALSE; return (s->bits[(e - s->lower)/WORDSIZE] >> (e - s->lower)%WORDSIZE) & 01; } /* The following macro tests whether two sets have an equivalent domain -- * i.e., bounds. It is only possible to perform the boolean operations * on equivalent sets. */ #define equivalent(s1, s2) \ ((s1)->lower==(s2)->lower && (s1)->upper==(s2)->upper) /************************************************************************** Unite(s1, s2, s3) Returns: void Purpose: Return in s3 the union of sets s1 and s2. Plan: Use the bitwise OR operator to construct the union of each set of words in s1 and s2. Notes: None. **/ void Unite(s1, s2, s3) set *s1, *s2; /* in: the sets to be united. */ set *s3; /* out: the union of s1 and s2. */ { register int i, Number_Of_Bytes; if ( ! (equivalent(s1, s2) && equivalent(s2, s3)) ) { error_occurred = TRUE; return; } Number_Of_Bytes = (s1->upper - s1->lower)/WORDSIZE + 1; for ( i = 0 ; i < Number_Of_Bytes; i++ ) s3->bits[i] = (s1->bits[i] | s2->bits[i]); error_occurred = FALSE; } /************************************************************************** Intersect(s1, s2, s3) Returns: void Purpose: Return in s3 the intersection of s1 and s2. Plan: Use the bitwise AND operator to construct the intersection of s1 and s2. Notes: None. **/ void Intersect(s1, s2, s3) set *s1, *s2; /* in: the sets to be intersected. */ set *s3; /* out: the intersection of s1 and s2. */ { register int i, Number_Of_Bytes; if ( ! (equivalent(s1, s2) && equivalent(s2, s3)) ) { error_occurred = TRUE; return; } Number_Of_Bytes = (s1->upper - s1->lower)/WORDSIZE + 1; for ( i = 0 ; i < Number_Of_Bytes; i++ ) s3->bits[i] = (s1->bits[i] & s2->bits[i]); error_occurred = FALSE; } /************************************************************************** Subtract(s1, s2, s3) Returns: void Purpose: Return in s3 the difference between s1 and s2 (i.e., s1-s2). Plan: Use the formula (A&~B) on each corresponding pair of words in s1 and s2. Notes: None. **/ void Subtract(s1, s2, s3) set *s1, *s2; /* in: the sets to be subtracted. */ set *s3; /* out: the difference between s1 and s2. */ { register int i, Number_Of_Bytes; if ( ! (equivalent(s1, s2) && equivalent(s2, s3)) ) { error_occurred = TRUE; return; } Number_Of_Bytes = (s1->upper - s1->lower)/WORDSIZE + 1; for ( i = 0 ; i < Number_Of_Bytes; i++ ) s3->bits[i] = s1->bits[i] & ~(s2->bits[i]); error_occurred = FALSE; } /************************************************************************** Copy(source, destination) Returns: void Purpose: Create a copy of a set. Plan: Trivial. Notes: None. **/ void Copy(source, destination) set *source, /* in: the set to be copied. */ *destination; /* out: a copy of "source". */ { register int i; if ( ! equivalent(source, destination) ) { error_occurred = TRUE; return; } for ( i = 0; i < MAX_ELEMENTS/WORDSIZE; i++ ) destination->bits[i] = source->bits[i]; error_occurred = FALSE; } /************************************************************************** Iterate(s, f) Returns: void Purpose: Perform some application-defined function f on each element of set s. The function f() should be of the form: boolean f(e) elementType e; The iteration will continue as long as more elements remain in the set and f() returns TRUE. Plan: Notes: There is no guaranteed order in which the elements are passed to f(). **/ void Iterate(s, f) set *s; /* in: the set to iterate through. */ boolean (*f)(); /* in: the function to perform on the elements. */ { register int i, j, Number_Of_Bytes; Number_Of_Bytes = (s->upper - s->lower)/WORDSIZE + 1; error_occurred = FALSE; for ( i = 0; i < Number_Of_Bytes; i++ ) for ( j = 0; j < WORDSIZE; j++ ) if ( (s->bits[i] >> j) % 2 ) if ( ! (*f)(j + i*WORDSIZE + s->lower) ) return; } /************************************************************************** Error_Occurred() Returns: boolean Purpose: Indicate whether the last operation could not be completed due to some error. Plan: The routine's value is the value of the local variable "error_occurred". Notes: It is the responsibility of each routine to correctly set "error_occurred". **/ boolean Error_Occurred() { return error_occurred; }