From cb5cd61d99f44e6a95105dbbf32d65143d8f3286 Mon Sep 17 00:00:00 2001 From: lixianjing Date: Thu, 19 Sep 2019 14:11:22 +0800 Subject: [PATCH] add object_get_prop_by_path --- docs/changes.md | 2 + src/tkc/object.c | 49 ++++++++++++++++++++- src/tkc/object.h | 12 ++++++ src/tkc/object_array.c | 5 ++- tests/object_array_test.cc | 49 ++++++++++++++++++++- tests/object_default_test.cc | 83 ++++++++++++++++++++++++++++++------ 6 files changed, 181 insertions(+), 19 deletions(-) diff --git a/docs/changes.md b/docs/changes.md index e5e67f359..879606850 100644 --- a/docs/changes.md +++ b/docs/changes.md @@ -2,6 +2,8 @@ * 2019/09/19 * 修改"color\_component" "digit\_clock" "mutable\_image"的注释,支持designer编辑(感谢大恒提供补丁)。 + * 增加object\_array + * 增加object\_get\_prop\_by\_path * 2019/09/18 * 增加iostream\_mem。 diff --git a/src/tkc/object.c b/src/tkc/object.c index 2766453cd..ad86706b4 100644 --- a/src/tkc/object.c +++ b/src/tkc/object.c @@ -90,10 +90,10 @@ object_t* object_ref(object_t* obj) { return obj; } -ret_t object_get_prop(object_t* obj, const char* name, value_t* v) { +static ret_t object_get_prop_by_name(object_t* obj, const char* name, value_t* v) { ret_t ret = RET_NOT_FOUND; + return_value_if_fail(obj != NULL && obj->vt != NULL, RET_BAD_PARAMS); return_value_if_fail(name != NULL && v != NULL, RET_BAD_PARAMS); - return_value_if_fail(obj != NULL && obj->vt != NULL && obj->ref_count >= 0, RET_BAD_PARAMS); value_set_int(v, 0); if (obj->vt->get_prop != NULL) { @@ -103,6 +103,51 @@ ret_t object_get_prop(object_t* obj, const char* name, value_t* v) { return ret; } +ret_t object_get_prop_by_path(object_t* obj, const char* name, value_t* v) { + char* p = NULL; + uint32_t len = 0; + char path[MAX_PATH + 1]; + ret_t ret = RET_NOT_FOUND; + return_value_if_fail(obj != NULL && obj->vt != NULL, RET_BAD_PARAMS); + return_value_if_fail(name != NULL && v != NULL, RET_BAD_PARAMS); + + len = strlen(name); + return_value_if_fail(len <= MAX_PATH, RET_BAD_PARAMS); + + memcpy(path, name, len + 1); + + name = path; + do { + p = strchr(name, '.'); + if (p != NULL) { + *p = '\0'; + } + + if (object_get_prop_by_name(obj, name, v) != RET_OK) { + break; + } + + if (p == NULL) { + ret = RET_OK; + break; + } + + if (v->type == VALUE_TYPE_OBJECT) { + obj = value_object(v); + } else { + break; + } + + name = p + 1; + } while (p != NULL); + + return ret; +} + +ret_t object_get_prop(object_t* obj, const char* name, value_t* v) { + return object_get_prop_by_name(obj, name, v); +} + const char* object_get_prop_str(object_t* obj, const char* name) { value_t v; if (object_get_prop(obj, name, &v) == RET_OK) { diff --git a/src/tkc/object.h b/src/tkc/object.h index ba11532c7..b4bafb9f2 100644 --- a/src/tkc/object.h +++ b/src/tkc/object.h @@ -465,6 +465,18 @@ ret_t object_exec(object_t* obj, const char* name, const char* args); */ ret_t object_notify_changed(object_t* obj); +/** + * @method object_get_prop_by_path + * 获取指定path属性的值。 + * + * @param {object_t*} obj object对象。 + * @param {const char*} path 属性的path,各级之间用.分隔。 + * @param {value_t*} v 返回属性的值。 + * + * @return {ret_t} 返回RET_OK表示成功,否则表示失败。 + */ +ret_t object_get_prop_by_path(object_t* obj, const char* path, value_t* v); + #define OBJECT(obj) ((object_t*)(obj)) END_C_DECLS diff --git a/src/tkc/object_array.c b/src/tkc/object_array.c index 3800de21e..a820217b0 100644 --- a/src/tkc/object_array.c +++ b/src/tkc/object_array.c @@ -112,6 +112,7 @@ static ret_t object_array_remove_prop(object_t* obj, const char* name) { ret_t ret = RET_NOT_FOUND; int32_t index = tk_atoi(name); object_array_t* o = OBJECT_ARRAY(obj); + return_value_if_fail(isdigit(*name), RET_NOT_FOUND); if (index >= 0 && index < o->props_size) { value_t* iter = o->props + index; @@ -129,7 +130,7 @@ static ret_t object_array_set_prop(object_t* obj, const char* name, const value_ int32_t index = tk_atoi(name); return_value_if_fail(object_array_extend(obj) == RET_OK, RET_OOM); - if (index >= 0 && index < o->props_size) { + if (isdigit(*name) && index >= 0 && index < o->props_size) { value_t* iter = o->props + index; value_reset(iter); ret = value_deep_copy(iter, v); @@ -149,7 +150,7 @@ static ret_t object_array_get_prop(object_t* obj, const char* name, value_t* v) if (tk_str_eq(name, "length") || tk_str_eq(name, "size")) { value_set_int(v, o->props_size); ret = RET_OK; - } else { + } else if (isdigit(*name)) { int32_t index = tk_atoi(name); if (index >= 0 && index < o->props_size) { value_t* iter = o->props + index; diff --git a/tests/object_array_test.cc b/tests/object_array_test.cc index 3a33bc36d..9491a093c 100644 --- a/tests/object_array_test.cc +++ b/tests/object_array_test.cc @@ -1,4 +1,5 @@ #include "tkc/utils.h" +#include "tkc/object_default.h" #include "tkc/object_array.h" #include "gtest/gtest.h" #include @@ -126,7 +127,7 @@ TEST(ObjectArray, dup) { ASSERT_EQ(object_set_prop(obj, "-1", value_set_int(&v, 3)), RET_OK); dup = object_array_clone(OBJECT_ARRAY(obj)); - + log = ""; object_foreach_prop(dup, visit_dump, &log); ASSERT_EQ(log, "0123"); @@ -135,3 +136,49 @@ TEST(ObjectArray, dup) { object_unref(dup); } +TEST(ObjectArray, path) { + value_t v; + object_t* clone = NULL; + object_t* root = object_default_create(); + object_t* obja = object_array_create(); + object_t* obja1 = object_default_create(); + object_t* obja2 = object_default_create(); + object_t* objb = object_array_create(); + object_t* objb1 = object_default_create(); + object_t* objb2 = object_default_create(); + + ASSERT_EQ(object_set_prop_object(root, "a", obja), RET_OK); + ASSERT_EQ(object_set_prop_object(root, "b", objb), RET_OK); + + ASSERT_EQ(object_set_prop_object(obja, "-1", obja1), RET_OK); + ASSERT_EQ(object_set_prop_int(obja1, "value", 456), RET_OK); + ASSERT_EQ(object_get_prop_by_path(root, "a.0.value", &v), RET_OK); + ASSERT_EQ(value_int(&v), 456); + + ASSERT_EQ(object_set_prop_object(obja, "-1", obja2), RET_OK); + ASSERT_EQ(object_set_prop_int(obja2, "value", 56), RET_OK); + ASSERT_EQ(object_get_prop_by_path(root, "a.1.value", &v), RET_OK); + ASSERT_EQ(value_int(&v), 56); + + ASSERT_EQ(object_set_prop_object(objb, "-1", objb1), RET_OK); + ASSERT_EQ(object_set_prop_int(objb1, "value", 56), RET_OK); + ASSERT_EQ(object_get_prop_by_path(root, "b.0.value", &v), RET_OK); + ASSERT_EQ(value_int(&v), 56); + + ASSERT_EQ(object_set_prop_object(objb, "-1", objb2), RET_OK); + ASSERT_EQ(object_set_prop_int(objb2, "value", 156), RET_OK); + ASSERT_EQ(object_get_prop_by_path(root, "b.1.value", &v), RET_OK); + ASSERT_EQ(value_int(&v), 156); + + ASSERT_NE(object_get_prop_by_path(root, "a.a.value", &v), RET_OK); + ASSERT_NE(object_get_prop_by_path(root, "b.a.value", &v), RET_OK); + ASSERT_NE(object_get_prop_by_path(root, "c.value", &v), RET_OK); + + object_unref(root); + object_unref(obja); + object_unref(obja1); + object_unref(obja2); + object_unref(objb); + object_unref(objb1); + object_unref(objb2); +} diff --git a/tests/object_default_test.cc b/tests/object_default_test.cc index 5f2309192..67c5bc8e2 100644 --- a/tests/object_default_test.cc +++ b/tests/object_default_test.cc @@ -29,7 +29,7 @@ static ret_t visit_dump(void* ctx, const void* data) { return RET_OK; } -TEST(ObejectDefault, events) { +TEST(ObjectDefault, events) { value_t v; string log; object_t* obj = object_default_create(); @@ -47,7 +47,7 @@ TEST(ObejectDefault, events) { ASSERT_EQ(log, "6:6:8:8:destroy:"); } -TEST(ObejectDefault, basic) { +TEST(ObjectDefault, basic) { value_t v; string log; object_t* obj = object_default_create(); @@ -189,7 +189,7 @@ static ret_t visit_test_busy(void* ctx, const void* data) { return RET_OK; } -TEST(ObejectDefault, visis_remove) { +TEST(ObjectDefault, visis_remove) { value_t v; string log; object_t* obj = object_default_create(); @@ -226,7 +226,7 @@ TEST(ObejectDefault, visis_remove) { object_unref(obj); } -TEST(ObejectDefault, random) { +TEST(ObjectDefault, random) { value_t v; string log; char name[32]; @@ -248,7 +248,7 @@ TEST(ObejectDefault, random) { object_unref(obj); } -TEST(ObejectDefault, set_name) { +TEST(ObjectDefault, set_name) { object_t* obj = object_default_create(); object_set_name(obj, "abc"); @@ -260,7 +260,7 @@ TEST(ObejectDefault, set_name) { object_unref(obj); } -TEST(ObejectDefault, set_prop_int) { +TEST(ObjectDefault, set_prop_int) { object_t* obj = object_default_create(); ASSERT_EQ(object_set_prop_int(obj, "int", 123), RET_OK); @@ -269,7 +269,7 @@ TEST(ObejectDefault, set_prop_int) { object_unref(obj); } -TEST(ObejectDefault, set_prop_float) { +TEST(ObjectDefault, set_prop_float) { object_t* obj = object_default_create(); ASSERT_EQ(object_set_prop_float(obj, "float", 123), RET_OK); @@ -278,7 +278,7 @@ TEST(ObejectDefault, set_prop_float) { object_unref(obj); } -TEST(ObejectDefault, copy_prop) { +TEST(ObjectDefault, copy_prop) { object_t* src = object_default_create(); object_t* obj = object_default_create(); @@ -294,7 +294,7 @@ TEST(ObejectDefault, copy_prop) { object_unref(obj); } -TEST(ObejectDefault, set_prop_str) { +TEST(ObjectDefault, set_prop_str) { object_t* obj = object_default_create(); ASSERT_EQ(object_set_prop_str(obj, "str", "123"), RET_OK); @@ -303,7 +303,7 @@ TEST(ObejectDefault, set_prop_str) { object_unref(obj); } -TEST(ObejectDefault, exec) { +TEST(ObjectDefault, exec) { object_t* obj = object_default_create(); ASSERT_EQ(object_can_exec(obj, "test", "123"), FALSE); @@ -312,7 +312,7 @@ TEST(ObejectDefault, exec) { object_unref(obj); } -TEST(ObejectDefault, has_prop) { +TEST(ObjectDefault, has_prop) { object_t* obj = object_default_create(); ASSERT_EQ(object_set_prop_float(obj, "a", 123), RET_OK); @@ -322,7 +322,7 @@ TEST(ObejectDefault, has_prop) { object_unref(obj); } -TEST(ObejectDefault, expr_number) { +TEST(ObjectDefault, expr_number) { value_t v; object_t* obj = object_default_create(); @@ -337,7 +337,7 @@ TEST(ObejectDefault, expr_number) { object_unref(obj); } -TEST(ObejectDefault, expr_str) { +TEST(ObjectDefault, expr_str) { value_t v; object_t* obj = object_default_create(); @@ -350,7 +350,7 @@ TEST(ObejectDefault, expr_str) { object_unref(obj); } -TEST(ObejectDefault, clone) { +TEST(ObjectDefault, clone) { value_t v; object_t* clone = NULL; object_t* obj = object_default_create(); @@ -366,3 +366,58 @@ TEST(ObejectDefault, clone) { object_unref(obj); object_unref(clone); } + +TEST(ObjectDefault, path) { + value_t v; + object_t* clone = NULL; + object_t* root = object_default_create(); + object_t* obja = object_default_create(); + object_t* obja1 = object_default_create(); + object_t* obja2 = object_default_create(); + object_t* objb = object_default_create(); + object_t* objb1 = object_default_create(); + object_t* objb2 = object_default_create(); + + ASSERT_EQ(object_set_prop_object(root, "a", obja), RET_OK); + ASSERT_EQ(object_set_prop_object(root, "b", objb), RET_OK); + + ASSERT_EQ(object_set_prop_int(obja, "value", 123), RET_OK); + ASSERT_EQ(object_get_prop_by_path(root, "a.value", &v), RET_OK); + ASSERT_EQ(value_int(&v), 123); + + ASSERT_EQ(object_set_prop_int(objb, "value", 123), RET_OK); + ASSERT_EQ(object_get_prop_by_path(root, "b.value", &v), RET_OK); + ASSERT_EQ(value_int(&v), 123); + + ASSERT_EQ(object_set_prop_object(obja, "1", obja1), RET_OK); + ASSERT_EQ(object_set_prop_int(obja1, "value", 456), RET_OK); + ASSERT_EQ(object_get_prop_by_path(root, "a.1.value", &v), RET_OK); + ASSERT_EQ(value_int(&v), 456); + + ASSERT_EQ(object_set_prop_object(obja, "2", obja2), RET_OK); + ASSERT_EQ(object_set_prop_int(obja2, "value", 56), RET_OK); + ASSERT_EQ(object_get_prop_by_path(root, "a.2.value", &v), RET_OK); + ASSERT_EQ(value_int(&v), 56); + + ASSERT_EQ(object_set_prop_object(objb, "1", objb1), RET_OK); + ASSERT_EQ(object_set_prop_int(objb1, "value", 56), RET_OK); + ASSERT_EQ(object_get_prop_by_path(root, "b.1.value", &v), RET_OK); + ASSERT_EQ(value_int(&v), 56); + + ASSERT_EQ(object_set_prop_object(objb, "2", objb2), RET_OK); + ASSERT_EQ(object_set_prop_int(objb2, "value", 156), RET_OK); + ASSERT_EQ(object_get_prop_by_path(root, "b.2.value", &v), RET_OK); + ASSERT_EQ(value_int(&v), 156); + + ASSERT_NE(object_get_prop_by_path(root, "a.a.value", &v), RET_OK); + ASSERT_NE(object_get_prop_by_path(root, "b.a.value", &v), RET_OK); + ASSERT_NE(object_get_prop_by_path(root, "c.value", &v), RET_OK); + + object_unref(root); + object_unref(obja); + object_unref(obja1); + object_unref(obja2); + object_unref(objb); + object_unref(objb1); + object_unref(objb2); +}