ibireme / yyjson

The fastest JSON library in C
https://ibireme.github.io/yyjson/doc/doxygen/html/
MIT License
3.04k stars 262 forks source link

Add context to pointer results (yyjson_mut_get_pointern_ex) #84

Closed TkTech closed 1 year ago

TkTech commented 2 years ago

I find it common to want to replace the value discovered by a call to yyjson_mut_get_pointer, however the current API provides no context about where in the document the match was found.

I propose a yyjson_mut_get_pointern_ex (which yyjson_mut_get_pointer would use) with something like:

yyjson_mut_val * yyjson_mut_get_pointern_ex(
    const char *pointer,
    size_t pointer_len,
    yyjson_mut_val *container,
    const char *key,
    size_t *idx;
)

This would return the pointer as it does now, but would also populate container (if not NULL) with the yyjson_mut_val that contains the matching value. If container is a yyjson_mut_obj, it would populate key with the matching key. If container is a yyjson_mut_arr, it would populate idx. This would provide enough information to replace the returned value in its parent.

I'm happy to implement this one, but I'm hoping you have an idea for a better API.

ibireme commented 2 years ago

Since the container here is implemented with a circular linked list, I thought it would be enough to return a previous node (previous value in array or previous key in object), for example:

yyjson_mut_val *yyjson_mut_get_pointer_ex(yyjson_mut_val *val,
                                          const char *ptr,
                                          size_t len,
                                          yyjson_mut_val **ctn,
                                          yyjson_mut_val **pre);

void yyjson_mut_replace_pointer_ex(yyjson_mut_val *ctn,
                                   yyjson_mut_val *pre,
                                   yyjson_mut_val *new_val);

void yyjson_mut_remove_pointer_ex(yyjson_mut_val *ctn,
                                  yyjson_mut_val *pre);

The previous node can be used as a one-time token to replace or remove the matching node like this:

void yyjson_mut_replace_pointer_ex(yyjson_mut_val *ctn, 
                                   yyjson_mut_val *pre, 
                                   yyjson_mut_val *new_val) {
    // check input...
    if (yyjson_mut_is_arr(ctn)) {
        yyjson_mut_val *old_val = pre->next;
        if (ctn->uni.ptr == old_val) ctn->uni.ptr = new_val;
        if (old_val->next == old_val) {
            new_val->next = new_val;
        } else {
            new_val->next = old_val->next;
            pre->next = new_val;
        }
    } else {
        yyjson_mut_val *old_key = pre->next->next;
        yyjson_mut_val *old_val = old_key->next;
        new_val->next = old_val->next;
        old_key->next = new_val;
    }
}
TkTech commented 2 years ago

Significantly simpler, I like it :+1:

ibireme commented 1 year ago

The new functions have been added to the master branch.