ibireme / yyjson

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

How to add object to another object? #83

Closed MadDogMayCry0 closed 2 years ago

MadDogMayCry0 commented 2 years ago
{
  "0":{
      "one":"text"
   }
}

and add to it

{
  "1":{
      "one":"text"
   }
}

to become

{
  "0":{
      "one":"text"
   }
  "1":{
      "one":"text"
   }
}

Great lib with bad doc =(

ibireme commented 2 years ago

Sorry for the bad doc...

To iterate over the key-value pairs of an existing object (your first object), you can use iterator API: https://github.com/ibireme/yyjson/blob/master/doc/API.md#json-object-iterator-api

To add a key-value pair to an object (your second object), you can use yyjson_mut_obj_add(obj, key, val) or yyjson_mut_obj_put(obj, key, val): https://github.com/ibireme/yyjson/blob/master/doc/API.md#mutable-json-object-modification-api

MadDogMayCry0 commented 2 years ago

Sorry for the bad doc...

To iterate over the key-value pairs of an existing object (your first object), you can use iterator API: https://github.com/ibireme/yyjson/blob/master/doc/API.md#json-object-iterator-api

To add a key-value pair to an object (your second object), you can use yyjson_mut_obj_add(obj, key, val) or yyjson_mut_obj_put(obj, key, val): https://github.com/ibireme/yyjson/blob/master/doc/API.md#mutable-json-object-modification-api

Please, can you write some example? In cJSON i create two objects and then addOne to AnotherOne. How to do this in your lib?

cJSON *root = cJSON_CreateObject();
cJSON *item = cJSON_CreateObject();
cJSON_AddStringToObject(item,"type","toy");
cJSON_AddStringToObject(item,"ip","myip");
cJSON_AddItemToObject(root, "0", item);

But in case you described above, i can only put a key and set his value, but how to set subItem with his own subKeys (Object)? @ibireme

yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
yyjson_mut_val *root = yyjson_mut_obj(doc);
yyjson_mut_doc_set_root(doc, root);
yyjson_mut_obj_add_str(doc, root, "type", "toy");
yyjson_mut_obj_add_str(doc, root, "ip", "myip");
...
ibireme commented 2 years ago

Here is the complete example code:

// create a doc to manage memory allocation
yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);

// same as cJSON
yyjson_mut_val *root = yyjson_mut_obj(doc);
yyjson_mut_val *item = yyjson_mut_obj(doc);
yyjson_mut_obj_add_strcpy(doc, item, "type", "toy");
yyjson_mut_obj_add_strcpy(doc, item, "ip", "myip");
yyjson_mut_obj_add_val(doc, root, "0", item);

// set doc root, write to string
yyjson_mut_doc_set_root(doc, root);
char *json = yyjson_mut_write(doc, YYJSON_WRITE_PRETTY, NULL);
printf("%s\n", json);

// free all memory
yyjson_mut_doc_free(doc);
free(json);
MadDogMayCry0 commented 2 years ago

Thank you veary much!

MadDogMayCry0 commented 2 years ago

@ibireme

UPD2

int i = 0;
// create a doc to manage memory allocation
yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
// same as cJSON
yyjson_mut_val *root = yyjson_mut_obj(doc);
while(true){
   const char cnt[5];itoa(i,&cnt,10);
   yyjson_mut_val *item = yyjson_mut_obj(doc);
   yyjson_mut_obj_add_strcpy(doc, item, "type", "toy");
   yyjson_mut_obj_add_strcpy(doc, item, "ip", "myip");
   yyjson_mut_obj_add_val(doc, root, cnt, item);
   // set doc root, write to string
   yyjson_mut_doc_set_root(doc, root);
   char *json = yyjson_mut_write(doc, YYJSON_WRITE_PRETTY, NULL);
   printf("%s\n", json);
   free(json);
   // free all memory
   // yyjson_mut_doc_free(doc);
   vTaskDelay(1000 / portTICK_PERIOD_MS);
   i++;
}

strange, but each new key updates all old keys to his own =)

{
    "4": {
        "type": "toy",
        "ip": "myip"
    },
    "4": {
        "type": "toy",
        "ip": "myip"
    },
    "4": {
        "type": "toy",
        "ip": "myip"
    },
    "4": {
        "type": "toy",
        "ip": "myip"
    },
    "4": {
        "type": "toy",
        "ip": "myip"
    }
}

UPD No, it does! Will try some tests. =) Com;ilation on Tensilica Xtensa LX6 (dual core cpu) This one https://en.wikipedia.org/wiki/ESP32 Thx you again!

It's seems to be this library no wanna be compilled for ESP-IDF @ VSCODE over cmake v4 for esp32 chip :(

