| 219 // (the first to find the index, the second to get a pointer) |
219 // (the first to find the index, the second to get a pointer) |
| 220 if (list->collection.size == 0) return 0; |
220 if (list->collection.size == 0) return 0; |
| 221 |
221 |
| 222 size_t index; |
222 size_t index; |
| 223 cx_linked_list *ll = &kv_list->list; |
223 cx_linked_list *ll = &kv_list->list; |
| 224 char *node = cx_linked_list_find( |
224 char *node = cx_linked_list_find_c( |
| 225 ll->begin, |
225 ll->begin, |
| 226 ll->loc_next, ll->loc_data, |
226 ll->loc_next, ll->loc_data, |
| 227 list->collection.cmpfunc, elem, |
227 elem, &index, |
| 228 &index |
228 cx_list_compare_wrapper, |
| |
229 list |
| 229 ); |
230 ); |
| 230 if (node == NULL) { |
231 if (node == NULL) { |
| 231 return list->collection.size; |
232 return list->collection.size; |
| 232 } |
233 } |
| 233 if (remove) { |
234 if (remove) { |
| 346 cxFree(kv_list->list.base.collection.allocator, node_ptr); |
347 cxFree(kv_list->list.base.collection.allocator, node_ptr); |
| 347 |
348 |
| 348 return 0; |
349 return 0; |
| 349 } |
350 } |
| 350 |
351 |
| 351 static void *cx_kvl_map_put(CxMap *map, CxHashKey key, void *value) { |
352 static CxMapEntry cx_kvl_map_put(CxMap *map, CxHashKey key, void *value) { |
| 352 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list; |
353 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list; |
| 353 // if the hash has not yet been computed, do it now |
354 // if the hash has not yet been computed, do it now |
| 354 if (key.hash == 0) { |
355 if (key.hash == 0) { |
| 355 cx_hash_murmur(&key); |
356 cx_hash_murmur(&key); |
| 356 } |
357 } |
| 357 |
358 |
| 358 // remove any existing element first |
359 // remove any existing element first |
| 359 cx_kvl_map_remove(map, key, NULL); |
360 cx_kvl_map_remove(map, key, NULL); |
| 360 |
361 |
| 361 // now reserve new memory in the map |
362 // now reserve new memory in the map |
| 362 void **map_data = kv_list->map_methods->put(map, key, NULL); |
363 CxMapEntry map_entry = kv_list->map_methods->put(map, key, NULL); |
| 363 if (map_data == NULL) return NULL; // LCOV_EXCL_LINE |
364 if (map_entry.key == NULL) return (CxMapEntry){NULL, NULL}; // LCOV_EXCL_LINE |
| 364 |
365 |
| 365 // insert the data into the list (which most likely destroys the sorted property) |
366 // insert the data into the list (which most likely destroys the sorted property) |
| 366 kv_list->list.base.collection.sorted = false; |
367 kv_list->list.base.collection.sorted = false; |
| 367 void *node_data = kv_list->list_methods->insert_element( |
368 void *node_data = kv_list->list_methods->insert_element( |
| 368 &kv_list->list.base, kv_list->list.base.collection.size, |
369 &kv_list->list.base, kv_list->list.base.collection.size, |
| 369 kv_list->list.base.collection.store_pointer ? &value : value); |
370 kv_list->list.base.collection.store_pointer ? &value : value); |
| 370 if (node_data == NULL) { // LCOV_EXCL_START |
371 if (node_data == NULL) { // LCOV_EXCL_START |
| 371 // non-destructively remove the key again |
372 // non-destructively remove the key again |
| 372 kv_list->map_methods->remove(&kv_list->map->map_base.base, key, &map_data); |
373 void *dummy; |
| 373 return NULL; |
374 kv_list->map_methods->remove(&kv_list->map->map_base.base, key, &dummy); |
| |
375 return (CxMapEntry){NULL, NULL}; |
| 374 } // LCOV_EXCL_STOP |
376 } // LCOV_EXCL_STOP |
| 375 |
377 |
| 376 // write the node pointer to the map entry |
378 // write the node pointer to the map entry |
| 377 *map_data = node_data; |
379 *(void**)map_entry.value = node_data; |
| 378 |
380 |
| 379 // copy the key to the node data |
381 // copy the key to the node data |
| 380 CxHashKey *key_ptr = cx_kv_list_loc_key(kv_list, node_data); |
382 CxHashKey *key_ptr = cx_kv_list_loc_key(kv_list, node_data); |
| 381 *key_ptr = key; |
383 *key_ptr = *map_entry.key; |
| 382 |
384 |
| 383 // we must return node_data here and not map_data, |
385 // we must return an entry that points to the node data! |
| 384 // because the node_data is the actual element of this collection |
386 return (CxMapEntry ){key_ptr, node_data}; |
| 385 return node_data; |
|
| 386 } |
387 } |
| 387 |
388 |
| 388 static void *cx_kvl_iter_current_entry(const void *it) { |
389 static void *cx_kvl_iter_current_entry(const void *it) { |
| 389 const CxMapIterator *iter = it; |
390 const CxMapIterator *iter = it; |
| 390 return (void*)&iter->entry; |
391 return (void*)&iter->entry; |
| 550 cx_kvl_map_iterator, |
551 cx_kvl_map_iterator, |
| 551 }; |
552 }; |
| 552 |
553 |
| 553 CxList *cxKvListCreate( |
554 CxList *cxKvListCreate( |
| 554 const CxAllocator *allocator, |
555 const CxAllocator *allocator, |
| 555 cx_compare_func comparator, |
|
| 556 size_t elem_size |
556 size_t elem_size |
| 557 ) { |
557 ) { |
| 558 if (allocator == NULL) { |
558 if (allocator == NULL) { |
| 559 allocator = cxDefaultAllocator; |
559 allocator = cxDefaultAllocator; |
| 560 } |
560 } |
| 561 |
561 |
| 562 // create a normal linked list and a normal hash map, first |
562 // create a normal linked list and a normal hash map, first |
| 563 CxList *list = cxLinkedListCreate(allocator, comparator, elem_size); |
563 CxList *list = cxLinkedListCreate(allocator, elem_size); |
| 564 if (list == NULL) return NULL; // LCOV_EXCL_LINE |
564 if (list == NULL) return NULL; // LCOV_EXCL_LINE |
| 565 cx_linked_list *ll = (cx_linked_list*)list; |
565 cx_linked_list *ll = (cx_linked_list*)list; |
| 566 cx_linked_list_extra_data(ll, sizeof(CxHashKey)); |
566 cx_linked_list_extra_data(ll, sizeof(CxHashKey)); |
| 567 CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 0); |
567 CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 0); |
| 568 if (map == NULL) { // LCOV_EXCL_START |
568 if (map == NULL) { // LCOV_EXCL_START |
| 598 kv_map->list = kv_list; |
598 kv_map->list = kv_list; |
| 599 |
599 |
| 600 // remember the base methods and override them |
600 // remember the base methods and override them |
| 601 kv_list->map_methods = map->cl; |
601 kv_list->map_methods = map->cl; |
| 602 map->cl = &cx_kv_map_class; |
602 map->cl = &cx_kv_map_class; |
| 603 if (list->climpl == NULL) { |
603 kv_list->list_methods = list->cl; |
| 604 kv_list->list_methods = list->cl; |
604 list->cl = &cx_kv_list_class; |
| 605 list->cl = &cx_kv_list_class; |
|
| 606 } else { |
|
| 607 kv_list->list_methods = list->climpl; |
|
| 608 list->climpl = &cx_kv_list_class; |
|
| 609 } |
|
| 610 |
605 |
| 611 return list; |
606 return list; |
| 612 } |
607 } |
| 613 |
608 |
| 614 CxMap *cxKvListCreateAsMap( |
609 CxMap *cxKvListCreateAsMap( |
| 615 const CxAllocator *allocator, |
610 const CxAllocator *allocator, |
| 616 cx_compare_func comparator, |
|
| 617 size_t elem_size |
611 size_t elem_size |
| 618 ) { |
612 ) { |
| 619 CxList *list = cxKvListCreate(allocator, comparator, elem_size); |
613 CxList *list = cxKvListCreate(allocator, elem_size); |
| 620 return list == NULL ? NULL : cxKvListAsMap(list); |
614 return list == NULL ? NULL : cxKvListAsMap(list); |
| 621 } |
615 } |
| 622 |
616 |
| 623 CxList *cxKvListAsList(CxMap *map) { |
617 CxList *cxKvListAsList(CxMap *map) { |
| 624 return &((struct cx_kv_list_map_s*)map)->list->list.base; |
618 return &((struct cx_kv_list_map_s*)map)->list->list.base; |
| 647 if (existing != NULL) { |
641 if (existing != NULL) { |
| 648 // the key is already assigned to another node, we disallow re-assignment |
642 // the key is already assigned to another node, we disallow re-assignment |
| 649 return 1; |
643 return 1; |
| 650 } |
644 } |
| 651 |
645 |
| 652 // add the key to the map; |
646 // add the key to the map |
| 653 if (NULL == kv_list->map_methods->put(&kv_list->map->map_base.base, key, node_data)) { |
647 const CxMapEntry entry = kv_list->map_methods->put( |
| 654 return 1; // LCOV_EXCL_LINE |
648 &kv_list->map->map_base.base, key, node_data); |
| 655 } |
649 if (entry.key == NULL) return 1; // LCOV_EXCL_LINE |
| 656 |
650 |
| 657 // write the key to the list's node |
651 // write the key to the list's node |
| 658 CxHashKey *loc_key = cx_kv_list_loc_key(kv_list, node_data); |
652 CxHashKey *loc_key = cx_kv_list_loc_key(kv_list, node_data); |
| 659 *loc_key = key; |
653 *loc_key = *entry.key; |
| 660 |
654 |
| 661 return 0; |
655 return 0; |
| 662 } |
656 } |
| 663 |
657 |
| 664 int cxKvListRemoveKey(CxList *list, size_t index) { |
658 int cxKvListRemoveKey(CxList *list, size_t index) { |
| 696 list->collection.sorted = false; |
690 list->collection.sorted = false; |
| 697 |
691 |
| 698 cx_kv_list *kv_list = (cx_kv_list*)list; |
692 cx_kv_list *kv_list = (cx_kv_list*)list; |
| 699 |
693 |
| 700 // reserve memory in the map |
694 // reserve memory in the map |
| 701 void **map_data = kv_list->map_methods->put(&kv_list->map->map_base.base, key, NULL); |
695 CxMapEntry map_entry = kv_list->map_methods->put(&kv_list->map->map_base.base, key, NULL); |
| 702 if (map_data == NULL) return 1; // LCOV_EXCL_LINE |
696 if (map_entry.key == NULL) return 1; // LCOV_EXCL_LINE |
| 703 |
697 |
| 704 // insert the node |
698 // insert the node |
| 705 void *node_data = kv_list->list_methods->insert_element(&kv_list->list.base, index, |
699 void *node_data = kv_list->list_methods->insert_element(&kv_list->list.base, index, |
| 706 kv_list->list.base.collection.store_pointer ? &value : value); |
700 kv_list->list.base.collection.store_pointer ? &value : value); |
| 707 if (node_data == NULL) { // LCOV_EXCL_START |
701 if (node_data == NULL) { // LCOV_EXCL_START |
| 708 // non-destructively remove the key again |
702 // non-destructively remove the key again |
| 709 kv_list->map_methods->remove(&kv_list->map->map_base.base, key, &map_data); |
703 void *dummy; |
| |
704 kv_list->map_methods->remove(&kv_list->map->map_base.base, key, &dummy); |
| 710 return 1; |
705 return 1; |
| 711 } // LCOV_EXCL_STOP |
706 } // LCOV_EXCL_STOP |
| 712 *map_data = node_data; |
707 *(void**)map_entry.value = node_data; |
| 713 |
708 |
| 714 // write the key to the node |
709 // write the key to the node |
| 715 CxHashKey *loc_key = cx_kv_list_loc_key(kv_list, node_data); |
710 CxHashKey *loc_key = cx_kv_list_loc_key(kv_list, node_data); |
| 716 *loc_key = key; |
711 *loc_key = *map_entry.key; |
| 717 |
712 |
| 718 return 0; |
713 return 0; |
| 719 } |
714 } |