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

Feature: transfer the ownership of the yyjson_mut_val #106

Closed faultaddr closed 1 year ago

faultaddr commented 1 year ago

Problem:

I found that we malloc the memory when needed, but the val not keep the ref of the memory access.So, In our situation, It's difficult to detach the memory from the doc for single yyjson_mut_val.

Solution:

So, I try to make some changes, making the real memory detach become possible.

The code is on the way, But I don't know is it reasonable to do as above.

ibireme commented 1 year ago

The yyjson_mut_doc is designed to create JSON data from scratch as quickly as possible. As a result, the memory pool is designed to be simple and not focused on releasing individual values. This allows for fast and easy creation and release of all values. You can find more information about it here: API.md#create-json-document

If you want to control the memory for individual values, a simpler solution would be to use calloc or your own memory pool to create all yyjson_mut_val, and then use yyjson_mut_set_xxx() to assign values. Would this approach work for your needs?

faultaddr commented 1 year ago

Usually a json object is obtained through Parse, In my opinion, remove the single yyjson_mut_val from the original yyjson_mut_doc, and then attach it as a child for another yyjson_mut_doc is impossible under current circumstances.

jsonA: "{\"test1\": \"true\", \"test2\": false}"
jsonB: "{\"test1\": {\"test3\": \"nb\"}, \"test3\": false}"

we would like to make jsonA become {\"test1\": \"true\"} and jsonB become "{\"test1\": {\"test3\": \"nb\"}, \"test2\": false,\"test3\": false}" without any copy operation, something like the std::move to saving time.

so, we define the

struct yyjson_mut_val {
  uint64_t tag;
  yyjson_val_uni uni;
  yyjson_mut_val* next;
  yyjson_val_chunk* val_chunk;
  yyjson_str_chunk* str_chunk;
};

and change the

// do the same thing in unsafe_yyjson_str_pool_grow
bool unsafe_yyjson_val_pool_grow(yyjson_val_pool* pool, yyjson_alc* alc, usize count) {
  yyjson_val_chunk* chunk;
  usize size;

  if (count >= USIZE_MAX / sizeof(yyjson_mut_val) - 16)
    return false;
  size = (count + 1) * sizeof(yyjson_mut_val);
//  size = yyjson_max(pool->chunk_size, size);
  chunk = (yyjson_val_chunk*)alc->malloc(alc->ctx, size);
  if (yyjson_unlikely(!chunk))
    return false;

  chunk->next = pool->chunks;
  pool->chunks = chunk;
  pool->cur = (yyjson_mut_val*)(void*)((u8*)chunk + sizeof(yyjson_mut_val));
  pool->end = (yyjson_mut_val*)(void*)((u8*)chunk + size);

//  size = yyjson_min(pool->chunk_size * 2, pool->chunk_size_max);
//  pool->chunk_size = size;
  return true;
}

when we create new yyjson_mut_val, just record the chunk addr for both val/str. so we can tansfer the ownership when needed.

so we have defined several functions to solve the problem

yyjson_val_chunk* unsafe_yyjson_str_pool_shrink(yyjson_str_pool* pool, yyjson_mut_val* val);
yyjson_str_chunk* unsafe_yyjson_val_pool_shrink(yyjson_val_pool* pool,yyjson_mut_val* val);
bool unsafe_yyjson_str_pool_grow_without_malloc(yyjson_str_pool* pool, yyjson_str_chunk *chunk);
bool unsafe_yyjson_val_pool_grow_without_malloc(yyjson_val_pool* pool, yyjson_val_chunk* chunk);
// change the detach function
yyjson_mut_val* unsafe_yyjson_mut_val_detach(yyjson_mut_doc* old_doc, yyjson_mut_doc* doc, yyjson_mut_val* parent, yyjson_mut_val* item)

Maybe tonight, I would create the PR. lol :) 😁talk is cheap, I will show u the code.