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, |