src/kv_list.c

changeset 1384
a2cfbff39e5d
parent 1383
3db28cb1e5ec
equal deleted inserted replaced
1383:3db28cb1e5ec 1384:a2cfbff39e5d
29 #include "cx/kv_list.h" 29 #include "cx/kv_list.h"
30 #include "cx/hash_map.h" 30 #include "cx/hash_map.h"
31 #include "cx/linked_list.h" 31 #include "cx/linked_list.h"
32 32
33 #include <string.h> 33 #include <string.h>
34 #include <assert.h>
34 35
35 typedef struct cx_kv_list_s cx_kv_list; 36 typedef struct cx_kv_list_s cx_kv_list;
36 37
37 struct cx_kv_list_map_s { 38 struct cx_kv_list_map_s {
38 struct cx_hash_map_s map_base; 39 struct cx_hash_map_s map_base;
348 cxFree(kv_list->list.base.collection.allocator, node_ptr); 349 cxFree(kv_list->list.base.collection.allocator, node_ptr);
349 350
350 return 0; 351 return 0;
351 } 352 }
352 353
354 static void *cx_kvl_iter_current_entry(const void *it) {
355 const CxMapIterator *iter = it;
356 return (void*)&iter->entry;
357 }
358
359 static void *cx_kvl_iter_current_key(const void *it) {
360 const CxMapEntry *entry = cx_kvl_iter_current_entry(it);
361 return (void*)entry->key;
362 }
363
364 static void *cx_kvl_iter_current_value(const void *it) {
365 const CxMapEntry *entry = cx_kvl_iter_current_entry(it);
366 return entry->value;
367 }
368
369 static void cx_kvl_iter_next(void *it) {
370 CxMapIterator *iter = it;
371 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)iter->map.m)->list;
372
373 // find the next list entry that has a key assigned
374 CxHashKey *key = NULL;
375 char *next = iter->elem;
376 while (true) {
377 next = *(char**)(next + kv_list->list.loc_next);
378 if (next == NULL) break;
379 key = cx_kv_list_loc_key(kv_list, next + kv_list->list.loc_data);
380 if (key->hash != 0) break;
381 }
382 if (next == NULL) {
383 iter->index = kv_list->list.base.collection.size;
384 iter->elem = NULL;
385 iter->entry = (CxMapEntry){NULL, NULL};
386 return;
387 }
388
389 // TODO: implement removal
390
391 // advance to the next element
392 iter->index++;
393 iter->elem = next;
394 iter->entry.key = key;
395 if (kv_list->list.base.collection.store_pointer) {
396 iter->entry.value = *(void**)(next + kv_list->list.loc_data);
397 } else {
398 iter->entry.value = (void*)(next + kv_list->list.loc_data);
399 }
400 }
401
402 static bool cx_kvl_iter_valid(const void *it) {
403 const CxMapIterator *iter = it;
404 return iter->elem != NULL;
405 }
406
353 CxMapIterator cx_kvl_map_iterator(const CxMap *map, enum cx_map_iterator_type type) { 407 CxMapIterator cx_kvl_map_iterator(const CxMap *map, enum cx_map_iterator_type type) {
408 CxMapIterator iter = {};
409
410 iter.type = type;
411 iter.map.c = map;
412 // although we iterate over the list, we only report that many elements that have a key in the map
413 iter.elem_count = map->collection.size;
414
415 switch (type) {
416 case CX_MAP_ITERATOR_PAIRS:
417 iter.elem_size = sizeof(CxMapEntry);
418 iter.base.current = cx_kvl_iter_current_entry;
419 break;
420 case CX_MAP_ITERATOR_KEYS:
421 iter.elem_size = sizeof(CxHashKey);
422 iter.base.current = cx_kvl_iter_current_key;
423 break;
424 case CX_MAP_ITERATOR_VALUES:
425 iter.elem_size = map->collection.elem_size;
426 iter.base.current = cx_kvl_iter_current_value;
427 break;
428 default:
429 assert(false); // LCOV_EXCL_LINE
430 }
431
432 iter.base.next = cx_kvl_iter_next;
433 iter.base.valid = cx_kvl_iter_valid;
434
435 // find the first list entry that has a key assigned
354 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list; 436 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list;
355 return kv_list->map_methods->iterator(map, type); 437 CxHashKey *key = NULL;
438 char *next = kv_list->list.begin;
439 while (next != NULL) {
440 key = cx_kv_list_loc_key(kv_list, next + kv_list->list.loc_data);
441 if (key->hash != 0) break;
442 next = *(char**)(next + kv_list->list.loc_next);
443 }
444 if (next == NULL) {
445 iter.elem = NULL;
446 iter.entry = (CxMapEntry){NULL, NULL};
447 } else {
448 iter.elem = next;
449 iter.entry.key = key;
450 if (kv_list->list.base.collection.store_pointer) {
451 iter.entry.value = *(void**)(next + kv_list->list.loc_data);
452 } else {
453 iter.entry.value = (void*)(next + kv_list->list.loc_data);
454 }
455 }
456
457 return iter;
356 } 458 }
357 459
358 static cx_list_class cx_kv_list_class = { 460 static cx_list_class cx_kv_list_class = {
359 cx_kvl_deallocate, 461 cx_kvl_deallocate,
360 cx_kvl_insert_element, 462 cx_kvl_insert_element,
480 return 1; 582 return 1;
481 } 583 }
482 584
483 // add the key to the map; 585 // add the key to the map;
484 if (NULL == kv_list->map_methods->put(&kv_list->map->map_base.base, key, node_data)) { 586 if (NULL == kv_list->map_methods->put(&kv_list->map->map_base.base, key, node_data)) {
485 return 1; 587 return 1; // LCOV_EXCL_LINE
486 } 588 }
487 589
488 // write the key to the list's node 590 // write the key to the list's node
489 CxHashKey *loc_key = cx_kv_list_loc_key(kv_list, node_data); 591 CxHashKey *loc_key = cx_kv_list_loc_key(kv_list, node_data);
490 *loc_key = key; 592 *loc_key = key;

mercurial