mirror of
https://github.com/zlgopen/awtk.git
synced 2025-05-08 11:33:48 +08:00
add value_replace
This commit is contained in:
parent
293492c1b4
commit
a6a06a3380
@ -1,5 +1,8 @@
|
||||
# 最新动态
|
||||
|
||||
2025/04/27
|
||||
* 增加value_replace,用于避免value\ data的内存地址相同导致先reset后deep_copy出现野指针的问题(感谢兆坤提供补丁)。
|
||||
|
||||
2025/04/25
|
||||
* object有属性删除时发送EVT_PROPS_CHANGED事件(感谢兆坤提供补丁)。
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"]
|
||||
|
@ -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";
|
||||
|
Loading…
x
Reference in New Issue
Block a user