UNIXworkcode

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