Insert the element 's' of size 'len', setting as auxiliary data * the pointer 'data'. If the element is already present, the associated * data is updated (only if 'overwrite' is set to 1), and 0 is returned, * otherwise the element is inserted and 1 is returned. On out of memory the * function returns 0 as well but sets errno to ENOMEM, otherwise errno will * be set to 0. */
| 627 | * be set to 0. |
| 628 | */ |
| 629 | int raxGenericInsert(rax *rax, unsigned char *s, size_t len, void *data, void **old, int overwrite) { |
| 630 | size_t i; |
| 631 | int j = 0; /* Split position. If raxLowWalk() stops in a compressed |
| 632 | node, the index 'j' represents the char we stopped within the |
| 633 | compressed node, that is, the position where to split the |
| 634 | node for insertion. */ |
| 635 | raxNode *h, **parentlink; |
| 636 | |
| 637 | debugf("### Insert %.*s with value %p\n", (int)len, s, data); |
| 638 | int inline_leaf = 0; |
| 639 | i = raxLowWalk(rax,s,len,&h,&parentlink,&j,NULL,&inline_leaf); |
| 640 | |
| 641 | /* If the key was found as an inline leaf, the value is stored |
| 642 | * directly in the parent's child pointer slot. Update it in place |
| 643 | * without any allocation. */ |
| 644 | if (i == len && inline_leaf) { |
| 645 | void *curval; |
| 646 | memcpy(&curval,parentlink,sizeof(curval)); |
| 647 | if (old) *old = curval; |
| 648 | if (overwrite) memcpy(parentlink,&data,sizeof(data)); |
| 649 | errno = 0; |
| 650 | return 0; /* Element already exists. */ |
| 651 | } |
| 652 | |
| 653 | /* If we stopped because we hit an inline leaf but still have |
| 654 | * characters to insert, we must "un-inline" the leaf: allocate |
| 655 | * a real node for it so we can continue the insertion. */ |
| 656 | if (inline_leaf && i < len) { |
| 657 | raxNode *leaf; |
| 658 | if (!raxMaterializeInlineLeaf(rax,h,parentlink,&leaf)) { |
| 659 | errno = ENOMEM; |
| 660 | return 0; |
| 661 | } |
| 662 | h = leaf; |
| 663 | j = 0; |
| 664 | /* h is now a real node with size=0 and iskey=1, iscompr=0. |
| 665 | * Neither ALGO 1 nor ALGO 2 will trigger. We fall through to |
| 666 | * the "insert remaining chars" loop. */ |
| 667 | } |
| 668 | |
| 669 | /* If i == len we walked following the whole string. If we are not |
| 670 | * in the middle of a compressed node, the string is either already |
| 671 | * inserted or this middle node is currently not a key, but can represent |
| 672 | * our key. We have just to reallocate the node and make space for the |
| 673 | * data pointer. */ |
| 674 | if (i == len && (!h->iscompr || j == 0 /* not in the middle if j is 0 */)) { |
| 675 | debugf("### Insert: node representing key exists\n"); |
| 676 | /* Make space for the value pointer if needed. */ |
| 677 | if (!h->iskey || (h->isnull && overwrite)) { |
| 678 | h = raxReallocForData(h,data); |
| 679 | if (h) memcpy(parentlink,&h,sizeof(h)); |
| 680 | } |
| 681 | if (h == NULL) { |
| 682 | errno = ENOMEM; |
| 683 | return 0; |
| 684 | } |
| 685 | |
| 686 | /* Update the existing key if there is already one. */ |
no test coverage detected