home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Datafile PD-CD 4
/
DATAFILE_PDCD4.iso
/
unix
/
unixtools
/
util
/
c
/
map
< prev
next >
Wrap
Text File
|
1992-07-21
|
11KB
|
466 lines
/* > C.Map - Map data type */
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "map.h"
#ifdef test
#include <stdio.h>
#endif
/* Return values from functions */
#define OK 1
#define ERR 0
/* Utility function - find a binding in a map */
static link find (const map m, const void *domain, int *bucket, link *prev)
{
link this;
link p;
int i;
p = NULL;
i = (m->hash)(domain) % m->buckets;
if ( bucket != NULL )
*bucket = i;
this = m->bucket[i];
while ( this != NULL )
{
if ( memcmp(domain,this->data,m->domain_size) == 0 )
{
if ( prev != NULL )
*prev = p;
return this;
}
else
{
p = this;
this = this->next;
}
}
if ( prev != NULL )
*prev = p;
return NULL;
}
/* General component routines */
map map_new (int domain_len, int range_len, int buckets, int (*hash)(const void *))
{
register map m;
int i;
m = malloc(sizeof(struct map));
if ( m == NULL )
return NULL;
m->bucket = malloc(buckets * ( sizeof(struct link) - 1 ));
if ( m->bucket == NULL )
{
free(m);
return NULL;
}
for ( i = 0; i < buckets; ++i )
m->bucket[i] = NULL;
m->hash = hash;
m->buckets = buckets;
m->domain_size = domain_len;
m->range_size = range_len;
return m;
}
void map_free (map m)
{
map_clear(m);
free(m->bucket);
free(m);
}
void map_clear (map m)
{
int i;
link this_entry;
link next_entry;
for ( i = 0; i < m->buckets; ++i )
{
this_entry = m->bucket[i];
while ( this_entry != NULL )
{
next_entry = this_entry->next;
free(this_entry);
this_entry = next_entry;
}
m->bucket[i] = NULL;
}
}
int map_copy (map m1, const map m2)
{
link from, to;
link new;
int size;
int i;
if ( m1->domain_size != m2->domain_size )
return ERR;
if ( m1->range_size != m2->range_size )
return ERR;
if ( m1->buckets != m2->buckets )
return ERR;
if ( m1->hash != m2->hash )
return ERR;
map_clear(m1);
size = m2->domain_size + m2->range_size;
for ( i = 0; i < m2->buckets; ++i )
{
from = m2->bucket[i];
if ( from == NULL )
m1->bucket[i] = NULL;
else
{
new = malloc(sizeof(struct link) - 1 + size);
if ( new == NULL )
{
map_clear(m1);
return ERR;
}
memcpy(new->data,from->data,size);
new->next = NULL;
m1->bucket[i] = new;
to = new;
from = from->next;
while ( from != NULL )
{
new = malloc(sizeof(struct link) - 1 + size);
if ( new == NULL )
{
map_clear(m1);
return ERR;
}
memcpy(new->data,from->data,size);
new->next = NULL;
to->next = new;
to = to->next;
from = from->next;
}
}
}
return OK;
}
int map_equal (const map m1, const map m2)
{
link p1;
link p2;
void *v1;
void *v2;
int count1;
int count2;
int i;
int d_size;
int r_size;
if ( m1->domain_size != m2->domain_size )
return 0;
if ( m1->range_size != m2->range_size )
return 0;
if ( m1->buckets != m2->buckets )
return 0;
if ( m1->hash != m2->hash )
return 0;
d_size = m1->domain_size;
r_size = m1->range_size;
for ( i = 0; i < m1->buckets; ++i )
{
if ( m1->bucket[i] == NULL && m2->bucket[i] != NULL )
return 0;
if ( m2->bucket[i] == NULL && m1->bucket[i] != NULL )
return 0;
p1 = m1->bucket[i];
count1 = 0;
while ( p1 != NULL )
{
v1 = &p1->data[0];
for ( p2 = m2->bucket[i]; p2 != NULL; p2 = p2->next )
{
v2 = &p2->data[0];
if ( memcmp(v1,v2,d_size) == 0 )
break;
}
if ( p2 == NULL )
return 0;
v1 = &p1->data[d_size];
v2 = &p2->data[d_size];
if ( memcmp(v1,v2,r_size) != 0 )
return 0;
++count1;
p1 = p1->next;
}
count2 = 0;
for ( p2 = m2->bucket[i]; p2 != NULL; p2 = p2->next )
++count2;
if ( count1 != count2 )
return 0;
}
return 1;
}
int map_empty (const map m)
{
int i;
for ( i = 0; i < m->buckets; ++i )
if ( m->bucket[i] != NULL )
return 0;
return 1;
}
int map_size (const map m)
{
link p;
int i;
int count = 0;
for ( i = 0; i < m->buckets; ++i )
{
for ( p = m->bucket[i]; p != NULL; p = p->next )
++count;
}
return count;
}
int map_iterate (const map m, int (*process)(void *, void *))
{
link p;
int i;
int ret;
void *domain;
void *range;
for ( i = 0; i < m->buckets; ++i )
{
for ( p = m->bucket[i]; p != NULL; p = p->next )
{
domain = &p->data[0];
range = &p->data[m->domain_size];
ret = process(domain,range);
/* Non-zero => stop processing here */
/* Negative => Abnormal (error) termination */
if ( ret != 0 )
return ( ret >= 0 );
}
}
return OK;
}
/* Map-specific routines */
int map_bind (map m, const void *domain_val, const void *range_val)
{
link this;
link new;
int i;
this = find(m,domain_val,&i,NULL);
if ( this != NULL )
return ERR;
new = malloc(sizeof(struct link) - 1 + m->domain_size + m->range_size);
if ( new == NULL )
return ERR;
memcpy(&new->data[0],domain_val,m->domain_size);
memcpy(&new->data[m->domain_size],range_val,m->range_size);
new->next = m->bucket[i];
m->bucket[i] = new;
return OK;
}
int map_unbind (map m, const void *domain_val)
{
link this;
link prev;
int i;
this = find(m,domain_val,&i,&prev);
if ( this == NULL )
return ERR;
if ( prev == NULL )
m->bucket[i] = this->next;
else
prev->next = this->next;