main/app.c:59: undefined
reference to `yyjson_mut_doc_free'
collect2.exe: error: ld returned 1 exit status
MadDogMayCry0 commented 2 years ago

@ibireme

UPD2

int i = 0;
// create a doc to manage memory allocation
yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
// same as cJSON
yyjson_mut_val *root = yyjson_mut_obj(doc);
while(true){
   const char cnt[5];itoa(i,&cnt,10);
   yyjson_mut_val *item = yyjson_mut_obj(doc);
   yyjson_mut_obj_add_strcpy(doc, item, "type", "toy");
   yyjson_mut_obj_add_strcpy(doc, item, "ip", "myip");
   yyjson_mut_obj_add_val(doc, root, cnt, item);
   // set doc root, write to string
   yyjson_mut_doc_set_root(doc, root);
   char *json = yyjson_mut_write(doc, YYJSON_WRITE_PRETTY, NULL);
   printf("%s\n", json);
   free(json);
   // free all memory
   // yyjson_mut_doc_free(doc);
   vTaskDelay(1000 / portTICK_PERIOD_MS);
   i++;
}

strange, but each new key updates all old keys to his own =)


{
    "4": {
        "type": "toy",
        "ip": "myip"
    },
    "4": {
        "type": "toy",
        "ip": "myip"
    },
    "4": {
        "type": "toy",
        "ip": "myip"
    },
    "4": {
        "type": "toy",
        "ip": "myip"
    },
    "4": {
        "type": "toy",
        "ip": "myip"
    }
}
ibireme commented 2 years ago

The string is not copied by default , you need to use the API with the cpy to copy the value:

yyjson_mut_val *key = yyjson_mut_strcpy(doc, cnt);
yyjson_mut_obj_add(doc, key, item);

The documentation here is not clear enough, I'll update it later.

MadDogMayCry0 commented 2 years ago

@ibireme

int i = 0;
yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
yyjson_mut_val *root = yyjson_mut_obj(doc);
while(true){
   char cnt[5];itoa(i,&cnt,10);
   yyjson_mut_val *item = yyjson_mut_obj(doc);
   yyjson_mut_obj_add_str(doc, item, "type", "toy");
   yyjson_mut_obj_add_str(doc, item, "ip", "myip");
   yyjson_mut_val *key = yyjson_mut_strcpy(doc, cnt);
   yyjson_mut_obj_add(doc, key, item);
   yyjson_mut_doc_set_root(doc, root);
   char *json = yyjson_mut_write(doc, YYJSON_WRITE_PRETTY, NULL);
   printf("%s\n", json);
   free(json);
   vTaskDelay(1000 / portTICK_PERIOD_MS);
   i++;
}

now i have {} in output string :(

ibireme commented 2 years ago

My mistake, that line should be: yyjson_mut_obj_add(root, key, item);. I've tested and the output should be OK now.

MadDogMayCry0 commented 2 years ago

@ibireme

My mistake, that line should be: yyjson_mut_obj_add(root, key, item);. I've tested and the output should be OK now.

Some tests:

cJSON_AddStringToObject(item,"type", "toys");
cJSON_AddStringToObject(item,"ip","Hello, it's me Mario :)");
cJSON_AddItemToObject(root, cnt, item);

adding key value's pair as above:

YYJSON - 4uS (WOW)
cJSON - 65uS veary slow...

my ram is 225kb max objects for:

cJSON 1573
YYJSON 1359

So, speed needs more ram.

Ok, conclusion on this moment looks like:

int i = 0;
yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
yyjson_mut_val *root = yyjson_mut_obj(doc);
while(true){
    char cnt[5];itoa(i,&cnt,10);
    yyjson_mut_val *item = yyjson_mut_obj(doc);
    yyjson_mut_obj_add_str(doc, item, "type", "toy");
    yyjson_mut_obj_add_str(doc, item, "ip", "myip");
    yyjson_mut_val *key = yyjson_mut_strcpy(doc, cnt);
    yyjson_mut_obj_add(root, key, item);
    yyjson_mut_doc_set_root(doc, root);

    char *json = yyjson_mut_write(doc, YYJSON_WRITE_PRETTY, NULL);
    printf("%s\n", json);
    free(json);
    i++;
}

For example, how to get "toy" from "0"->"type"->"toy"? in a foreach cycle?

"0": {
     "type": "toy",
     "ip": "myip"
}

How to convert yyjson_val to char[] ?

size_t idx, max;
yyjson_val *key_, *val;
yyjson_obj_foreach(root, idx, max, key_, val){
   printf("key:%s - val:%s",key_,val);
}
format '%s' expects argument of type 'char *', but argument 7 has type 'yyjson_val *'
ibireme commented 2 years ago

To get the content from val, you can use yyjson_get_xxx(val):

const char *json = "{\"0\":{\"type\":\"toy0\"},\"1\":{\"type\":\"toy1\"}}";
yyjson_doc *doc = yyjson_read(json, strlen(json), 0);
yyjson_val *root = yyjson_doc_get_root(doc);

usize idx, max;
yyjson_val *key, *val;
yyjson_obj_foreach(root, idx, max, key, val) {
    printf("key: %s\n", yyjson_get_str(key)); // "0", "1"
    yyjson_val *type = yyjson_obj_get(val, "type");
    printf("type: %s\n", yyjson_get_str(type)); // "toy0", "toy1"
}
MadDogMayCry0 commented 2 years ago

@ibireme

To get the content from val, you can use yyjson_get_xxx(val):

const char *json = "{\"0\":{\"type\":\"toy0\"},\"1\":{\"type\":\"toy1\"}}";
yyjson_doc *doc = yyjson_read(json, strlen(json), 0);
yyjson_val *root = yyjson_doc_get_root(doc);

usize idx, max;
yyjson_val *key, *val;
yyjson_obj_foreach(root, idx, max, key, val) {
    printf("key: %s\n", yyjson_get_str(key)); // "0", "1"
    yyjson_val *type = yyjson_obj_get(val, "type");
    printf("type: %s\n", yyjson_get_str(type)); // "toy0", "toy1"
}

Ok, i see you use new string, but i want to use current Objects in ram. I doing same, but get PANIC

yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
yyjson_mut_val *root = yyjson_mut_obj(doc);
while(true){
   char cnt[5];itoa(i,&cnt,10);
   yyjson_mut_val *key = yyjson_mut_str(doc, cnt);
   yyjson_mut_val *item = yyjson_mut_obj(doc);
   yyjson_mut_obj_add_str(doc, item, "type", "toy");
   yyjson_mut_obj_add_str(doc, item, "ip", "Hello, it's me Mario :)");
   if(yyjson_mut_obj_add(root, key, item)){
      usize idx, max;
      yyjson_val *key, *val;
      yyjson_obj_foreach(root, idx, max, key, val) {
          printf("key: %s\n", yyjson_get_str(key)); // "0", "1"
          yyjson_val *type = yyjson_obj_get(val, "type");
          printf("type: %s\n", yyjson_get_str(type)); // "toy0", "toy1"
      }
   }
}

with this i get nothing in foreach (0 cycles)

yyjson_val *root = yyjson_doc_get_root(doc);

Help =(

ibireme commented 2 years ago

All mutable values should be called with mut function, otherwise there will be a type mismatch warning. The inner loop should be:

          usize idx, max;
          yyjson_mut_val *key_i, *val_i;
          yyjson_mut_obj_foreach(root, idx, max, key_i, val_i) {
              printf("key: %s\n", yyjson_mut_get_str(key_i)); // "0", "1"
              yyjson_mut_val *type = yyjson_mut_obj_get(val_i, "type");
              printf("type: %s\n", yyjson_mut_get_str(type)); // "toy0", "toy1"
          }
MadDogMayCry0 commented 2 years ago

@ibireme i try to remove key in root

yyjson_mut_val *test = yyjson_mut_obj_get(root, "0");
yyjson_mut_obj_clear(test);

or

yyjson_mut_obj_remove(root, "0");

Without success.. I promise to make simple examples based on your answers =)

ibireme commented 2 years ago

Try this

yyjson_mut_obj_remove_str(root, "0");

or

yyjson_mut_obj_remove(root, yyjson_mut_str(doc, "0"));

When passing in the wrong type, you should get a incompatible pointer types passing warning in compile log.

MadDogMayCry0 commented 2 years ago

It's works. I'll be back later and post simple examples that someone can use in future! Thank you! Don't close issue pls, maby i have more question about sub objects and sub arrays.

MadDogMayCry0 commented 2 years ago

@ibireme I did some tests and i have something wrong.

It seems that the method that deletes the string does not release memory, or I'm doing something wrong. After ten deletion cycles, the memory does not return to its original value, but continues to be consumed.

int i = 0;
int d = 15;
yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
yyjson_mut_val *root = yyjson_mut_obj(doc);
while(true){
    char cnt[5];itoa(i,&cnt,10);
    if(i<=15){
        yyjson_mut_val *obj = yyjson_mut_strcpy(doc, cnt);
        yyjson_mut_val *item = yyjson_mut_obj(doc);
        yyjson_mut_obj_add_str(doc, item, "name", "djfhsdkjafhj sadhlfjhsaldjf hlskjad fhljksadhf lkjsadhfl jhsadlkjf hlsakdjf hlkjsadh flkjasdhf lkjsahdlfjk hsalkdjfh");
        yyjson_mut_obj_add_str(doc, item, "type", "dfkjsdkfj lsdkjflk sjdlfjsdl jflsdkjflksjdfl kjsdlfkj lsdkfj lskdfj");
        yyjson_mut_obj_add(root, obj, item);
        i++;
    }
    else{
        char cnt[5];itoa(d,&cnt,10);
        yyjson_mut_obj_remove_str(root,cnt);
        if(d==0){
            i=0;
            d=16;
        }
        d--;
    }
}
Before cycles 359457
After 10 deliting cycles 317256
After 40 deliting cycles 249144
ibireme commented 2 years ago

It seems that the method that deletes the string does not release memory, or I'm doing something wrong. After ten deletion cycles, the memory does not return to its original value, but continues to be consumed.

This behavior is documented: https://github.com/ibireme/yyjson/blob/master/doc/API.md#create-json-document

MadDogMayCry0 commented 2 years ago

@ibireme

It seems that the method that deletes the string does not release memory, or I'm doing something wrong. After ten deletion cycles, the memory does not return to its original value, but continues to be consumed.

This behavior is documented: https://github.com/ibireme/yyjson/blob/master/doc/API.md#create-json-document

How, then, to keep a constantly changing dynamic object? I need to keep a dynamically changing object in memory throughout the whole time :(

ibireme commented 2 years ago

How, then, to keep a constantly changing dynamic object? I need to keep a dynamically changing object in memory throughout the whole time :(

You can use yyjson_mut_doc_mut_copy() to create a copy and then free the old doc. But as the documentation says, yyjson_mut_doc is more suitable for write-once, than mutation of an existing document.

MadDogMayCry0 commented 2 years ago

How, then, to keep a constantly changing dynamic object? I need to keep a dynamically changing object in memory throughout the whole time :(

You can use yyjson_mut_doc_mut_copy() to create a copy and then free the old doc. But as the documentation says, yyjson_mut_doc is more suitable for write-once, than mutation of an existing document.

It's any other way to use something else instead of mut in my case?

ibireme commented 2 years ago

How, then, to keep a constantly changing dynamic object? I need to keep a dynamically changing object in memory throughout the whole time :(

You can use yyjson_mut_doc_mut_copy() to create a copy and then free the old doc. But as the documentation says, yyjson_mut_doc is more suitable for write-once, than mutation of an existing document.

It's any other way to use something else instead of mut in my case?

You can use your own data structures to hold your values, and then create the JSON doc, serialize to string, free it all at once when you need a JSON string.

MadDogMayCry0 commented 2 years ago

@ibireme Or we can get new function

yyjson_doc_update_size(doc);

=)

ibireme commented 2 years ago

It's hard to do that, for example:

┌───────────────────────────────────────────────────┐
│0 toy myip 1 toy1 myip1                            │
└▲─▲────────────────────────────────────────────────┘
 │ │                                                 
 └─┼──── yyjson_mut_val *val1 = yyjson_mut_strcpy(doc, "0");                      
   │                                                 
   └──── yyjson_mut_val *val2 = yyjson_mut_strcpy(doc, "toy");             

Multiple strings are stored in one contiguous memory area. When you try to free val1, the memory of string is not actually freed.

MadDogMayCry0 commented 2 years ago

@ibireme Ok, let me going through mut_doc_free way. I try to

int i = 0;
int d = 15;
yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
yyjson_mut_val *root = yyjson_mut_obj(doc);
while(true){
    char cnt[5];itoa(i,&cnt,10);
    if(i<=15){
        yyjson_mut_val *obj = yyjson_mut_strcpy(doc, cnt);
        yyjson_mut_val *item = yyjson_mut_obj(doc);
        yyjson_mut_obj_add_str(doc, item, "name", "djfhsdkjafhj sadhlfjhsaldjf hlskjad fhljksadhf lkjsadhfl jhsadlkjf hlsakdjf hlkjsadh flkjasdhf lkjsahdlfjk hsalkdjfh");
        yyjson_mut_obj_add_str(doc, item, "type", "dfkjsdkfj lsdkjflk sjdlfjsdl jflsdkjflksjdfl kjsdlfkj lsdkfj lskdfj");
        yyjson_mut_obj_add(root, obj, item);
        i++;
    }
    else{
        char cnt[5];itoa(d,&cnt,10);
        yyjson_mut_obj_remove_str(root,cnt);
        yyjson_mut_doc *alc = yyjson_mut_doc_new(NULL);
        yyjson_mut_doc_mut_copy(doc,alc);
        yyjson_mut_doc_free(doc);
        doc = yyjson_mut_doc_new(alc);
        root = yyjson_mut_obj(doc);
        if(d==0){
            i=0;
            d=16;
        }
        d--;
    }
}

but this is trash i think :D help!

ibireme commented 2 years ago

I'm not sure what you want... For this loop code, it is more efficient to clean up memory while d==0. This is a space-time trade off.

MadDogMayCry0 commented 2 years ago

I'm not sure what you want... For this loop code, it is more efficient to clean up memory while d==0. This is a space-time trade off.

I need to get an object that is always in memory and its structure is available at any time. However, I don't want to leak memory when I delete its elements. You told me that i can use the method to copy the doc and then free it (hovever i don't understand this model). I just tried to reproduce this situation above. https://github.com/ibireme/yyjson/issues/83#issuecomment-1118342721

ibireme commented 2 years ago

I'm not sure what you want... For this loop code, it is more efficient to clean up memory while d==0. This is a space-time trade off.

I need to get an object that is always in memory and its structure is available at any time. However, I don't want to leak memory when I delete its elements. You told me that i can use the method to copy the doc and then free it (hovever i don't understand this model). I just tried to reproduce this situation above. #83 (comment)

yyjson is not designed for that, yyjson focus on speed and does not provide a function to free a single value. If you want to free some of these values, this is the only way (current version):

// deep copy all values referenced from root
yyjson_mut_doc *tmp_doc = yyjson_mut_doc_mut_copy(doc, NULL);

// free all old values
yyjson_mut_doc_free(doc);

// replace old doc
doc = tmp_doc;
MadDogMayCry0 commented 2 years ago

@ibireme I dont sure, but i have a PANIC take a look pls

yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
yyjson_mut_val *root = yyjson_mut_obj(doc);

yyjson_mut_val *obj0 = yyjson_mut_strcpy(doc, "0");
yyjson_mut_val *item = yyjson_mut_obj(doc);
yyjson_mut_obj_add_str(doc, item, "toy", "some toy");
yyjson_mut_obj_add(root, obj0, item);

yyjson_mut_obj_remove_str(root,"0");
yyjson_mut_doc *tmp_doc = yyjson_mut_doc_mut_copy(doc, NULL);
yyjson_mut_doc_free(doc);
doc = tmp_doc;

yyjson_mut_doc_set_root(doc, root);
char *json = yyjson_mut_write(doc, YYJSON_WRITE_PRETTY, NULL);
printf("%s\n", json);
free(json);
ibireme commented 2 years ago

@MadDogMayCry0 The memory of yyjson_mut_val is held by doc, if you free the doc, all the values created from it will be freed too.

yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
yyjson_mut_val *root = yyjson_mut_obj(doc);
yyjson_mut_doc_set_root(doc, root); // set the root before copy

yyjson_mut_val *obj0 = yyjson_mut_strcpy(doc, "0");
yyjson_mut_val *item = yyjson_mut_obj(doc);
yyjson_mut_obj_add_str(doc, item, "toy", "some toy");
yyjson_mut_obj_add(root, obj0, item);

yyjson_mut_obj_remove_str(root,"0");
yyjson_mut_doc *tmp_doc = yyjson_mut_doc_mut_copy(doc, NULL);
yyjson_mut_doc_free(doc); // free all values
doc = tmp_doc;

// yyjson_mut_doc_set_root(doc, root); // the `root` is created from old doc, no longer valid here
char *json = yyjson_mut_write(doc, YYJSON_WRITE_PRETTY, NULL);
printf("%s\n", json);
free(json);
MadDogMayCry0 commented 2 years ago

@ibireme Hmmm...

void json(){
    int i = 0;
    int d = 5;
    yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
    yyjson_mut_val *root = yyjson_mut_obj(doc);
    yyjson_mut_doc_set_root(doc, root);
    while(true){
        if(i<=5){
            char cnt[5];itoa(i,&cnt,10);
            yyjson_mut_val *obj = yyjson_mut_strcpy(doc, cnt);
            yyjson_mut_val *item = yyjson_mut_obj(doc);
            yyjson_mut_obj_add_str(doc, item, "toy", "some toy");
            yyjson_mut_obj_add(root, obj, item);
            i++;
        }
        else{
            char cnt[5];itoa(d,&cnt,10);

            yyjson_mut_obj_remove_str(root,cnt);
            yyjson_mut_doc *tmp_doc = yyjson_mut_doc_mut_copy(doc, NULL);
            yyjson_mut_doc_free(doc);
            doc = tmp_doc;

            d--;
            if(d==-1){
                i=0;
                d=5;
            }
        }
        char *json = yyjson_mut_write(doc, YYJSON_WRITE_PRETTY, NULL);
        printf("%s\n", json);
        free(json);
    }
}

its can only get first DELETION cycle (i>5), then did deleted key "5", and when it trying to delete key "4" then core panic :(

ibireme commented 2 years ago

Same mistake:

void json(){
    int i = 0;
    int d = 5;
    yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
    yyjson_mut_val *root = yyjson_mut_obj(doc);
    yyjson_mut_doc_set_root(doc, root);
    while(true){
        if(i<=5){
            char cnt[5];itoa(i,&cnt,10);
            yyjson_mut_val *obj = yyjson_mut_strcpy(doc, cnt);
            yyjson_mut_val *item = yyjson_mut_obj(doc);
            yyjson_mut_obj_add_str(doc, item, "toy", "some toy");
            yyjson_mut_obj_add(root, obj, item);
            i++;
        }
        else{
            char cnt[5];itoa(d,&cnt,10);

            yyjson_mut_obj_remove_str(root,cnt);
            yyjson_mut_doc *tmp_doc = yyjson_mut_doc_mut_copy(doc, NULL);
            yyjson_mut_doc_free(doc); // `root` is also freed
            doc = tmp_doc;
            root = yyjson_mut_doc_get_root(doc); // get new `root` from new `doc`

            d--;
            if(d==-1){
                i=0;
                d=5;
            }
        }
        char *json = yyjson_mut_write(doc, YYJSON_WRITE_PRETTY, NULL);
        printf("%s\n", json);
        free(json);
    }
}
MadDogMayCry0 commented 2 years ago

@ibireme hmm. me again. It's seems to be something strange.

void json(){
    int i = 0;
    int d = 500;
    yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
    yyjson_mut_val *root = yyjson_mut_obj(doc);
    yyjson_mut_doc_set_root(doc, root);
    while(true){
        if(i<=500){
            char cnt[5];itoa(i,&cnt,10);
            yyjson_mut_val *obj = yyjson_mut_strcpy(doc, cnt);
            yyjson_mut_val *item = yyjson_mut_obj(doc);
            yyjson_mut_obj_add_str(doc, item, "toy", "some toy djfhsdjkfh kjsdfhkjsdhfkjhs dkjfhskdj hfkjsdhf kjsdhfk jhsdkjfh skdjhf kjsdhf kjshdkfj hsdkjf hksjdhf ksjfh kjsdhfkjsdhfkjhsdkj hfksjdh fkjsdhf kjshdkfj hskjdfh");
            yyjson_mut_obj_add(root, obj, item);
            i++;
        }
        else{
            char cnt[5];itoa(d,&cnt,10);

            yyjson_mut_obj_remove_str(root,cnt);
            yyjson_mut_doc *tmp_doc = yyjson_mut_doc_mut_copy(doc, NULL);
            yyjson_mut_doc_free(doc);
            doc = tmp_doc;
            root = yyjson_mut_doc_get_root(doc);

            d--;
            if(d==-1){
                i=0;
                d=500;
            }
        }
        // char *json = yyjson_mut_write(doc, YYJSON_WRITE_PRETTY, NULL);
        // printf("%s\n", json);
        // free(json);
    }
}

if this line is in game

char *json = yyjson_mut_write(doc, YYJSON_WRITE_PRETTY, NULL);
printf("%s\n", json);
free(json);

then its ok, and i see that mut_cpy and fee works and took 1027uS of time. When this block of code above is commented, then after two normal "DELITING" for keys 500 and 499 (took 1000uS of time) then on key 498 and next others its took only 2uS and seems to be DOC is {} becuse i see that RAM will newer changes after that and its full and free.

ibireme commented 2 years ago

I tested your code in macOS+clang and checked with address sanitizer/footprint, and it seems to work fine. If your memory is really small, you should check each return value to make sure the memory allocation was successful.

Besides, you should release the memory once inside d==-1 block.

MadDogMayCry0 commented 2 years ago

@ibireme

I tested your code in macOS+clang and checked with address sanitizer/footprint, and it seems to work fine. If your memory is really small, you should check each return value to make sure the memory allocation was successful.

The lib is terrable stable and fast! Yes, you are right about memory,- i forgoth, that copy structure needs ram for its self.

Bad for me your very cool library is not suitable for my use case :( I need to free memory every time an element is deleted. Maybe in the future you will add some new type of elements for such scenarios. Thank you for help!

MadDogMayCry0 commented 2 years ago

@ibireme Ok, i just use _free when no keys inside of doc and a many keys has been deleted before it. It's helps but i don't sure this is a right way :) I will add examples as i promised later! Thank you :) :+1:

MadDogMayCry0 commented 2 years ago

@ibireme This is me again.. I fight for w freedom, and try to change "value"

const char *str = "{\"key\":\"value\"}";
    yyjson_doc *json = yyjson_read(str, strlen(str), 0);
    yyjson_val *val = yyjson_mut_doc_get_root(json);
    yyjson_mut_obj_put(val,"key","hehe");
    if(json){
        yyjson_val *name = yyjson_obj_get(val, "key");
        printf("name: %s\n", yyjson_get_str(name));
    }
    yyjson_doc_free(json);

but still have "value" :(

ibireme commented 2 years ago
const char *str = "{\"key\":\"value\"}";
yyjson_doc *json = yyjson_read(str, strlen(str), 0);

// Incompatible pointer types initializing 'yyjson_val *' (aka 'struct yyjson_val *') with an expression of type 'yyjson_mut_val *' (aka 'struct yyjson_mut_val *')
yyjson_val *val = yyjson_mut_doc_get_root(json);

// Incompatible pointer types passing 'char [4]' to parameter of type 'yyjson_mut_val *' (aka 'struct yyjson_mut_val *')

// Incompatible pointer types passing 'char [5]' to parameter of type 'yyjson_mut_val *' (aka 'struct yyjson_mut_val *')

// Incompatible pointer types passing 'yyjson_val *' (aka 'struct yyjson_val *') to parameter of type 'yyjson_mut_val *' (aka 'struct yyjson_mut_val *')
yyjson_mut_obj_put(val,"key","hehe");
if(json){
    yyjson_val *name = yyjson_obj_get(val, "key");
    printf("name: %s\n", yyjson_get_str(name));
}
yyjson_doc_free(json);

You should read the documentation, or at least use an editor/IDE with error checking.

MadDogMayCry0 commented 2 years ago

@ibireme

UPD Ok, i got it....

const char *str = "{\"key\":\"value\"}";
    yyjson_doc *input = yyjson_read(str, strlen(str), 0);
    yyjson_mut_doc *json = yyjson_doc_mut_copy(input, NULL);

i hope this is a right way.

const char *str = "{\"key\":\"value\"}";
    yyjson_mut_doc *json = yyjson_read(str, strlen(str), 0);
    yyjson_mut_val *base = yyjson_mut_doc_get_root(json);
    if(json){
        yyjson_mut_val *name = yyjson_mut_obj_get(base, "key");
        printf("name: %s\n", yyjson_mut_get_str(name));
    }
    yyjson_mut_doc_free(json);
warning: initialization of
'yyjson_mut_doc *' {aka 'struct yyjson_mut_doc *'} from incompatible pointer type 'yyjson_doc *' {aka 'struct yyjson_doc *'} [-Wincompatible-pointer-types]
     yyjson_mut_doc *json = yyjson_read(str, strlen(str), 0);
MadDogMayCry0 commented 2 years ago

@ibireme I really don't understand on how to read this documentation and understand it :(

/** Replaces value from the object with given key.
    @warning This function takes a linear search time. */
yyjson_api_inline bool yyjson_mut_obj_replace(yyjson_mut_val *obj,
                                              yyjson_mut_val *key,
                                              yyjson_mut_val *val);

Ok, nice! Let's go!

const char *str = "{\"key\":\"value\"}";
    yyjson_doc *input = yyjson_read(str, strlen(str), 0);
    yyjson_mut_doc *json = yyjson_doc_mut_copy(input, NULL);
    yyjson_mut_val *base = yyjson_mut_doc_get_root(json);
    yyjson_mut_val *key = yyjson_mut_obj_get(base, "key");
    yyjson_mut_val *val = yyjson_mut_str(json,"blabla");
    yyjson_mut_obj_replace(base,key,val);
    if(json){
        yyjson_mut_val *name = yyjson_mut_obj_get(base, "key");
        printf("name: %s\n", yyjson_mut_get_str(name));
    }
    yyjson_mut_doc_free(json);

output:

"value"

...

const char *str = "{\"key\":\"value\"}";
    yyjson_doc *input = yyjson_read(str, strlen(str), 0);
    yyjson_mut_doc *json = yyjson_doc_mut_copy(input, NULL);
    yyjson_mut_val *base = yyjson_mut_doc_get_root(json);    
   yyjson_mut_val *key = yyjson_mut_str(json, "key");
    yyjson_mut_val *val = yyjson_mut_str(json, "dolphin");
    yyjson_mut_obj_put(base,key,val);
    if(json){
        yyjson_mut_val *name = yyjson_mut_obj_get(base, "key");
        printf("name: %s\n", yyjson_mut_get_str(name));
    }
    yyjson_mut_doc_free(json);

output: "dolphin" ...

ibireme commented 2 years ago

Here is a mistake:

const char *str = "{\"key\":\"value\"}";
    yyjson_doc *input = yyjson_read(str, strlen(str), 0);
    yyjson_mut_doc *json = yyjson_doc_mut_copy(input, NULL);
    yyjson_mut_val *base = yyjson_mut_doc_get_root(json);
    yyjson_mut_val *key = yyjson_mut_obj_get(base, "key"); // this returns "value", not "key"
    yyjson_mut_val *val = yyjson_mut_str(json,"blabla");
    yyjson_mut_obj_replace(base,key,val); // and this will fail, nothing will be changed
    if(json){
        yyjson_mut_val *name = yyjson_mut_obj_get(base, "key");
        printf("name: %s\n", yyjson_mut_get_str(name));
    }
    yyjson_mut_doc_free(json);

output:

"value"

This code looks correct:

const char *str = "{\"key\":\"value\"}";
    yyjson_doc *input = yyjson_read(str, strlen(str), 0);
    yyjson_mut_doc *json = yyjson_doc_mut_copy(input, NULL);
    yyjson_mut_val *base = yyjson_mut_doc_get_root(json);    
   yyjson_mut_val *key = yyjson_mut_str(json, "key");
    yyjson_mut_val *val = yyjson_mut_str(json, "dolphin");
    yyjson_mut_obj_put(base,key,val);
    if(json){
        yyjson_mut_val *name = yyjson_mut_obj_get(base, "key");
        printf("name: %s\n", yyjson_mut_get_str(name));
    }
    yyjson_mut_doc_free(json);

output: "dolphin" ...

This library is optimized for building JSON, not manipulating JSON objects frequently. The key-value pairs of objects are stored in linked list, so adding is fast, but searching and replacing is slow.

MadDogMayCry0 commented 2 years ago

@ibireme

yyjson_mut_val *key = yyjson_mut_obj_get(base, "key"); // this returns "value", not "key"

how to get key? :)

ibireme commented 2 years ago

@ibireme

yyjson_mut_val *key = yyjson_mut_obj_get(base, "key"); // this returns "value", not "key"

how to get key? :)

As your second code snippet above, use yyjson_mut_str() to create the key, or use iterator/for_each macro to iterate over all keys.

MadDogMayCry0 commented 2 years ago

@ibireme Me again.. I don;t realy sure about BUG, but take a look

bool json_put(yyjson_mut_doc *json,yyjson_mut_val* obj,char* obj_key, char* obj_val){
    yyjson_mut_val *key = yyjson_mut_str(json, obj_key);
    yyjson_mut_val *val = yyjson_mut_str(json, obj_val);
    // I tryed mut_put with same result
    return yyjson_mut_obj_replace(obj,key,val);
}

char buff[256]="{\"dhcp\":\"false\",\"ip\":\"192.168.1.15\",\"mask\":\"255.255.255.0\",\"gw\":\"192.168.1.1\",\"dns1\":\"192.168.1.1\",\"dns2\":\"8.8.8.8\"}";

yyjson_mut_doc *eth_json = json_doc(buff,strlen(buff));
yyjson_mut_val *eth_root = yyjson_mut_doc_get_root(eth_json);

Now, if i use

json_put(eth_json,eth_root,"dhcp","true");

i got

{"dhcp":"true","ip":"192.168.1.15","mask":"255.255.255.0","gw":"192.168.1.1","dns1":"192.168.1.1","dns2":"8.8.8.8"}

and after "false" seems to be ok. When i then try to change another elements

json_put(eth_json,eth_root,"ip","192.168.1.7");
json_put(eth_json,eth_root,"gw","192.168.1.1");
json_put(eth_json,eth_root,"mask","255.255.255.0");
json_put(eth_json,eth_root,"dns1","192.168.1.1");
json_put(eth_json,eth_root,"dns2","8.8.8.7");

I got after

{"dhcp":"68.1.7","ip":"192.168.1.7","mask":"255.255.255.0","gw":"192.168.1.1","dns1":"192.168.1.1","dns2":"8.8.8.7"}

amd when now i repeat this one again

json_put(eth_json,eth_root,"dhcp","true");

i got

{"dhcp":"true","ip":"dhcp\u0000true\u0000\u0000","mask":"255.255.255.0","gw":"192.168.1.1","dns1":"192.168.1.1","dns2":"8.8.8.7"}

Hmm...

ibireme commented 2 years ago

I have tested with these codes and it seems OK:

char buff[256]="{\"dhcp\":\"false\",\"ip\":\"192.168.1.15\",\"mask\":\"255.255.255.0\",\"gw\":\"192.168.1.1\",\"dns1\":\"192.168.1.1\",\"dns2\":\"8.8.8.8\"}";
yyjson_doc *doc = yyjson_read(buff, strlen(buff), 0);

yyjson_mut_doc *eth_json = yyjson_doc_mut_copy(doc, NULL);
yyjson_mut_val *eth_root = yyjson_mut_doc_get_root(eth_json);

json_put(eth_json,eth_root,"dhcp","true");

json_put(eth_json,eth_root,"ip","192.168.1.7");
json_put(eth_json,eth_root,"gw","192.168.1.1");
json_put(eth_json,eth_root,"mask","255.255.255.0");
json_put(eth_json,eth_root,"dns1","192.168.1.1");
json_put(eth_json,eth_root,"dns2","8.8.8.7");

json_put(eth_json,eth_root,"dhcp","true");

char *str = yyjson_mut_write(eth_json, 0, NULL);

output:

"{\"dhcp\":\"true\",\"ip\":\"192.168.1.7\",\"mask\":\"255.255.255.0\",\"gw\":\"192.168.1.1\",\"dns1\":\"192.168.1.1\",\"dns2\":\"8.8.8.7\"}"

I noticed that the value of ip contains some NUL characters, maybe you are not using a constant string. Try using the yyjson_mut_strcpy() function to copy the string into val. See comment: https://github.com/ibireme/yyjson/blob/331037f038c2e673f6567b132aede74196f87b58/src/yyjson.h#L1676-L1679

MadDogMayCry0 commented 2 years ago

@ibireme

I have tested with these codes and it seems OK:

char buff[256]="{\"dhcp\":\"false\",\"ip\":\"192.168.1.15\",\"mask\":\"255.255.255.0\",\"gw\":\"192.168.1.1\",\"dns1\":\"192.168.1.1\",\"dns2\":\"8.8.8.8\"}";
yyjson_doc *doc = yyjson_read(buff, strlen(buff), 0);

yyjson_mut_doc *eth_json = yyjson_doc_mut_copy(doc, NULL);
yyjson_mut_val *eth_root = yyjson_mut_doc_get_root(eth_json);

json_put(eth_json,eth_root,"dhcp","true");

json_put(eth_json,eth_root,"ip","192.168.1.7");
json_put(eth_json,eth_root,"gw","192.168.1.1");
json_put(eth_json,eth_root,"mask","255.255.255.0");
json_put(eth_json,eth_root,"dns1","192.168.1.1");
json_put(eth_json,eth_root,"dns2","8.8.8.7");

json_put(eth_json,eth_root,"dhcp","true");

char *str = yyjson_mut_write(eth_json, 0, NULL);

output:

"{\"dhcp\":\"true\",\"ip\":\"192.168.1.7\",\"mask\":\"255.255.255.0\",\"gw\":\"192.168.1.1\",\"dns1\":\"192.168.1.1\",\"dns2\":\"8.8.8.7\"}"

I noticed that the value of ip contains some NUL characters, maybe you are not using a constant string. Try using the yyjson_mut_strcpy() function to copy the string into val. See comment:

https://github.com/ibireme/yyjson/blob/331037f038c2e673f6567b132aede74196f87b58/src/yyjson.h#L1676-L1679

When i did it in line like you, it's works too/ But i'm sure, if you try to separate it in a time, it's will works like described above. Try to write console scenario, and when you send "1" to console, PUT "dhcp", and when u press "2" put IP. after 3'st try u become this BUG. But don't FREE json after each PUT's.

ibireme commented 2 years ago

@MadDogMayCry0 When you use console input, your string is not constant and the memory it points to may be modified. So you should use yyjson_mut_strcpy() to copy that string.