Mon, 06 May 2013 13:44:27 +0200
some fixes and new public APIs
/* * */ #include <stdlib.h> #include <string.h> #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(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); free(map); } int ucx_map_copy(UcxMap *from, UcxMap *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); } 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 *elm = map->map[slot]; UcxMapElement *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 == NULL) { map->map[slot] = e; } else { prev->next = 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(UcxMap *map, UcxKey key) { if(key.hash == 0) { key.hash = ucx_hash((char*)key.data, key.len); } UcxMapElement *elm = map->map[key.hash%map->size]; while (elm != NULL && 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) { return elm->data; } } elm = elm->next; } return NULL; } UcxKey ucx_key(void *data, size_t len) { UcxKey key; key.data = data; key.len = len; key.hash = ucx_hash(data, len); return key; } int ucx_hash(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 = malloc(n); r = 0; do { if (c == '=') break; if (r > n - 2) { n *= 2; key = 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 = malloc(n); r = 0; do { if (c == '\n') break; if (r > n - 2) { n *= 2; value = 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 = decoded; r = decodedSize; } else { r += 2; value = realloc(value, r); } if (allocator.pool) { void *pooledValue = allocator.malloc(allocator.pool, r); memcpy(pooledValue, value, r); free(value); value = 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(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; }