ucx/kv_list.c

branch
dav-2
changeset 891
4d58cbcc9efa
parent 889
42cdbf9bbd49
equal deleted inserted replaced
890:e77ccf1c4bb3 891:4d58cbcc9efa
96 list->map->map_base.base.collection.destructor_data = NULL; 96 list->map->map_base.base.collection.destructor_data = NULL;
97 } 97 }
98 } 98 }
99 99
100 static CxHashKey *cx_kv_list_loc_key(cx_kv_list *list, void *node_data) { 100 static CxHashKey *cx_kv_list_loc_key(cx_kv_list *list, void *node_data) {
101 return (CxHashKey*)((char*)node_data + list->list.base.collection.elem_size); 101 return (CxHashKey*)((char*)node_data - list->list.loc_data + list->list.loc_extra);
102 } 102 }
103 103
104 static void cx_kvl_deallocate(struct cx_list_s *list) { 104 static void cx_kvl_deallocate(struct cx_list_s *list) {
105 cx_kv_list *kv_list = (cx_kv_list*)list; 105 cx_kv_list *kv_list = (cx_kv_list*)list;
106 // patch the destructors 106 // patch the destructors
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) {
283 return iter; 284 return iter;
284 } 285 }
285 286
286 static void cx_kvl_map_deallocate(struct cx_map_s *map) { 287 static void cx_kvl_map_deallocate(struct cx_map_s *map) {
287 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list; 288 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list;
289 cx_kv_list_update_destructors(kv_list);
288 kv_list->map_methods->deallocate(map); 290 kv_list->map_methods->deallocate(map);
289 kv_list->list_methods->deallocate(&kv_list->list.base); 291 kv_list->list_methods->deallocate(&kv_list->list.base);
290 } 292 }
291 293
292 static void cx_kvl_map_clear(struct cx_map_s *map) { 294 static void cx_kvl_map_clear(struct cx_map_s *map) {
294 cx_kv_list_update_destructors(kv_list); 296 cx_kv_list_update_destructors(kv_list);
295 kv_list->list_methods->clear(&kv_list->list.base); 297 kv_list->list_methods->clear(&kv_list->list.base);
296 kv_list->map_methods->clear(map); 298 kv_list->map_methods->clear(map);
297 } 299 }
298 300
299 static void *cx_kvl_map_put(CxMap *map, CxHashKey key, void *value) { 301 static void *cx_kvl_map_get(const CxMap *map, CxHashKey key) {
300 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list;
301 // if the hash has not yet been computed, do it now
302 if (key.hash == 0) {
303 cx_hash_murmur(&key);
304 }
305
306 // reserve memory in the map first
307 void **map_data = kv_list->map_methods->put(map, key, NULL);
308 if (map_data == NULL) return NULL; // LCOV_EXCL_LINE
309
310 // insert the data into the list (which most likely destroys the sorted property)
311 kv_list->list.base.collection.sorted = false;
312 void *node_data = kv_list->list_methods->insert_element(
313 &kv_list->list.base, kv_list->list.base.collection.size,
314 kv_list->list.base.collection.store_pointer ? &value : value);
315 if (node_data == NULL) { // LCOV_EXCL_START
316 // non-destructively remove the key again
317 kv_list->map_methods->remove(&kv_list->map->map_base.base, key, &map_data);
318 return NULL;
319 } // LCOV_EXCL_STOP
320
321 // write the node pointer to the map entry
322 *map_data = node_data;
323
324 // copy the key to the node data
325 CxHashKey *key_ptr = cx_kv_list_loc_key(kv_list, node_data);
326 *key_ptr = key;
327
328 // we must return node_data here and not map_data,
329 // because the node_data is the actual element of this collection
330 return node_data;
331 }
332
333 void *cx_kvl_map_get(const CxMap *map, CxHashKey key) {
334 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list; 302 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list;
335 void *node_data = kv_list->map_methods->get(map, key); 303 void *node_data = kv_list->map_methods->get(map, key);
336 if (node_data == NULL) return NULL; // LCOV_EXCL_LINE 304 if (node_data == NULL) return NULL; // LCOV_EXCL_LINE
337 // return the node data 305 // return the node data
338 return kv_list->list.base.collection.store_pointer ? *(void**)node_data : node_data; 306 return kv_list->list.base.collection.store_pointer ? *(void**)node_data : node_data;
339 } 307 }
340 308
341 int cx_kvl_map_remove(CxMap *map, CxHashKey key, void *targetbuf) { 309 static int cx_kvl_map_remove(CxMap *map, CxHashKey key, void *targetbuf) {
342 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list; 310 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list;
343 311
344 void *node_data; 312 void *node_data;
345 if (kv_list->map_methods->remove(map, key, &node_data)) { 313 if (kv_list->map_methods->remove(map, key, &node_data)) {
346 return 1; 314 return 1;
377 345
378 // deallocate the node 346 // deallocate the node
379 cxFree(kv_list->list.base.collection.allocator, node_ptr); 347 cxFree(kv_list->list.base.collection.allocator, node_ptr);
380 348
381 return 0; 349 return 0;
350 }
351
352 static CxMapEntry cx_kvl_map_put(CxMap *map, CxHashKey key, void *value) {
353 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list;
354 // if the hash has not yet been computed, do it now
355 if (key.hash == 0) {
356 cx_hash_murmur(&key);
357 }
358
359 // remove any existing element first
360 cx_kvl_map_remove(map, key, NULL);
361
362 // now reserve new memory in the map
363 CxMapEntry map_entry = kv_list->map_methods->put(map, key, NULL);
364 if (map_entry.key == NULL) return (CxMapEntry){NULL, NULL}; // LCOV_EXCL_LINE
365
366 // insert the data into the list (which most likely destroys the sorted property)
367 kv_list->list.base.collection.sorted = false;
368 void *node_data = kv_list->list_methods->insert_element(
369 &kv_list->list.base, kv_list->list.base.collection.size,
370 kv_list->list.base.collection.store_pointer ? &value : value);
371 if (node_data == NULL) { // LCOV_EXCL_START
372 // non-destructively remove the key again
373 void *dummy;
374 kv_list->map_methods->remove(&kv_list->map->map_base.base, key, &dummy);
375 return (CxMapEntry){NULL, NULL};
376 } // LCOV_EXCL_STOP
377
378 // write the node pointer to the map entry
379 *(void**)map_entry.value = node_data;
380
381 // copy the key to the node data
382 CxHashKey *key_ptr = cx_kv_list_loc_key(kv_list, node_data);
383 *key_ptr = *map_entry.key;
384
385 // we must return an entry that points to the node data!
386 return (CxMapEntry ){key_ptr, node_data};
382 } 387 }
383 388
384 static void *cx_kvl_iter_current_entry(const void *it) { 389 static void *cx_kvl_iter_current_entry(const void *it) {
385 const CxMapIterator *iter = it; 390 const CxMapIterator *iter = it;
386 return (void*)&iter->entry; 391 return (void*)&iter->entry;
453 static bool cx_kvl_iter_valid(const void *it) { 458 static bool cx_kvl_iter_valid(const void *it) {
454 const CxMapIterator *iter = it; 459 const CxMapIterator *iter = it;
455 return iter->elem != NULL; 460 return iter->elem != NULL;
456 } 461 }
457 462
458 CxMapIterator cx_kvl_map_iterator(const CxMap *map, enum cx_map_iterator_type type) { 463 static CxMapIterator cx_kvl_map_iterator(const CxMap *map, enum cx_map_iterator_type type) {
459 CxMapIterator iter = {0}; 464 CxMapIterator iter = {0};
460 465
461 iter.type = type; 466 iter.type = type;
462 iter.map = (CxMap*)map; 467 iter.map = (CxMap*)map;
463 // although we iterate over the list, we only report that many elements that have a key in the map 468 // although we iterate over the list, we only report that many elements that have a key in the map
507 } 512 }
508 513
509 return iter; 514 return iter;
510 } 515 }
511 516
517 static int cx_kvl_change_capacity(struct cx_list_s *list,
518 cx_attr_unused size_t cap) {
519 // since our backing list is a linked list, we don't need to do much here,
520 // but rehashing the map is quite useful
521 cx_kv_list *kv_list = (cx_kv_list*)list;
522 cxMapRehash(&kv_list->map->map_base.base);
523 return 0;
524 }
525
512 static cx_list_class cx_kv_list_class = { 526 static cx_list_class cx_kv_list_class = {
513 cx_kvl_deallocate, 527 cx_kvl_deallocate,
514 cx_kvl_insert_element, 528 cx_kvl_insert_element,
515 cx_kvl_insert_array, 529 cx_kvl_insert_array,
516 cx_kvl_insert_sorted, 530 cx_kvl_insert_sorted,
522 cx_kvl_at, 536 cx_kvl_at,
523 cx_kvl_find_remove, 537 cx_kvl_find_remove,
524 cx_kvl_sort, 538 cx_kvl_sort,
525 NULL, 539 NULL,
526 cx_kvl_reverse, 540 cx_kvl_reverse,
541 cx_kvl_change_capacity,
527 cx_kvl_iterator, 542 cx_kvl_iterator,
528 }; 543 };
529 544
530 static cx_map_class cx_kv_map_class = { 545 static cx_map_class cx_kv_map_class = {
531 cx_kvl_map_deallocate, 546 cx_kvl_map_deallocate,
536 cx_kvl_map_iterator, 551 cx_kvl_map_iterator,
537 }; 552 };
538 553
539 CxList *cxKvListCreate( 554 CxList *cxKvListCreate(
540 const CxAllocator *allocator, 555 const CxAllocator *allocator,
541 cx_compare_func comparator,
542 size_t elem_size 556 size_t elem_size
543 ) { 557 ) {
544 if (allocator == NULL) { 558 if (allocator == NULL) {
545 allocator = cxDefaultAllocator; 559 allocator = cxDefaultAllocator;
546 } 560 }
547 561
548 // create a normal linked list and a normal hash map, first 562 // create a normal linked list and a normal hash map, first
549 CxList *list = cxLinkedListCreate(allocator, comparator, elem_size); 563 CxList *list = cxLinkedListCreate(allocator, elem_size);
550 if (list == NULL) return NULL; // LCOV_EXCL_LINE 564 if (list == NULL) return NULL; // LCOV_EXCL_LINE
551 cx_linked_list *ll = (cx_linked_list*)list; 565 cx_linked_list *ll = (cx_linked_list*)list;
552 ll->extra_data_len = sizeof(CxHashKey); 566 cx_linked_list_extra_data(ll, sizeof(CxHashKey));
553 CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 0); 567 CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 0);
554 if (map == NULL) { // LCOV_EXCL_START 568 if (map == NULL) { // LCOV_EXCL_START
555 cxListFree(list); 569 cxListFree(list);
556 return NULL; 570 return NULL;
557 } // LCOV_EXCL_STOP 571 } // LCOV_EXCL_STOP
584 kv_map->list = kv_list; 598 kv_map->list = kv_list;
585 599
586 // remember the base methods and override them 600 // remember the base methods and override them
587 kv_list->map_methods = map->cl; 601 kv_list->map_methods = map->cl;
588 map->cl = &cx_kv_map_class; 602 map->cl = &cx_kv_map_class;
589 if (list->climpl == NULL) { 603 kv_list->list_methods = list->cl;
590 kv_list->list_methods = list->cl; 604 list->cl = &cx_kv_list_class;
591 list->cl = &cx_kv_list_class;
592 } else {
593 kv_list->list_methods = list->climpl;
594 list->climpl = &cx_kv_list_class;
595 }
596 605
597 return list; 606 return list;
598 } 607 }
599 608
600 CxMap *cxKvListCreateAsMap( 609 CxMap *cxKvListCreateAsMap(
601 const CxAllocator *allocator, 610 const CxAllocator *allocator,
602 cx_compare_func comparator,
603 size_t elem_size 611 size_t elem_size
604 ) { 612 ) {
605 CxList *list = cxKvListCreate(allocator, comparator, elem_size); 613 CxList *list = cxKvListCreate(allocator, elem_size);
606 return list == NULL ? NULL : cxKvListAsMap(list); 614 return list == NULL ? NULL : cxKvListAsMap(list);
607 } 615 }
608 616
609 CxList *cxKvListAsList(CxMap *map) { 617 CxList *cxKvListAsList(CxMap *map) {
610 return &((struct cx_kv_list_map_s*)map)->list->list.base; 618 return &((struct cx_kv_list_map_s*)map)->list->list.base;
633 if (existing != NULL) { 641 if (existing != NULL) {
634 // 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
635 return 1; 643 return 1;
636 } 644 }
637 645
638 // add the key to the map; 646 // add the key to the map
639 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(
640 return 1; // LCOV_EXCL_LINE 648 &kv_list->map->map_base.base, key, node_data);
641 } 649 if (entry.key == NULL) return 1; // LCOV_EXCL_LINE
642 650
643 // write the key to the list's node 651 // write the key to the list's node
644 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);
645 *loc_key = key; 653 *loc_key = *entry.key;
646 654
647 return 0; 655 return 0;
648 } 656 }
649 657
650 int cxKvListRemoveKey(CxList *list, size_t index) { 658 int cxKvListRemoveKey(CxList *list, size_t index) {
682 list->collection.sorted = false; 690 list->collection.sorted = false;
683 691
684 cx_kv_list *kv_list = (cx_kv_list*)list; 692 cx_kv_list *kv_list = (cx_kv_list*)list;
685 693
686 // reserve memory in the map 694 // reserve memory in the map
687 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);
688 if (map_data == NULL) return 1; // LCOV_EXCL_LINE 696 if (map_entry.key == NULL) return 1; // LCOV_EXCL_LINE
689 697
690 // insert the node 698 // insert the node
691 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,
692 kv_list->list.base.collection.store_pointer ? &value : value); 700 kv_list->list.base.collection.store_pointer ? &value : value);
693 if (node_data == NULL) { // LCOV_EXCL_START 701 if (node_data == NULL) { // LCOV_EXCL_START
694 // non-destructively remove the key again 702 // non-destructively remove the key again
695 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);
696 return 1; 705 return 1;
697 } // LCOV_EXCL_STOP 706 } // LCOV_EXCL_STOP
698 *map_data = node_data; 707 *(void**)map_entry.value = node_data;
699 708
700 // write the key to the node 709 // write the key to the node
701 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);
702 *loc_key = key; 711 *loc_key = *map_entry.key;
703 712
704 return 0; 713 return 0;
705 } 714 }

mercurial