1 /* |
1 /* |
2 * |
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
|
3 * |
|
4 * Copyright 2013 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. |
3 */ |
27 */ |
4 |
28 |
5 #include <stdlib.h> |
29 #include <stdlib.h> |
6 #include <string.h> |
30 #include <string.h> |
7 |
31 |
8 #include "map.h" |
32 #include "map.h" |
9 |
33 |
10 UcxMap *ucx_map_new(size_t size) { |
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) { |
11 if(size == 0) { |
39 if(size == 0) { |
12 size = 16; |
40 size = 16; |
13 } |
41 } |
14 |
42 |
15 UcxMap *map = (UcxMap*)malloc(sizeof(UcxMap)); |
43 if(!allocator) { |
|
44 allocator = ucx_default_allocator(); |
|
45 } |
|
46 |
|
47 UcxMap *map = (UcxMap*)allocator->malloc(allocator->pool, sizeof(UcxMap)); |
16 if(map == NULL) { |
48 if(map == NULL) { |
17 return NULL; |
49 return NULL; |
18 } |
50 } |
19 |
51 |
20 map->map = (UcxMapElement**)calloc(size, sizeof(UcxMapElement*)); |
52 map->allocator = allocator; |
|
53 map->map = (UcxMapElement**)allocator->calloc( |
|
54 allocator->pool, |
|
55 size, |
|
56 sizeof(UcxMapElement*)); |
21 if(map->map == NULL) { |
57 if(map->map == NULL) { |
22 free(map); |
58 allocator->free(allocator->pool, map); |
23 return NULL; |
59 return NULL; |
24 } |
60 } |
25 map->size = size; |
61 map->size = size; |
26 map->count = 0; |
62 map->count = 0; |
27 |
63 |
28 return map; |
64 return map; |
29 } |
65 } |
30 |
66 |
31 void ucx_map_free_elmlist(UcxMap *map) { |
67 static void ucx_map_free_elmlist(UcxMap *map) { |
32 for (size_t n = 0 ; n < map->size ; n++) { |
68 for (size_t n = 0 ; n < map->size ; n++) { |
33 UcxMapElement *elem = map->map[n]; |
69 UcxMapElement *elem = map->map[n]; |
34 if (elem != NULL) { |
70 if (elem != NULL) { |
35 do { |
71 do { |
36 UcxMapElement *next = elem->next; |
72 UcxMapElement *next = elem->next; |
37 free(elem->key.data); |
73 map->allocator->free(map->allocator->pool, elem->key.data); |
38 free(elem); |
74 map->allocator->free(map->allocator->pool, elem); |
39 elem = next; |
75 elem = next; |
40 } while (elem != NULL); |
76 } while (elem != NULL); |
41 } |
77 } |
42 } |
78 } |
43 free(map->map); |
79 map->allocator->free(map->allocator->pool, map->map); |
44 } |
80 } |
45 |
81 |
46 void ucx_map_free(UcxMap *map) { |
82 void ucx_map_free(UcxMap *map) { |
47 ucx_map_free_elmlist(map); |
83 ucx_map_free_elmlist(map); |
48 free(map); |
84 map->allocator->free(map->allocator->pool, map); |
49 } |
85 } |
50 |
86 |
51 int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to, |
87 int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to, |
52 copy_func fnc, void *data) { |
88 copy_func fnc, void *data) { |
53 UcxMapIterator i = ucx_map_iterator(from); |
89 UcxMapIterator i = ucx_map_iterator(from); |
54 void *value; |
90 void *value; |
55 UCX_MAP_FOREACH(value, i) { |
91 UCX_MAP_FOREACH(key, value, i) { |
56 int ret = ucx_map_put(to, i.cur->key, fnc ? fnc(value, data) : value); |
92 int ret = ucx_map_put(to, i.cur->key, fnc ? fnc(value, data) : value); |
57 if(ret != 0) { |
93 if(ret != 0) { |
58 return 1; |
94 return 1; |
59 } |
95 } |
60 } |
96 } |
76 if (map->count > load) { |
112 if (map->count > load) { |
77 UcxMap oldmap; |
113 UcxMap oldmap; |
78 oldmap.map = map->map; |
114 oldmap.map = map->map; |
79 oldmap.size = map->size; |
115 oldmap.size = map->size; |
80 oldmap.count = map->count; |
116 oldmap.count = map->count; |
|
117 oldmap.allocator = map->allocator; |
81 |
118 |
82 map->size = (map->count * 5) >> 1; |
119 map->size = (map->count * 5) >> 1; |
83 map->map = (UcxMapElement**)calloc(map->size, sizeof(UcxMapElement*)); |
120 map->map = (UcxMapElement**)map->allocator->calloc( |
|
121 map->allocator->pool, |
|
122 map->size, |
|
123 sizeof(UcxMapElement*)); |
84 if(map->map == NULL) { |
124 if(map->map == NULL) { |
85 *map = oldmap; |
125 *map = oldmap; |
86 return 1; |
126 return 1; |
87 } |
127 } |
88 map->count = 0; |
128 map->count = 0; |
266 } |
311 } |
267 |
312 |
268 return 1; |
313 return 1; |
269 } |
314 } |
270 |
315 |
271 int ucx_map_load_enc(UcxMap *map, FILE *f, UcxAllocator allocator, |
|
272 ucx_map_coder decoder, void* decdata) { |
|
273 |
|
274 int c; int r, n; |
|
275 |
|
276 char *key, *value; |
|
277 |
|
278 while ((c = fgetc(f)) > 0) { |
|
279 /* Discard leading spaces and comments */ |
|
280 if (c < 33) continue; |
|
281 if (c == '#' || c == '!') { |
|
282 while ((c = (char) fgetc(f)) > 0) { |
|
283 if (c == '\n') break; |
|
284 } |
|
285 continue; |
|
286 } |
|
287 |
|
288 /* read into key buffer */ |
|
289 n = 16; |
|
290 key = (char*) malloc(n); |
|
291 r = 0; |
|
292 do { |
|
293 if (c == '=') break; |
|
294 if (r > n - 2) { |
|
295 n *= 2; |
|
296 key = (char*) realloc(key, n); |
|
297 } |
|
298 key[r] = c; |
|
299 r++; |
|
300 } while ((c = fgetc(f)) > 0); |
|
301 if (c <= 0) { |
|
302 free(key); |
|
303 return 1; |
|
304 } |
|
305 key[r] = 0; |
|
306 while (key[--r] == ' ') key[r] = 0; |
|
307 |
|
308 /* skip whitespaces */ |
|
309 while ((c = fgetc(f)) > 0) { |
|
310 if (c > 32) break; |
|
311 } |
|
312 if (c <= 0) { |
|
313 free(key); |
|
314 return 1; |
|
315 } |
|
316 |
|
317 /* read into value buffer */ |
|
318 n = 64; |
|
319 value = (char*) malloc(n); |
|
320 r = 0; |
|
321 do { |
|
322 if (c == '\n') break; |
|
323 if (r > n - 2) { |
|
324 n *= 2; |
|
325 value = (char*) realloc(value, n); |
|
326 } |
|
327 value[r] = c; |
|
328 r++; |
|
329 } while ((c = fgetc(f)) > 0); |
|
330 value[r] = 0; |
|
331 while (value[--r] < 33) value[r] = 0; |
|
332 |
|
333 if (decoder) { |
|
334 size_t decodedSize; |
|
335 void *decoded = decoder(value, decdata, &decodedSize); |
|
336 free(value); |
|
337 value = (char*) decoded; |
|
338 r = decodedSize; |
|
339 } else { |
|
340 r += 2; |
|
341 value = (char*) realloc(value, r); |
|
342 } |
|
343 |
|
344 if (allocator.pool) { |
|
345 void *pooledValue = allocator.malloc(allocator.pool, r); |
|
346 memcpy(pooledValue, value, r); |
|
347 free(value); |
|
348 value = (char*) pooledValue; |
|
349 } |
|
350 |
|
351 ucx_map_cstr_put(map, key, value); |
|
352 free(key); |
|
353 } |
|
354 |
|
355 return 0; |
|
356 } |
|
357 |
|
358 int ucx_map_store_enc(UcxMap *map, FILE *f, |
|
359 ucx_map_coder encoder, void *encdata) { |
|
360 UcxMapIterator iter = ucx_map_iterator(map); |
|
361 char *k, *v; |
|
362 sstr_t key, value; |
|
363 int written; |
|
364 |
|
365 UCX_MAP_FOREACH(v, iter) { |
|
366 k = (char*) iter.cur->key.data; |
|
367 key = sstr(k); |
|
368 if (encoder) { |
|
369 size_t encodedSize; |
|
370 void *encoded = encoder(v, encdata, &encodedSize); |
|
371 value = sstrn((char*) encoded,encodedSize - 1); |
|
372 } else { |
|
373 value = sstr(v); |
|
374 } |
|
375 |
|
376 written = 0; |
|
377 written += fwrite(key.ptr, 1, key.length, f); |
|
378 written += fwrite(" = ", 1, 3, f); |
|
379 written += fwrite(value.ptr, 1, value.length, f); |
|
380 written += fwrite("\n", 1, 1, f); |
|
381 |
|
382 if (encoder) { |
|
383 free(value.ptr); |
|
384 } |
|
385 |
|
386 if (written != key.length + value.length + 4) return 1; |
|
387 } |
|
388 |
|
389 return 0; |
|
390 } |
|