home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Datafile PD-CD 4
/
DATAFILE_PDCD4.iso
/
unix
/
unixtools
/
util
/
c
/
bag
< prev
next >
Wrap
Text File
|
1992-07-21
|
13KB
|
526 lines
/* C.Bag: Bag data type */
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "bag.h"
#ifdef test
#include <stdio.h>
#endif
struct link
{
struct link *next;
int count;
char data[1];
};
typedef struct link *link;
/* Return values from functions */
#define OK 1
#define ERR 0
/* Utility function - find an element in a bag */
static link find (const bag b, const void *element, link *prev)
{
link this;
link p = NULL;
const int size = b->obj_size;
for ( this = b->first; this != NULL; this = this->next )
{
if ( memcmp(element,this->data,size) == 0 )
{
if ( prev != NULL )
*prev = p;
return this;
}
p = this;
}
return NULL;
}
/* General component routines */
bag bag_new (int obj_len)
{
register bag b;
b = malloc(sizeof(struct bag));
if ( b == NULL )
return NULL;
b->first = NULL;
b->obj_size = obj_len;
return b;
}
void bag_free (bag b)
{
bag_clear(b);
free(b);
}
void bag_clear (bag b)
{
link this_entry = b->first;
link next_entry;
while ( this_entry != NULL )
{
next_entry = this_entry->next;
free(this_entry);
this_entry = next_entry;
}
b->first = NULL;
}
int bag_copy (bag b1, const bag b2)
{
link p;
link new;
link last;
int size;
if ( b1->obj_size != b2->obj_size )
return ERR;
bag_clear(b1);
last = (link)b1;
size = b2->obj_size;
for ( p = b2->first; p != NULL; p = p->next )
{
new = malloc(sizeof(struct link) - 1 + size);
if ( new == NULL )
{
bag_clear(b1);
return ERR;
}
last->next = new;
memcpy(new->data,p->data,size);
new->count = p->count;
last = new;
}
last->next = NULL;
return OK;
}
int bag_equal (const bag b1, const bag b2)
{
link p;
link q;
int n1 = 0;
int n2 = 0;
if ( b1->obj_size != b2->obj_size )
return 0;
/* For every element of b1, look for it in b2 */
for ( p = b1->first; p != NULL; p = p->next )
{
q = find(b2,p->data,NULL);
/* If it's not in b2, or the counts are different, b1 != b2 */
if ( q == NULL || p->count != q->count )
return 0;
/* Count the unique elements of b1 */
++n1;
}
/* Count the unique elements of b2 */
for ( p = b2->first; p != NULL; p = p->next )
++n2;
/* The bags differ if there are elements in b1 not in b2 */
return ( n1 == n2 );
}
int bag_empty (const bag b)
{
return ( b->first == NULL );
}
int bag_size (const bag b)
{
int i = 0;
link p;
for ( p = b->first; p != NULL; p = p->next )
i += p->count;
return i;
}
int bag_iterate (const bag b, int (*process)(void *, int))
{
int ret = 0;
link p;
for ( p = b->first; p != NULL; p = p->next )
{
ret = (*process)(p->data,p->count);
/* Non-zero => stop processing here */
if ( ret != 0 )
break;
}
/* Negative => Abnormal (error) termination */
return ( ret >= 0 );
}
/* bag-specific routines */
int bag_add (bag b, const void *object)
{
link new;
new = find(b,object,NULL);
if ( new != NULL )
{
++new->count;
return OK;
}
new = malloc(sizeof(struct link) - 1 + b->obj_size);
if ( new == NULL )
return ERR;
memcpy(new->data,object,b->obj_size);
new->count = 1;
new->next = b->first;
b->first = new;
return OK;
}
int bag_remove (bag b, const void *object)
{
link p;
link prev;
p = find(b,object,&prev);
if ( p == NULL )
return ERR;
if ( p->count > 1 )
{
--p->count;
return OK;
}
if ( prev == NULL )
b->first = p->next;
else
prev->next = p->next;
free(p);
return OK;
}
int bag_member (const bag b, const void *object)
{
return ( find(b,object,NULL) != NULL );
}
int bag_count (const bag b, const void *object)
{
link p = find(b,object,NULL);
return ( p != NULL ? p->count : 0 );
}
int bag_union (bag b1, const bag b2, const bag b3)
{
link p;
link new;
/* Check with b2's length occurs in bag_copy */
if ( b1->obj_size != b3->obj_size )
return ERR;
if ( !bag_copy(b1,b2) )
return ERR;
for ( p = b3->first; p != NULL; p = p->next )
{
new = find(b1,p->data,NULL);
if ( new != NULL )
{
new->count += p->count;
continue;
}
new = malloc(sizeof(struct link) - 1 + b1->obj_size);
if ( new == NULL )
return ERR;
memcpy(new->data,p->data,b1->obj_size);
new->count = 1;
new->next = b1->first;
b1->first = new;
}
return OK;
}
int bag_intersection (bag b1, const bag b2, const bag b3)
{
link p;
link q;
link new;
if ( b1->obj_size != b2->obj_size || b1->obj_size != b3->obj_size )
return ERR;
bag_clear(b1);
for ( p = b2->first; p != NULL; p = p->next )
{
q = find(b3,p->data,NULL);
if ( q == NULL )
continue;
new = malloc(sizeof(struct link) - 1 + b1->obj_size);
if ( new == NULL )
return ERR;
memcpy(new->data,p->data,b1->obj_size);
new->count = ( p->count < q->count ? p->count : q->count );
new->next = b1->first;
b1->first = new;
}
return OK;
}
int bag_difference (bag b1, const bag b2, const bag b3)
{
link p;
link q;
link new;
if ( b1->obj_size != b2->obj_size || b1->obj_size != b3->obj_size )
return ERR;
bag_clear(b1);
for ( p = b2->first; p != NULL; p = p->next )
{
q = find(b3,p->data,NULL);
if ( q != NULL && p->count <= q->count )
continue;
new = malloc(sizeof(struct link) - 1 + b1->obj_size);
if ( new == NULL )
return ERR;
memcpy(new->data,p->data,b1->obj_size);
new->count = p->count;
if ( q != NULL )
new->count -= q->count;
new->next = b1->first;
b1->first = new;
}
return OK;
}
int bag_unique_count (const bag b)
{
int i = 0;
link p;
for ( p = b->first; p != NULL; p = p->next )
++i;
return i;
}
int bag_subset (const bag b1, const bag b2)
{
link p;
link q;
if ( b1->obj_size != b2->obj_size )
return 0;
/* For every element of b1, look for it in b2 */
for ( p = b1->first; p != NULL; p = p->next )
{
q = find(b2,p->data,NULL);
/* If it's not in b2, or in less times, b1 is not a subset */
if ( q == NULL || p->count > q->count )
return 0;
}
return 1;