diff -r 0f94d369bb02 -r 1bcaac272cdf ucx/map.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/map.c Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,390 @@ +/* + * + */ + +#include +#include + +#include "map.h" + +UcxMap *ucx_map_new(size_t size) { + if(size == 0) { + size = 16; + } + + UcxMap *map = (UcxMap*)malloc(sizeof(UcxMap)); + if(map == NULL) { + return NULL; + } + + map->map = (UcxMapElement**)calloc(size, sizeof(UcxMapElement*)); + if(map->map == NULL) { + free(map); + return NULL; + } + map->size = size; + map->count = 0; + + return map; +} + +void ucx_map_free_elmlist(UcxMap *map) { + for (size_t n = 0 ; n < map->size ; n++) { + UcxMapElement *elem = map->map[n]; + if (elem != NULL) { + do { + UcxMapElement *next = elem->next; + free(elem->key.data); + free(elem); + elem = next; + } while (elem != NULL); + } + } + free(map->map); +} + +void ucx_map_free(UcxMap *map) { + ucx_map_free_elmlist(map); + free(map); +} + +int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to, + copy_func fnc, void *data) { + UcxMapIterator i = ucx_map_iterator(from); + void *value; + UCX_MAP_FOREACH(value, i) { + int ret = ucx_map_put(to, i.cur->key, fnc ? fnc(value, data) : value); + if(ret != 0) { + return 1; + } + } + return 0; +} + +UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data) { + size_t bs = (map->count * 5) >> 1; + UcxMap *newmap = ucx_map_new(bs > map->size ? bs : map->size); + if(newmap == NULL) { + return NULL; + } + ucx_map_copy(map, newmap, fnc, data); + return newmap; +} + +int ucx_map_rehash(UcxMap *map) { + size_t load = (map->size * 3) >> 2; + if (map->count > load) { + UcxMap oldmap; + oldmap.map = map->map; + oldmap.size = map->size; + oldmap.count = map->count; + + map->size = (map->count * 5) >> 1; + map->map = (UcxMapElement**)calloc(map->size, sizeof(UcxMapElement*)); + if(map->map == NULL) { + *map = oldmap; + return 1; + } + map->count = 0; + ucx_map_copy(&oldmap, map, NULL, NULL); + + /* free the UcxMapElement list of oldmap */ + ucx_map_free_elmlist(&oldmap); + } + return 0; +} + +int ucx_map_put(UcxMap *map, UcxKey key, void *data) { + if(key.hash == 0) { + key.hash = ucx_hash((char*)key.data, key.len); + } + + size_t slot = key.hash%map->size; + UcxMapElement *restrict elm = map->map[slot]; + UcxMapElement *restrict prev = NULL; + + while (elm != NULL && elm->key.hash < key.hash) { + prev = elm; + elm = elm->next; + } + + if (elm == NULL || elm->key.hash != key.hash) { + UcxMapElement *e = (UcxMapElement*)malloc(sizeof(UcxMapElement)); + if(e == NULL) { + return -1; + } + e->key.data = NULL; + if (prev) { + prev->next = e; + } else { + map->map[slot] = e; + } + e->next = elm; + elm = e; + } + + if(elm->key.data == NULL) { + void *kd = malloc(key.len); + if (kd == NULL) { + return -1; + } + memcpy(kd, key.data, key.len); + key.data = kd; + elm->key = key; + map->count++; + } + elm->data = data; + + return 0; +} + +void* ucx_map_get_and_remove(UcxMap *map, UcxKey key, _Bool remove) { + if(key.hash == 0) { + key.hash = ucx_hash((char*)key.data, key.len); + } + + size_t slot = key.hash%map->size; + UcxMapElement *restrict elm = map->map[slot]; + UcxMapElement *restrict pelm = NULL; + while (elm && elm->key.hash <= key.hash) { + if(elm->key.hash == key.hash) { + int n = (key.len > elm->key.len) ? elm->key.len : key.len; + if (memcmp(elm->key.data, key.data, n) == 0) { + void *data = elm->data; + if (remove) { + if (pelm) { + pelm->next = elm->next; + } else { + map->map[slot] = elm->next; + } + free(elm); + map->count--; + } + + return data; + } + } + pelm = elm; + elm = pelm->next; + } + + return NULL; +} + +void *ucx_map_get(UcxMap *map, UcxKey key) { + return ucx_map_get_and_remove(map, key, 0); +} + +void *ucx_map_remove(UcxMap *map, UcxKey key) { + return ucx_map_get_and_remove(map, key, 1); +} + +UcxKey ucx_key(void *data, size_t len) { + UcxKey key; + key.data = data; + key.len = len; + key.hash = ucx_hash((const char*) data, len); + return key; +} + + +int ucx_hash(const char *data, size_t len) { + /* murmur hash 2 */ + + int m = 0x5bd1e995; + int r = 24; + + int h = 25 ^ len; + + int i = 0; + while (len >= 4) { + int k = data[i + 0] & 0xFF; + k |= (data[i + 1] & 0xFF) << 8; + k |= (data[i + 2] & 0xFF) << 16; + k |= (data[i + 3] & 0xFF) << 24; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + i += 4; + len -= 4; + } + + switch (len) { + case 3: h ^= (data[i + 2] & 0xFF) << 16; + /* no break */ + case 2: h ^= (data[i + 1] & 0xFF) << 8; + /* no break */ + case 1: h ^= (data[i + 0] & 0xFF); h *= m; + /* no break */ + } + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} + +UcxMapIterator ucx_map_iterator(UcxMap *map) { + UcxMapIterator i; + i.map = map; + i.cur = NULL; + i.index = 0; + return i; +} + +int ucx_map_iter_next(UcxMapIterator *i, void **elm) { + UcxMapElement *e = i->cur; + + if(e == NULL) { + e = i->map->map[0]; + } else { + e = e->next; + } + + while(i->index < i->map->size) { + if(e != NULL) { + if(e->data != NULL) { + i->cur = e; + *elm = e->data; + return 0; + } + + e = e->next; + } else { + i->index++; + + if(i->index < i->map->size) { + e = i->map->map[i->index]; + } + } + } + + return 1; +} + +int ucx_map_load_enc(UcxMap *map, FILE *f, UcxAllocator allocator, + ucx_map_coder decoder, void* decdata) { + + int c; int r, n; + + char *key, *value; + + while ((c = fgetc(f)) > 0) { + /* Discard leading spaces and comments */ + if (c < 33) continue; + if (c == '#' || c == '!') { + while ((c = (char) fgetc(f)) > 0) { + if (c == '\n') break; + } + continue; + } + + /* read into key buffer */ + n = 16; + key = (char*) malloc(n); + r = 0; + do { + if (c == '=') break; + if (r > n - 2) { + n *= 2; + key = (char*) realloc(key, n); + } + key[r] = c; + r++; + } while ((c = fgetc(f)) > 0); + if (c <= 0) { + free(key); + return 1; + } + key[r] = 0; + while (key[--r] == ' ') key[r] = 0; + + /* skip whitespaces */ + while ((c = fgetc(f)) > 0) { + if (c > 32) break; + } + if (c <= 0) { + free(key); + return 1; + } + + /* read into value buffer */ + n = 64; + value = (char*) malloc(n); + r = 0; + do { + if (c == '\n') break; + if (r > n - 2) { + n *= 2; + value = (char*) realloc(value, n); + } + value[r] = c; + r++; + } while ((c = fgetc(f)) > 0); + value[r] = 0; + while (value[--r] < 33) value[r] = 0; + + if (decoder) { + size_t decodedSize; + void *decoded = decoder(value, decdata, &decodedSize); + free(value); + value = (char*) decoded; + r = decodedSize; + } else { + r += 2; + value = (char*) realloc(value, r); + } + + if (allocator.pool) { + void *pooledValue = allocator.malloc(allocator.pool, r); + memcpy(pooledValue, value, r); + free(value); + value = (char*) pooledValue; + } + + ucx_map_cstr_put(map, key, value); + free(key); + } + + return 0; +} + +int ucx_map_store_enc(UcxMap *map, FILE *f, + ucx_map_coder encoder, void *encdata) { + UcxMapIterator iter = ucx_map_iterator(map); + char *k, *v; + sstr_t key, value; + int written; + + UCX_MAP_FOREACH(v, iter) { + k = (char*) iter.cur->key.data; + key = sstr(k); + if (encoder) { + size_t encodedSize; + void *encoded = encoder(v, encdata, &encodedSize); + value = sstrn((char*) encoded,encodedSize - 1); + } else { + value = sstr(v); + } + + written = 0; + written += fwrite(key.ptr, 1, key.length, f); + written += fwrite(" = ", 1, 3, f); + written += fwrite(value.ptr, 1, value.length, f); + written += fwrite("\n", 1, 1, f); + + if (encoder) { + free(value.ptr); + } + + if (written != key.length + value.length + 4) return 1; + } + + return 0; +}