add value_replace

This commit is contained in:
lixianjing 2025-04-27 17:50:46 +08:00
parent 293492c1b4
commit a6a06a3380
9 changed files with 105 additions and 20 deletions

View File

@ -1,5 +1,8 @@
# 最新动态
2025/04/27
* 增加value_replace用于避免value\ data的内存地址相同导致先reset后deep_copy出现野指针的问题(感谢兆坤提供补丁)。
2025/04/25
* object有属性删除时发送EVT_PROPS_CHANGED事件(感谢兆坤提供补丁)。

View File

@ -196,10 +196,7 @@ static ret_t fscript_locals_get(fscript_t* fscript, const value_t* name, value_t
static ret_t fscript_locals_set_with_index(fscript_t* fscript, uint32_t index, const value_t* v) {
named_value_t* nv = (named_value_t*)(fscript->locals->elms[index]);
if (nv->value.free_handle) {
value_reset(&(nv->value));
}
return value_deep_copy(&(nv->value), v);
return value_replace(&(nv->value), v, TRUE);
}
static ret_t fscript_locals_set(fscript_t* fscript, const value_t* name, value_t* v) {

View File

@ -92,12 +92,7 @@ ret_t named_value_set_value(named_value_t* nv, const value_t* value) {
return RET_OK;
}
if (!value_equal(value, &(nv->value))) {
value_reset(&(nv->value));
return value_deep_copy(&(nv->value), value);
}
return RET_OK;
return value_replace(&(nv->value), value, TRUE);
}
ret_t named_value_deinit(named_value_t* nv) {

View File

@ -241,8 +241,7 @@ ret_t object_array_set(tk_object_t* obj, uint32_t index, const value_t* v) {
if (index < o->size) {
value_t* iter = o->props + index;
value_reset(iter);
ret = value_deep_copy(iter, v);
ret = value_replace(iter, v, TRUE);
emitter_dispatch(EMITTER(o), &e);
} else if (index == -1) {
ret = object_array_push(obj, v);

View File

@ -159,8 +159,7 @@ static ret_t value_deep_copy_keep_type(value_t* dst, const value_t* src) {
}
default: {
if (dst->type == src->type) {
value_reset(dst);
value_deep_copy(dst, src);
value_replace(dst, src, TRUE);
} else {
ret = RET_FAIL;
log_debug("not support type:%d\n", dst->type);
@ -190,8 +189,7 @@ static ret_t object_default_set_prop(tk_object_t* obj, const char* name, const v
if (o->keep_prop_type) {
ret = value_deep_copy_keep_type(vv, v);
} else {
value_reset(vv);
ret = value_deep_copy(vv, v);
ret = value_replace(vv, v, TRUE);
}
} else {
named_value_t* nv = named_value_create_ex(name, v);

View File

@ -192,8 +192,7 @@ static ret_t value_deep_copy_keep_type(value_t* dst, const value_t* src) {
}
default: {
if (dst->type == src->type) {
value_reset(dst);
value_deep_copy(dst, src);
value_replace(dst, src, TRUE);
} else {
ret = RET_FAIL;
log_debug("not support type:%d\n", dst->type);
@ -225,8 +224,7 @@ static ret_t object_hash_set_prop(tk_object_t* obj, const char* name, const valu
if (o->keep_prop_type) {
ret = value_deep_copy_keep_type(vv, v);
} else {
value_reset(vv);
ret = value_deep_copy(vv, v);
ret = value_replace(vv, v, TRUE);
}
} else {
named_value_hash_t* nvh = named_value_hash_create_ex(NULL, v);

View File

@ -525,6 +525,66 @@ ret_t value_deep_copy(value_t* dst, const value_t* src) {
return RET_OK;
}
static bool_t value_mem_equal(const value_t* v, const value_t* other) {
return_value_if_fail(v != NULL && other != NULL, FALSE);
if (v == other) {
return TRUE;
}
if (v->type != other->type) {
return FALSE;
}
switch (v->type) {
case VALUE_TYPE_SIZED_STRING:
return v->value.sized_str.str == other->value.sized_str.str;
case VALUE_TYPE_BINARY:
case VALUE_TYPE_UBJSON:
case VALUE_TYPE_GRADIENT:
return v->value.binary_data.data == other->value.binary_data.data;
case VALUE_TYPE_STRING:
return v->value.str == other->value.str;
case VALUE_TYPE_WSTRING:
return v->value.wstr == other->value.wstr;
case VALUE_TYPE_OBJECT:
return v->value.object == other->value.object;
case VALUE_TYPE_ID:
return v->value.id.id == other->value.id.id;
case VALUE_TYPE_FUNC:
return v->value.func.func == other->value.func.func;
case VALUE_TYPE_POINTER_REF:
return v->value.ptr_ref == other->value.ptr_ref;
default:
return FALSE;
}
}
ret_t value_replace(value_t* dst, const value_t* src, bool_t deep_copy) {
return_value_if_fail(dst != NULL && src != NULL, RET_BAD_PARAMS);
if (value_mem_equal(dst, src)) {
if (dst->free_handle && !src->free_handle) {
if (deep_copy) {
value_copy(dst, src);
dst->free_handle = TRUE;
return RET_OK;
} else {
log_error(
"%s: dst(%p) and src(%p) have the same value pointer, "
"but dst has free handle while src doesn't, and deep copy isn't enabled."
"Replacing them would cause memory leak!\n",
__FUNCTION__, dst, src);
return RET_FAIL;
}
}
} else {
value_reset(dst);
}
return deep_copy ? value_deep_copy(dst, src) : value_copy(dst, src);
}
bool_t value_is_null(value_t* v) {
return v == NULL || v->type == VALUE_TYPE_INVALID;
}

View File

@ -816,6 +816,17 @@ ret_t value_copy(value_t* dst, const value_t* src);
*/
ret_t value_deep_copy(value_t* dst, const value_t* src);
/**
* @method value_replace
* value的值
* @param {value_t*} dst value对象
* @param {const value_t*} src value对象
* @param {bool_t} deep_copy
*
* @return {ret_t} RET_OK表示成功
*/
ret_t value_replace(value_t* dst, const value_t* src, bool_t deep_copy);
/**
* @method value_create
* @annotation ["constructor", "scriptable", "gc"]

View File

@ -320,6 +320,30 @@ TEST(ValueTest, copy_str) {
value_reset(&other);
}
TEST(ValueTest, replace) {
value_t v;
value_t other;
value_dup_str(&v, "hello");
value_dup_str(&other, "awtk");
ASSERT_EQ(value_replace(&v, &other, FALSE), RET_OK);
ASSERT_STREQ(value_str(&v), "awtk");
ASSERT_EQ(v.free_handle, FALSE);
ASSERT_NE(value_replace(&other, &v, FALSE), RET_OK);
ASSERT_EQ(value_replace(&other, &v, TRUE), RET_OK);
ASSERT_EQ(value_replace(&v, &other, TRUE), RET_OK);
ASSERT_STREQ(value_str(&v), "awtk");
ASSERT_EQ(v.free_handle, TRUE);
ASSERT_EQ(value_replace(&v, &other, TRUE), RET_OK);
value_reset(&v);
value_reset(&other);
}
TEST(ValueTest, ubjson) {
value_t v;
const char* str = "str";