ucx/map.c

Mon, 08 Oct 2012 12:29:27 +0200

author
Mike Becker <universe@uap-core.de>
date
Mon, 08 Oct 2012 12:29:27 +0200
changeset 53
e533c170bfb8
parent 52
34f50d0bada4
child 67
27e67e725d35
permissions
-rw-r--r--

added ucx_map_remove

     1 /*
     2  *
     3  */
     5 #include <stdlib.h>
     6 #include <string.h>
     8 #include "map.h"
    10 UcxMap *ucx_map_new(size_t size) {
    11     if(size == 0) {
    12         size = 16;
    13     }
    15     UcxMap *map = (UcxMap*)malloc(sizeof(UcxMap));
    16     if(map == NULL) {
    17         return NULL;
    18     }
    20     map->map = (UcxMapElement**)calloc(size, sizeof(UcxMapElement*));
    21     if(map->map == NULL) {
    22         free(map);
    23         return NULL;
    24     }
    25     map->size = size;
    26     map->count = 0;
    28     return map;
    29 }
    31 void ucx_map_free(UcxMap *map) {
    32     for (size_t n = 0 ; n < map->size ; n++) {
    33         UcxMapElement *elem = map->map[n];
    34         if (elem != NULL) {
    35             do {
    36                 UcxMapElement *next = elem->next;
    37                 free(elem->key.data);
    38                 free(elem);
    39                 elem = next;
    40             } while (elem != NULL);
    41         }
    42     }
    43     free(map->map);
    44     free(map);
    45 }
    47 int ucx_map_copy(UcxMap *from, UcxMap *to, copy_func fnc, void *data) {
    48     UcxMapIterator i = ucx_map_iterator(from);
    49     void *value;
    50     UCX_MAP_FOREACH(value, i) {
    51         int ret = ucx_map_put(to, i.cur->key, fnc ? fnc(value, data) : value);
    52         if(ret != 0) {
    53             return 1;
    54         }
    55     }
    56     return 0;
    57 }
    59 UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data) {
    60     size_t bs = (map->count * 5) >> 1;
    61     UcxMap *newmap = ucx_map_new(bs > map->size ? bs : map->size);
    62     if(newmap == NULL) {
    63         return NULL;
    64     }
    65     ucx_map_copy(map, newmap, fnc, data);
    66     return newmap;
    67 }
    69 int ucx_map_rehash(UcxMap *map) {
    70     size_t load = (map->size * 3) >> 2;
    71     if (map->count > load) {
    72         UcxMap oldmap;
    73         oldmap.map = map->map;
    74         oldmap.size = map->size;
    75         oldmap.count = map->count;
    77         map->size = (map->count * 5) >> 1;
    78         map->map = (UcxMapElement**)calloc(map->size, sizeof(UcxMapElement*));
    79         if(map->map == NULL) {
    80             *map = oldmap;
    81             return 1;
    82         }
    83         map->count = 0;
    84         ucx_map_copy(&oldmap, map, NULL, NULL);
    85     }
    86     return 0;
    87 }
    89 int ucx_map_put(UcxMap *map, UcxKey key, void *data) {
    90     if(key.hash == 0) {
    91         key.hash = ucx_hash((char*)key.data, key.len);
    92     }
    94     size_t slot = key.hash%map->size;
    95     UcxMapElement *elm = map->map[slot];
    96     UcxMapElement *prev = NULL;
    98     while (elm != NULL && elm->key.hash < key.hash) {
    99         prev = elm;
   100         elm = elm->next;
   101     }
   103     if (elm == NULL || elm->key.hash != key.hash) {
   104         UcxMapElement *e = (UcxMapElement*)malloc(sizeof(UcxMapElement));
   105         if(e == NULL) {
   106             return -1;
   107         }
   108         e->key.data = NULL;
   109         if (prev) {
   110             prev->next = e;
   111         } else {
   112             map->map[slot] = e;
   113         }
   114         e->next = elm;
   115         elm = e;
   116     }
   118     if(elm->key.data == NULL) {
   119         void *kd = malloc(key.len);
   120         if (kd == NULL) {
   121             return -1;
   122         }
   123         memcpy(kd, key.data, key.len);
   124         key.data = kd;
   125         elm->key = key;
   126         map->count++;
   127     }
   128     elm->data = data;
   130     return 0;
   131 }
   133 void* ucx_map_get_and_remove(UcxMap *map, UcxKey key, _Bool remove) {
   134     if(key.hash == 0) {
   135         key.hash = ucx_hash((char*)key.data, key.len);
   136     }
   138     size_t slot = key.hash%map->size;
   139     UcxMapElement *elm = map->map[slot];
   140     UcxMapElement *pelm = NULL;
   141     while (elm && elm->key.hash <= key.hash) {
   142         if(elm->key.hash == key.hash) {
   143             int n = (key.len > elm->key.len) ? elm->key.len : key.len;
   144             if (memcmp(elm->key.data, key.data, n) == 0) {
   145                 void *data = elm->data;
   146                 if (remove) {
   147                     if (pelm) {
   148                         pelm->next = elm->next;
   149                     } else {
   150                         map->map[slot] = elm->next;
   151                     }
   152                     free(elm);
   153                     map->count--;
   154                 }
   156                 return data;
   157             }
   158         }
   159         pelm = elm;
   160         elm = pelm->next;
   161     }
   163     return NULL;
   164 }
   166 void *ucx_map_get(UcxMap *map, UcxKey key) {
   167     return ucx_map_get_and_remove(map, key, 0);
   168 }
   170 void *ucx_map_remove(UcxMap *map, UcxKey key) {
   171     return ucx_map_get_and_remove(map, key, 1);
   172 }
   174 UcxKey ucx_key(void *data, size_t len) {
   175     UcxKey key;
   176     key.data = data;
   177     key.len = len;
   178     key.hash = ucx_hash(data, len);
   179     return key;
   180 }
   183 int ucx_hash(char *data, size_t len) {
   184     /* murmur hash 2 */
   186     int m = 0x5bd1e995;
   187     int r = 24;
   189     int h = 25 ^ len;
   191     int i = 0;
   192     while (len >= 4) {
   193         int k = data[i + 0] & 0xFF;
   194         k |= (data[i + 1] & 0xFF) << 8;
   195         k |= (data[i + 2] & 0xFF) << 16;
   196         k |= (data[i + 3] & 0xFF) << 24;
   198         k *= m;
   199         k ^= k >> r;
   200         k *= m;
   202         h *= m;
   203         h ^= k;
   205         i += 4;
   206         len -= 4;
   207     }
   209     switch (len) {
   210         case 3: h ^= (data[i + 2] & 0xFF) << 16;
   211         /* no break */
   212         case 2: h ^= (data[i + 1] & 0xFF) << 8;
   213         /* no break */
   214         case 1: h ^= (data[i + 0] & 0xFF); h *= m;
   215         /* no break */
   216     }
   218     h ^= h >> 13;
   219     h *= m;
   220     h ^= h >> 15;
   222     return h;
   223 }
   225 UcxMapIterator ucx_map_iterator(UcxMap *map) {
   226     UcxMapIterator i;
   227     i.map = map;
   228     i.cur = NULL;
   229     i.index = 0;
   230     return i;
   231 }
   233 int ucx_map_iter_next(UcxMapIterator *i, void **elm) {
   234     UcxMapElement *e = i->cur;
   236     if(e == NULL) {
   237         e = i->map->map[0];
   238     } else {
   239         e = e->next;
   240     }
   242     while(i->index < i->map->size) {
   243         if(e != NULL) {
   244             if(e->data != NULL) {
   245                 i->cur = e;
   246                 *elm = e->data;
   247                 return 0;
   248             }
   250             e = e->next;
   251         } else {
   252             i->index++;
   254             if(i->index < i->map->size) {
   255                 e = i->map->map[i->index];
   256             }
   257         }
   258     }
   260     return 1;
   261 }
   263 int ucx_map_load_enc(UcxMap *map, FILE *f, UcxAllocator allocator,
   264         ucx_map_coder decoder, void* decdata) {
   266     int c; int r, n;
   268     char *key, *value;
   270     while ((c = fgetc(f)) > 0) {
   271         /* Discard leading spaces and comments */
   272         if (c < 33) continue;
   273         if (c == '#' || c == '!') {
   274             while ((c = (char) fgetc(f)) > 0) {
   275                 if (c == '\n') break;
   276             }
   277             continue;
   278         }
   280         /* read into key buffer */
   281         n = 16;
   282         key = malloc(n);
   283         r = 0;
   284         do {
   285             if (c == '=') break;
   286             if (r > n - 2) {
   287                 n *= 2;
   288                 key = realloc(key, n);
   289             }
   290             key[r] = c;
   291             r++;
   292         } while ((c = fgetc(f)) > 0);
   293         if (c <= 0) {
   294             free(key);
   295             return 1;
   296         }
   297         key[r] = 0;
   298         while (key[--r] == ' ') key[r] = 0;
   300         /* skip whitespaces */
   301         while ((c = fgetc(f)) > 0) {
   302             if (c > 32) break;
   303         }
   304         if (c <= 0) {
   305             free(key);
   306             return 1;
   307         }
   309         /* read into value buffer */
   310         n = 64;
   311         value = malloc(n);
   312         r = 0;
   313         do {
   314             if (c == '\n') break;
   315             if (r > n - 2) {
   316                 n *= 2;
   317                 value = realloc(value, n);
   318             }
   319             value[r] = c;
   320             r++;
   321         } while ((c = fgetc(f)) > 0);
   322         value[r] = 0;
   323         while (value[--r] < 33) value[r] = 0;
   325         if (decoder) {
   326             size_t decodedSize;
   327             void *decoded = decoder(value, decdata, &decodedSize);
   328             free(value);
   329             value = decoded;
   330             r = decodedSize;
   331         } else {
   332             r += 2;
   333             value = realloc(value, r);
   334         }
   336         if (allocator.pool) {
   337             void *pooledValue = allocator.malloc(allocator.pool, r);
   338             memcpy(pooledValue, value, r);
   339             free(value);
   340             value = pooledValue;
   341         }
   343         ucx_map_cstr_put(map, key, value);
   344         free(key);
   345     }
   347     return 0;
   348 }
   350 int ucx_map_store_enc(UcxMap *map, FILE *f,
   351         ucx_map_coder encoder, void *encdata) {
   352     UcxMapIterator iter = ucx_map_iterator(map);
   353     char *k, *v;
   354     sstr_t key, value;
   355     int written;
   357     UCX_MAP_FOREACH(v, iter) {
   358         k = (char*) iter.cur->key.data;
   359         key = sstr(k);
   360         if (encoder) {
   361             size_t encodedSize;
   362             void *encoded = encoder(v, encdata, &encodedSize);
   363             value = sstrn(encoded,encodedSize - 1);
   364         } else {
   365             value = sstr(v);
   366         }
   368         written = 0;
   369         written += fwrite(key.ptr, 1, key.length, f);
   370         written += fwrite(" = ", 1, 3, f);
   371         written += fwrite(value.ptr, 1, value.length, f);
   372         written += fwrite("\n", 1, 1, f);
   374         if (encoder) {
   375             free(value.ptr);
   376         }
   378         if (written != key.length + value.length + 4) return 1;
   379     }
   381     return 0;
   382 }

mercurial