ucx/map.c

Thu, 28 Feb 2013 08:50:24 +0100

author
Mike Becker <universe@uap-core.de>
date
Thu, 28 Feb 2013 08:50:24 +0100
changeset 103
08018864fb91
parent 95
ecfdc1c4a552
child 107
86b19c98b5fd
permissions
-rw-r--r--

added license and copyright notice to all files

olaf@20 1 /*
universe@103 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
olaf@20 3 *
universe@103 4 * Copyright 2013 Olaf Wintermann. All rights reserved.
universe@103 5 *
universe@103 6 * Redistribution and use in source and binary forms, with or without
universe@103 7 * modification, are permitted provided that the following conditions are met:
universe@103 8 *
universe@103 9 * 1. Redistributions of source code must retain the above copyright
universe@103 10 * notice, this list of conditions and the following disclaimer.
universe@103 11 *
universe@103 12 * 2. Redistributions in binary form must reproduce the above copyright
universe@103 13 * notice, this list of conditions and the following disclaimer in the
universe@103 14 * documentation and/or other materials provided with the distribution.
universe@103 15 *
universe@103 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
universe@103 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
universe@103 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
universe@103 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
universe@103 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
universe@103 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
universe@103 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
universe@103 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
universe@103 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
universe@103 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
universe@103 26 * POSSIBILITY OF SUCH DAMAGE.
olaf@20 27 */
olaf@2 28
olaf@20 29 #include <stdlib.h>
olaf@20 30 #include <string.h>
olaf@20 31
olaf@20 32 #include "map.h"
olaf@20 33
olaf@20 34 UcxMap *ucx_map_new(size_t size) {
olaf@45 35 if(size == 0) {
olaf@45 36 size = 16;
olaf@45 37 }
olaf@45 38
olaf@20 39 UcxMap *map = (UcxMap*)malloc(sizeof(UcxMap));
olaf@20 40 if(map == NULL) {
olaf@20 41 return NULL;
olaf@20 42 }
olaf@20 43
universe@29 44 map->map = (UcxMapElement**)calloc(size, sizeof(UcxMapElement*));
olaf@20 45 if(map->map == NULL) {
olaf@20 46 free(map);
olaf@20 47 return NULL;
olaf@20 48 }
olaf@20 49 map->size = size;
olaf@45 50 map->count = 0;
olaf@20 51
olaf@20 52 return map;
olaf@20 53 }
olaf@20 54
olaf@70 55 void ucx_map_free_elmlist(UcxMap *map) {
universe@29 56 for (size_t n = 0 ; n < map->size ; n++) {
universe@29 57 UcxMapElement *elem = map->map[n];
universe@29 58 if (elem != NULL) {
universe@29 59 do {
universe@29 60 UcxMapElement *next = elem->next;
olaf@30 61 free(elem->key.data);
universe@29 62 free(elem);
universe@29 63 elem = next;
universe@29 64 } while (elem != NULL);
universe@29 65 }
universe@29 66 }
olaf@30 67 free(map->map);
olaf@70 68 }
olaf@70 69
olaf@70 70 void ucx_map_free(UcxMap *map) {
olaf@70 71 ucx_map_free_elmlist(map);
universe@29 72 free(map);
universe@29 73 }
universe@29 74
universe@67 75 int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to,
universe@67 76 copy_func fnc, void *data) {
olaf@52 77 UcxMapIterator i = ucx_map_iterator(from);
olaf@52 78 void *value;
olaf@52 79 UCX_MAP_FOREACH(value, i) {
olaf@52 80 int ret = ucx_map_put(to, i.cur->key, fnc ? fnc(value, data) : value);
olaf@52 81 if(ret != 0) {
olaf@52 82 return 1;
olaf@52 83 }
olaf@52 84 }
olaf@52 85 return 0;
olaf@52 86 }
olaf@52 87
olaf@44 88 UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data) {
universe@51 89 size_t bs = (map->count * 5) >> 1;
olaf@45 90 UcxMap *newmap = ucx_map_new(bs > map->size ? bs : map->size);
olaf@52 91 if(newmap == NULL) {
olaf@52 92 return NULL;
olaf@44 93 }
olaf@52 94 ucx_map_copy(map, newmap, fnc, data);
olaf@44 95 return newmap;
olaf@44 96 }
olaf@44 97
olaf@52 98 int ucx_map_rehash(UcxMap *map) {
universe@51 99 size_t load = (map->size * 3) >> 2;
universe@51 100 if (map->count > load) {
olaf@52 101 UcxMap oldmap;
olaf@52 102 oldmap.map = map->map;
olaf@52 103 oldmap.size = map->size;
olaf@52 104 oldmap.count = map->count;
olaf@52 105
olaf@52 106 map->size = (map->count * 5) >> 1;
olaf@52 107 map->map = (UcxMapElement**)calloc(map->size, sizeof(UcxMapElement*));
olaf@52 108 if(map->map == NULL) {
olaf@52 109 *map = oldmap;
olaf@52 110 return 1;
olaf@52 111 }
olaf@52 112 map->count = 0;
olaf@52 113 ucx_map_copy(&oldmap, map, NULL, NULL);
olaf@70 114
olaf@70 115 /* free the UcxMapElement list of oldmap */
olaf@70 116 ucx_map_free_elmlist(&oldmap);
universe@51 117 }
olaf@52 118 return 0;
universe@51 119 }
universe@51 120
olaf@20 121 int ucx_map_put(UcxMap *map, UcxKey key, void *data) {
olaf@20 122 if(key.hash == 0) {
olaf@20 123 key.hash = ucx_hash((char*)key.data, key.len);
olaf@20 124 }
olaf@20 125
universe@29 126 size_t slot = key.hash%map->size;
universe@67 127 UcxMapElement *restrict elm = map->map[slot];
universe@67 128 UcxMapElement *restrict prev = NULL;
universe@29 129
universe@29 130 while (elm != NULL && elm->key.hash < key.hash) {
universe@29 131 prev = elm;
universe@29 132 elm = elm->next;
universe@29 133 }
universe@29 134
universe@29 135 if (elm == NULL || elm->key.hash != key.hash) {
olaf@20 136 UcxMapElement *e = (UcxMapElement*)malloc(sizeof(UcxMapElement));
olaf@20 137 if(e == NULL) {
olaf@20 138 return -1;
olaf@20 139 }
olaf@30 140 e->key.data = NULL;
universe@53 141 if (prev) {
universe@53 142 prev->next = e;
universe@53 143 } else {
universe@29 144 map->map[slot] = e;
universe@29 145 }
universe@29 146 e->next = elm;
olaf@20 147 elm = e;
olaf@20 148 }
universe@29 149
olaf@30 150 if(elm->key.data == NULL) {
olaf@30 151 void *kd = malloc(key.len);
olaf@30 152 if (kd == NULL) {
olaf@30 153 return -1;
olaf@30 154 }
olaf@30 155 memcpy(kd, key.data, key.len);
olaf@30 156 key.data = kd;
olaf@30 157 elm->key = key;
olaf@45 158 map->count++;
olaf@30 159 }
olaf@20 160 elm->data = data;
olaf@20 161
olaf@20 162 return 0;
olaf@20 163 }
olaf@20 164
universe@53 165 void* ucx_map_get_and_remove(UcxMap *map, UcxKey key, _Bool remove) {
olaf@20 166 if(key.hash == 0) {
olaf@20 167 key.hash = ucx_hash((char*)key.data, key.len);
olaf@20 168 }
olaf@20 169
universe@53 170 size_t slot = key.hash%map->size;
universe@67 171 UcxMapElement *restrict elm = map->map[slot];
universe@67 172 UcxMapElement *restrict pelm = NULL;
universe@53 173 while (elm && elm->key.hash <= key.hash) {
olaf@20 174 if(elm->key.hash == key.hash) {
olaf@20 175 int n = (key.len > elm->key.len) ? elm->key.len : key.len;
universe@29 176 if (memcmp(elm->key.data, key.data, n) == 0) {
universe@53 177 void *data = elm->data;
universe@53 178 if (remove) {
universe@53 179 if (pelm) {
universe@53 180 pelm->next = elm->next;
universe@53 181 } else {
universe@53 182 map->map[slot] = elm->next;
universe@53 183 }
universe@53 184 free(elm);
universe@53 185 map->count--;
universe@53 186 }
universe@53 187
universe@53 188 return data;
olaf@20 189 }
olaf@20 190 }
universe@53 191 pelm = elm;
universe@53 192 elm = pelm->next;
olaf@20 193 }
olaf@20 194
olaf@20 195 return NULL;
olaf@20 196 }
olaf@20 197
universe@53 198 void *ucx_map_get(UcxMap *map, UcxKey key) {
universe@53 199 return ucx_map_get_and_remove(map, key, 0);
universe@53 200 }
universe@53 201
universe@53 202 void *ucx_map_remove(UcxMap *map, UcxKey key) {
universe@53 203 return ucx_map_get_and_remove(map, key, 1);
universe@53 204 }
universe@53 205
olaf@20 206 UcxKey ucx_key(void *data, size_t len) {
olaf@20 207 UcxKey key;
olaf@20 208 key.data = data;
olaf@20 209 key.len = len;
universe@69 210 key.hash = ucx_hash((const char*) data, len);
olaf@20 211 return key;
olaf@20 212 }
olaf@20 213
olaf@20 214
universe@67 215 int ucx_hash(const char *data, size_t len) {
olaf@20 216 /* murmur hash 2 */
olaf@20 217
olaf@20 218 int m = 0x5bd1e995;
olaf@20 219 int r = 24;
olaf@20 220
olaf@20 221 int h = 25 ^ len;
olaf@20 222
olaf@20 223 int i = 0;
olaf@20 224 while (len >= 4) {
olaf@20 225 int k = data[i + 0] & 0xFF;
olaf@20 226 k |= (data[i + 1] & 0xFF) << 8;
olaf@20 227 k |= (data[i + 2] & 0xFF) << 16;
olaf@20 228 k |= (data[i + 3] & 0xFF) << 24;
olaf@20 229
olaf@20 230 k *= m;
olaf@20 231 k ^= k >> r;
olaf@20 232 k *= m;
olaf@20 233
olaf@20 234 h *= m;
olaf@20 235 h ^= k;
olaf@20 236
olaf@20 237 i += 4;
olaf@20 238 len -= 4;
olaf@20 239 }
olaf@20 240
olaf@20 241 switch (len) {
olaf@20 242 case 3: h ^= (data[i + 2] & 0xFF) << 16;
universe@38 243 /* no break */
olaf@20 244 case 2: h ^= (data[i + 1] & 0xFF) << 8;
universe@38 245 /* no break */
olaf@20 246 case 1: h ^= (data[i + 0] & 0xFF); h *= m;
universe@38 247 /* no break */
olaf@20 248 }
olaf@20 249
olaf@20 250 h ^= h >> 13;
olaf@20 251 h *= m;
olaf@20 252 h ^= h >> 15;
olaf@20 253
olaf@20 254 return h;
olaf@20 255 }
olaf@31 256
olaf@31 257 UcxMapIterator ucx_map_iterator(UcxMap *map) {
olaf@31 258 UcxMapIterator i;
olaf@31 259 i.map = map;
olaf@31 260 i.cur = NULL;
olaf@31 261 i.index = 0;
olaf@31 262 return i;
olaf@31 263 }
olaf@31 264
olaf@31 265 int ucx_map_iter_next(UcxMapIterator *i, void **elm) {
olaf@31 266 UcxMapElement *e = i->cur;
olaf@31 267
olaf@31 268 if(e == NULL) {
olaf@31 269 e = i->map->map[0];
olaf@31 270 } else {
olaf@31 271 e = e->next;
olaf@31 272 }
olaf@31 273
olaf@31 274 while(i->index < i->map->size) {
olaf@31 275 if(e != NULL) {
olaf@31 276 if(e->data != NULL) {
olaf@31 277 i->cur = e;
olaf@31 278 *elm = e->data;
olaf@31 279 return 0;
olaf@31 280 }
olaf@31 281
olaf@31 282 e = e->next;
olaf@31 283 } else {
olaf@31 284 i->index++;
olaf@31 285
olaf@31 286 if(i->index < i->map->size) {
olaf@31 287 e = i->map->map[i->index];
olaf@31 288 }
olaf@31 289 }
olaf@31 290 }
olaf@31 291
olaf@31 292 return 1;
olaf@31 293 }
universe@42 294
universe@48 295 int ucx_map_load_enc(UcxMap *map, FILE *f, UcxAllocator allocator,
universe@48 296 ucx_map_coder decoder, void* decdata) {
universe@42 297
universe@43 298 int c; int r, n;
universe@42 299
universe@42 300 char *key, *value;
universe@42 301
universe@43 302 while ((c = fgetc(f)) > 0) {
universe@42 303 /* Discard leading spaces and comments */
universe@43 304 if (c < 33) continue;
universe@42 305 if (c == '#' || c == '!') {
universe@42 306 while ((c = (char) fgetc(f)) > 0) {
universe@42 307 if (c == '\n') break;
universe@42 308 }
universe@42 309 continue;
universe@42 310 }
universe@42 311
universe@42 312 /* read into key buffer */
universe@42 313 n = 16;
universe@69 314 key = (char*) malloc(n);
universe@42 315 r = 0;
universe@42 316 do {
universe@42 317 if (c == '=') break;
universe@42 318 if (r > n - 2) {
universe@42 319 n *= 2;
universe@69 320 key = (char*) realloc(key, n);
universe@42 321 }
universe@42 322 key[r] = c;
universe@42 323 r++;
universe@43 324 } while ((c = fgetc(f)) > 0);
universe@43 325 if (c <= 0) {
universe@42 326 free(key);
universe@42 327 return 1;
universe@42 328 }
universe@42 329 key[r] = 0;
universe@43 330 while (key[--r] == ' ') key[r] = 0;
universe@43 331
universe@43 332 /* skip whitespaces */
universe@43 333 while ((c = fgetc(f)) > 0) {
universe@43 334 if (c > 32) break;
universe@43 335 }
universe@43 336 if (c <= 0) {
universe@43 337 free(key);
universe@43 338 return 1;
universe@43 339 }
universe@42 340
universe@42 341 /* read into value buffer */
universe@42 342 n = 64;
universe@69 343 value = (char*) malloc(n);
universe@42 344 r = 0;
universe@43 345 do {
universe@42 346 if (c == '\n') break;
universe@43 347 if (r > n - 2) {
universe@42 348 n *= 2;
universe@69 349 value = (char*) realloc(value, n);
universe@42 350 }
universe@42 351 value[r] = c;
universe@42 352 r++;
universe@43 353 } while ((c = fgetc(f)) > 0);
universe@42 354 value[r] = 0;
universe@43 355 while (value[--r] < 33) value[r] = 0;
universe@46 356
universe@48 357 if (decoder) {
universe@48 358 size_t decodedSize;
universe@48 359 void *decoded = decoder(value, decdata, &decodedSize);
universe@46 360 free(value);
universe@69 361 value = (char*) decoded;
universe@48 362 r = decodedSize;
universe@48 363 } else {
universe@48 364 r += 2;
universe@69 365 value = (char*) realloc(value, r);
universe@48 366 }
universe@48 367
universe@48 368 if (allocator.pool) {
universe@48 369 void *pooledValue = allocator.malloc(allocator.pool, r);
universe@48 370 memcpy(pooledValue, value, r);
universe@48 371 free(value);
universe@69 372 value = (char*) pooledValue;
universe@46 373 }
universe@42 374
universe@42 375 ucx_map_cstr_put(map, key, value);
universe@42 376 free(key);
universe@42 377 }
universe@42 378
universe@42 379 return 0;
universe@42 380 }
universe@42 381
universe@48 382 int ucx_map_store_enc(UcxMap *map, FILE *f,
universe@48 383 ucx_map_coder encoder, void *encdata) {
universe@42 384 UcxMapIterator iter = ucx_map_iterator(map);
universe@42 385 char *k, *v;
universe@42 386 sstr_t key, value;
universe@95 387 size_t written;
universe@42 388
universe@42 389 UCX_MAP_FOREACH(v, iter) {
universe@42 390 k = (char*) iter.cur->key.data;
olaf@79 391 key = sstrn(k, iter.cur->key.len);
universe@48 392 if (encoder) {
universe@48 393 size_t encodedSize;
universe@48 394 void *encoded = encoder(v, encdata, &encodedSize);
universe@69 395 value = sstrn((char*) encoded,encodedSize - 1);
universe@48 396 } else {
universe@46 397 value = sstr(v);
universe@46 398 }
universe@42 399
universe@42 400 written = 0;
universe@42 401 written += fwrite(key.ptr, 1, key.length, f);
universe@42 402 written += fwrite(" = ", 1, 3, f);
universe@42 403 written += fwrite(value.ptr, 1, value.length, f);
universe@42 404 written += fwrite("\n", 1, 1, f);
universe@42 405
universe@48 406 if (encoder) {
universe@46 407 free(value.ptr);
universe@46 408 }
universe@46 409
universe@42 410 if (written != key.length + value.length + 4) return 1;
universe@42 411 }
universe@42 412
universe@42 413 return 0;
universe@42 414 }

mercurial