1
Name:
Joints, Simon Peyote
2008-03-25 17:22
I want to create a linked list data-structure in C, but I do not want to have to malloc any memory. Is it possible to do this in a way that makes it simple to traverse and add to the list?
Regards,
Simon Peyote Joints
12
Name:
Anonymous
2008-03-25 17:52
#include "HashMap.h"
#include <stdlib.h>
#include <string.h>
enum EntryState {
ES_EMPTY = 0,
ES_SINGLE,
ES_BUCKET
};
static size_t hash_sdbm( const char *s ) {
size_t hash = 0, c;
unsigned char *us = (unsigned char*) s;
while ( c = *us++ )
hash = c + ( hash << 6 ) + ( hash << 16 ) - hash;
return hash;
}
HashMap hashmap_alloc() {
return hashmap_alloc_size( 1024 );
}
HashMap hashmap_alloc_size( size_t s ) {
HashMap ret;
ret.size = s;
ret.data = calloc( s, sizeof( HashMapEntry ) );
return ret;
}
HashMap hashmap_copy( HashMap* h ) {
HashMap ret;
size_t i, j;
ret.size = h->size;
ret.data = malloc( h->size * sizeof( HashMapEntry ) );
for ( i = 0; i < h->size; ++i ) {
HashMapEntry *he = &h->data[i] , *re = &ret.data[i] ;
re->state = he->state;
if ( he->state == ES_SINGLE ) {
re->entry.value = he->entry.value;
re->entry.key = malloc( strlen( he->entry.key ) + 1 );
strcpy( re->entry.key, he->entry.key );
}
else if ( he->state == ES_BUCKET ) {
re->bucket = vector_alloc();
for ( j = 0; j < vector_size( &he->bucket ); ++j ) {
KeyValuePair *kvp = vector_index( &he->bucket, j );
KeyValuePair *nkvp = malloc( sizeof( KeyValuePair ) );
nkvp->key = malloc( strlen( kvp->key ) + 1 );
strcpy( nkvp->key, kvp->key );
nkvp->value = kvp->value;
vector_push_back( &re->bucket, nkvp );
}
}
}
return ret;
}
void hashmap_free( HashMap* h ) {
size_t i, j;
for ( i = 0; i < h->size; ++i ) {
HashMapEntry *he = &h->data[i] ;
if ( he->state == ES_SINGLE ) {
free( he->entry.key );
}
else if ( he->state == ES_BUCKET ) {
for ( j = 0; i < vector_size( &he->bucket ); ++j ) {
KeyValuePair *kvp = vector_index( &he->bucket, j );
free( kvp->key );
free( kvp );
}
vector_free( &he->bucket );
}
}
/* free the data */
free( h->data );
}
bool hashmap_haskey( HashMap* h, const char* k ) {
return hashmap_get( h, k ) != 0;
}
static HashMapEntry* hashmap_getentry( HashMap* h, const char* k ) {
size_t index = hash_sdbm( k ) % h->size;
return &h->data[ index ];
}
void* hashmap_get( HashMap* h, const char* k ) {
HashMapEntry *e = hashmap_getentry( h, k );
size_t i;
if ( e->state == ES_SINGLE ) {
if ( !strcmp( e->entry.key, k ) )
return e->entry.value;
return 0;
}
else if ( e->state == ES_BUCKET ) {
Vector *v = &e->bucket;
for ( i = 0; i < v->size; ++i ) {
KeyValuePair *kvp = vector_index( v, i );
if ( !strcmp( kvp->key, k ) )
return kvp->value;
}
return 0;
}
return 0;
}
void hashmap_insert( HashMap* h, const char* k, void* v ) {
HashMapEntry *e = hashmap_getentry( h, k );
if ( e->state == ES_EMPTY ) {
e->state = ES_SINGLE;
e->entry.key = malloc( strlen( k ) + 1 );
strcpy( e->entry.key, k );
e->entry.value = v;
}
else if ( e->state == ES_SINGLE ) {
KeyValuePair kvp = e->entry;
KeyValuePair *pkvp;
e->state = ES_BUCKET;
e->bucket = vector_alloc();
pkvp = malloc( sizeof( KeyValuePair ) );
pkvp->key = kvp.key;
pkvp->value = kvp.value;
vector_push_back( &e->bucket, pkvp );
}
if ( e->state == ES_BUCKET ) {
KeyValuePair *pkvp;
pkvp = malloc( sizeof( KeyValuePair ) );
pkvp->key = malloc( strlen( k ) + 1 );
strcpy( pkvp->key, k );
pkvp->value = v;
vector_push_back( &e->bucket, pkvp );
}
}
void hashmap_remove( HashMap* h, const char* k ) {
HashMapEntry *e = hashmap_getentry( h, k );
size_t i;
if ( e->state == ES_SINGLE ) {
free( e->entry.key );
e->state = ES_EMPTY;
}
else if ( e->state == ES_BUCKET ) {
Vector cv = vector_copy( &e->bucket );
vector_clear( &e->bucket );
for ( i = 0; i < vector_size( &cv ); ++i ) {
KeyValuePair *kvp = vector_index( &cv, i );
if ( !strcmp( kvp->key, k ) ) {
free( kvp->key );
free( kvp );
}
else {
vector_push_back( &e->bucket, kvp );
}
}
vector_free( &cv );
if ( vector_empty( &e->bucket ) ) {
vector_free( &e->bucket );
e->state = ES_EMPTY;
}
}
}