From f8dfd03f9e92a84ef83d68d40e2a47bfa5f6934e Mon Sep 17 00:00:00 2001 From: lixianjing Date: Fri, 14 Feb 2025 17:44:55 +0800 Subject: [PATCH] improve ubjson --- docs/changes.md | 1 + src/ubjson/ubjson_const.h | 6 +- src/ubjson/ubjson_parser.c | 85 +++++++++++++++++++++++- src/ubjson/ubjson_reader.c | 85 ++++++++++++++++++++++++ src/ubjson/ubjson_reader.h | 1 + src/ubjson/ubjson_writer.c | 124 +++++++++++++++++++++++++++++++++--- src/ubjson/ubjson_writer.h | 85 ++++++++++++++++++++++++ tests/ubjson_parser_test.cc | 96 ++++++++++++++++++++++++++++ tests/ubjson_reader_test.cc | 89 +++++++++++++++++++++++++- tests/ubjson_writer_test.cc | 83 ++++++++++++++++++++++++ 10 files changed, 641 insertions(+), 14 deletions(-) diff --git a/docs/changes.md b/docs/changes.md index 9529ee3b9..5a6dd19a7 100644 --- a/docs/changes.md +++ b/docs/changes.md @@ -2,6 +2,7 @@ 2025/02/14 * endian类增加了小端的支持和修改了注释(增加测试用例)(感谢智明提供补丁) + * 实现了 ubjson 规范中的使用类型和计数进行数组优化(感谢林福提供补丁) 2025/02/13 * 更新1m资源(感谢泽武提供补丁) diff --git a/src/ubjson/ubjson_const.h b/src/ubjson/ubjson_const.h index c015f568f..fbf9ebbef 100644 --- a/src/ubjson/ubjson_const.h +++ b/src/ubjson/ubjson_const.h @@ -48,7 +48,11 @@ typedef enum _ubjson_marker_t { UBJSON_MARKER_ARRAY_BEGIN = '[', UBJSON_MARKER_ARRAY_END = ']', UBJSON_MARKER_OBJECT_BEGIN = '{', - UBJSON_MARKER_OBJECT_END = '}' + UBJSON_MARKER_OBJECT_END = '}', + + /* container optimized format */ + UBJSON_MARKER_CONTAINER_TYPE = '&', + UBJSON_MARKER_CONTAINER_COUNT = '#', } ubjson_marker_t; END_C_DECLS diff --git a/src/ubjson/ubjson_parser.c b/src/ubjson/ubjson_parser.c index 2aa9e4751..c7cbb9caf 100644 --- a/src/ubjson/ubjson_parser.c +++ b/src/ubjson/ubjson_parser.c @@ -39,6 +39,8 @@ typedef struct _ubjson_parser_t { bool_t error; uint32_t level; tk_object_t* stack[MAX_LEVEL + 1]; + + uint32_t optimized_type; } ubjson_parser_t; static ret_t ubjson_do_parse_object(ubjson_parser_t* parser); @@ -123,6 +125,65 @@ static ret_t ubjson_parser_read(ubjson_parser_t* parser, value_t* v) { return ubjson_reader_read(reader, v); } +static ret_t ubjson_on_optimized_array_object(ubjson_parser_t* parser, const char* key, + value_t* v) { + ret_t ret = RET_OK; + uint32_t type = parser->optimized_type; + parser->optimized_type = 0; + + if (type == UBJSON_MARKER_UINT8) { + uint8_t* p = v->value.binary_data.data; + for (uint32_t i = 0; i < v->value.binary_data.size; i++) { + ret = tk_object_set_prop_uint8(parser->obj, key, p[i]); + return_value_if_fail(ret == RET_OK, ret); + } + } else if (type == UBJSON_MARKER_INT8) { + int8_t* p = v->value.binary_data.data; + for (uint32_t i = 0; i < v->value.binary_data.size; i++) { + ret = tk_object_set_prop_int8(parser->obj, key, p[i]); + return_value_if_fail(ret == RET_OK, ret); + } + } else if (type == UBJSON_MARKER_INT16) { + int16_t* p = v->value.binary_data.data; + uint32_t count = v->value.binary_data.size / sizeof(int16_t); + for (uint32_t i = 0; i < count; i++) { + ret = tk_object_set_prop_int16(parser->obj, key, p[i]); + return_value_if_fail(ret == RET_OK, ret); + } + } else if (type == UBJSON_MARKER_INT32) { + int32_t* p = v->value.binary_data.data; + uint32_t count = v->value.binary_data.size / sizeof(int32_t); + for (uint32_t i = 0; i < count; i++) { + ret = tk_object_set_prop_int32(parser->obj, key, p[i]); + return_value_if_fail(ret == RET_OK, ret); + } + } else if (type == UBJSON_MARKER_INT64) { + int64_t* p = v->value.binary_data.data; + uint32_t count = v->value.binary_data.size / sizeof(int64_t); + for (uint32_t i = 0; i < count; i++) { + ret = tk_object_set_prop_int64(parser->obj, key, p[i]); + return_value_if_fail(ret == RET_OK, ret); + } + } else if (type == UBJSON_MARKER_FLOAT32) { + float* p = v->value.binary_data.data; + uint32_t count = v->value.binary_data.size / sizeof(float); + for (uint32_t i = 0; i < count; i++) { + ret = tk_object_set_prop_float(parser->obj, key, p[i]); + return_value_if_fail(ret == RET_OK, ret); + } + } else if (type == UBJSON_MARKER_FLOAT64) { + double* p = v->value.binary_data.data; + uint32_t count = v->value.binary_data.size / sizeof(double); + for (uint32_t i = 0; i < count; i++) { + ret = tk_object_set_prop_double(parser->obj, key, p[i]); + return_value_if_fail(ret == RET_OK, ret); + } + } else { + return_value_if_fail(!"not support!", RET_FAIL); + } + return ret; +} + static ret_t ubjson_on_key_value_object(void* ctx, const char* key, value_t* v) { ret_t ret = RET_OK; ubjson_parser_t* parser = (ubjson_parser_t*)ctx; @@ -134,6 +195,7 @@ static ret_t ubjson_on_key_value_object(void* ctx, const char* key, value_t* v) if (v->type == VALUE_TYPE_TOKEN) { uint32_t token = value_token(v); + if (token == UBJSON_MARKER_OBJECT_BEGIN || token == UBJSON_MARKER_ARRAY_BEGIN) { tk_object_t* obj = token == UBJSON_MARKER_OBJECT_BEGIN ? object_default_create() : object_array_create(); @@ -152,12 +214,26 @@ static ret_t ubjson_on_key_value_object(void* ctx, const char* key, value_t* v) tk_object_unref(obj); } else if (token == UBJSON_MARKER_OBJECT_END || token == UBJSON_MARKER_ARRAY_END) { ret = ubjson_parser_pop(parser); + + } else if (token == UBJSON_MARKER_UINT8 || token == UBJSON_MARKER_INT8 || + token == UBJSON_MARKER_INT16 || token == UBJSON_MARKER_INT32 || + token == UBJSON_MARKER_INT64 || token == UBJSON_MARKER_FLOAT32 || + token == UBJSON_MARKER_FLOAT64) { + parser->optimized_type = token; } else { assert(!"not supported"); ret = RET_NOT_IMPL; } } else { - ret = tk_object_set_prop(parser->obj, key, v); + if (parser->optimized_type != 0) { + return_value_if_fail(v->type == VALUE_TYPE_BINARY, RET_FAIL); + + ubjson_on_optimized_array_object(parser, key, v); + ret = ubjson_parser_pop(parser); + + } else { + ret = tk_object_set_prop(parser->obj, key, v); + } } return ret; @@ -248,8 +324,11 @@ static ret_t ubjson_do_parse_array(ubjson_parser_t* parser) { ubjson_do_parse_array(parser); continue; } else { - assert(!"invalid format"); - return RET_BAD_PARAMS; + ubjson_parser_on_key_value(parser, NULL, v); /* 上报优化数组的类型 */ + + return_value_if_fail(ubjson_parser_read(parser, &value) == RET_OK, RET_FAIL); + ubjson_parser_on_key_value(parser, NULL, v); + return RET_OK; } } diff --git a/src/ubjson/ubjson_reader.c b/src/ubjson/ubjson_reader.c index 3059855f5..6afc72ae5 100644 --- a/src/ubjson/ubjson_reader.c +++ b/src/ubjson/ubjson_reader.c @@ -57,11 +57,78 @@ static bool_t is_binary(const char* str, uint32_t len) { return FALSE; } +static ret_t ubjson_reader_read_optimized_array(ubjson_reader_t* reader, uint8_t type, int count, + value_t* v) { + return_value_if_fail(reader != NULL && reader->read != NULL && v != NULL, RET_BAD_PARAMS); + + ret_t ret = RET_OK; + value_t vlen; + int len = 0; + str_t* str = &(reader->str); + + if (type == UBJSON_MARKER_UINT8 || type == UBJSON_MARKER_INT8) { + len = count; + } else if (type == UBJSON_MARKER_INT16) { + len = count * sizeof(int16_t); + } else if (type == UBJSON_MARKER_INT32) { + len = count * sizeof(int32_t); + } else if (type == UBJSON_MARKER_INT64) { + len = count * sizeof(int64_t); + } else if (type == UBJSON_MARKER_FLOAT32) { + len = count * sizeof(float); + } else if (type == UBJSON_MARKER_FLOAT64) { + len = count * sizeof(double); + } + + return_value_if_fail(str_extend(str, len + 1) == RET_OK, RET_OOM); + return_value_if_fail(ubjson_reader_read_data(reader, str->str, len) == RET_OK, RET_FAIL); + + str->size = len; + str->str[len] = '\0'; + + if (type == UBJSON_MARKER_INT16) { + int16_t* p = (int16_t*)str->str; + for (int i = 0; i < count; i++) { + int16_t vp = uint16_from_big_endian(p[i]); + p[i] = vp; + } + + } else if (type == UBJSON_MARKER_INT32) { + int32_t* p = (int32_t*)str->str; + for (int i = 0; i < count; i++) { + int32_t vp = int32_from_big_endian(p[i]); + p[i] = vp; + } + } else if (type == UBJSON_MARKER_INT64) { + int64_t* p = (int64_t*)str->str; + for (int i = 0; i < count; i++) { + int64_t vp = int64_from_big_endian(p[i]); + p[i] = vp; + } + } else if (type == UBJSON_MARKER_FLOAT32) { + float* p = (float*)str->str; + for (int i = 0; i < count; i++) { + float vp = float_from_big_endian(p[i]); + p[i] = vp; + } + } else if (type == UBJSON_MARKER_FLOAT64) { + double* p = (double*)str->str; + for (int i = 0; i < count; i++) { + double vp = double_from_big_endian(p[i]); + p[i] = vp; + } + } + + value_set_binary_data(v, str->str, len); + + return RET_OK; +} ret_t ubjson_reader_read(ubjson_reader_t* reader, value_t* v) { ret_t ret = RET_OK; uint8_t marker = 0; return_value_if_fail(reader != NULL && reader->read != NULL && v != NULL, RET_BAD_PARAMS); + ret = ubjson_reader_read_data(reader, &marker, 1); if (ret != RET_OK) { @@ -219,6 +286,24 @@ ret_t ubjson_reader_read(ubjson_reader_t* reader, value_t* v) { value_set_token(v, UBJSON_MARKER_OBJECT_END); break; } + case UBJSON_MARKER_CONTAINER_TYPE: { + ret = ubjson_reader_read_data(reader, &marker, 1); + return_value_if_fail(ret == RET_OK, RET_FAIL); + value_set_token(v, marker); + + reader->optimized_type = marker; + break; + } + case UBJSON_MARKER_CONTAINER_COUNT: { + value_t vlen; + ret = ubjson_reader_read(reader, &vlen); + return_value_if_fail(ret == RET_OK, RET_FAIL); + + ret = ubjson_reader_read_optimized_array(reader, reader->optimized_type, value_int(&vlen), v); + reader->optimized_type = 0; + + break; + } default: { ret = RET_FAIL; break; diff --git a/src/ubjson/ubjson_reader.h b/src/ubjson/ubjson_reader.h index 6afb2cf0d..25bc6b05f 100644 --- a/src/ubjson/ubjson_reader.h +++ b/src/ubjson/ubjson_reader.h @@ -38,6 +38,7 @@ struct _ubjson_reader_t { str_t str; wstr_t wstr; ubjson_read_callback_t read; + uint8_t optimized_type; }; ubjson_reader_t* ubjson_reader_init(ubjson_reader_t* reader, ubjson_read_callback_t read, diff --git a/src/ubjson/ubjson_writer.c b/src/ubjson/ubjson_writer.c index 8b50264da..3cea7e6ce 100644 --- a/src/ubjson/ubjson_writer.c +++ b/src/ubjson/ubjson_writer.c @@ -45,18 +45,23 @@ static ret_t ubjson_writer_write_marker(ubjson_writer_t* writer, uint8_t marker) return ubjson_writer_write_data(writer, &marker, 1); } +static ret_t ubjson_writer_write_length(ubjson_writer_t* writer, uint32_t len) { + ret_t ret = RET_BAD_PARAMS; + if (len <= INT8_MAX) { + ret = ubjson_writer_write_int8(writer, (int8_t)len); + } else if (len <= INT16_MAX) { + ret = ubjson_writer_write_int16(writer, (int16_t)len); + } else if (len <= INT_MAX) { + ret = ubjson_writer_write_int32(writer, (int32_t)len); + } + + return ret; +} + static ret_t ubjson_writer_write_key_len(ubjson_writer_t* writer, const char* value, uint32_t len) { return_value_if_fail(writer != NULL && value != NULL, RET_BAD_PARAMS); - if (len <= INT8_MAX) { - ubjson_writer_write_int8(writer, (int8_t)len); - } else if (len <= INT16_MAX) { - ubjson_writer_write_int16(writer, (int16_t)len); - } else if (len <= INT_MAX) { - ubjson_writer_write_int32(writer, (int32_t)len); - } else { - return RET_BAD_PARAMS; - } + return_value_if_fail(ubjson_writer_write_length(writer, len) == RET_OK, RET_OOM); return_value_if_fail(ubjson_writer_write_data(writer, value, len) == RET_OK, RET_OOM); @@ -496,3 +501,104 @@ ret_t ubjson_writer_write_object_end(ubjson_writer_t* writer) { return RET_OK; } + +static ret_t ubjson_writer_write_optimized_array(ubjson_writer_t* writer, char type, uint32_t count, + void* array) { + ret_t ret; + return_value_if_fail(writer != NULL && array != NULL && count > 0, RET_BAD_PARAMS); + + return_value_if_fail(ubjson_writer_write_marker(writer, UBJSON_MARKER_ARRAY_BEGIN) == RET_OK, + RET_OOM); + return_value_if_fail(ubjson_writer_write_marker(writer, UBJSON_MARKER_CONTAINER_TYPE) == RET_OK, + RET_OOM); + return_value_if_fail(ubjson_writer_write_marker(writer, type) == RET_OK, RET_OOM); + return_value_if_fail(ubjson_writer_write_marker(writer, UBJSON_MARKER_CONTAINER_COUNT) == RET_OK, + RET_OOM); + + return_value_if_fail(ubjson_writer_write_length(writer, count) == RET_OK, RET_OOM); + + if (type == UBJSON_MARKER_INT8 || type == UBJSON_MARKER_UINT8) { + ret = ubjson_writer_write_data(writer, array, count); + return_value_if_fail(ret == RET_OK, RET_OOM); + + } else if (type == UBJSON_MARKER_INT16) { + int16_t* p = (int16_t*)array; + + for (uint32_t i = 0; i < count; i++) { + int16_t val = p[i]; + val = int16_to_big_endian(val); + ret = ubjson_writer_write_data(writer, &val, sizeof(val)); + return_value_if_fail(ret == RET_OK, RET_OOM); + } + + } else if (type == UBJSON_MARKER_INT32) { + int32_t* p = (int32_t*)array; + + for (uint32_t i = 0; i < count; i++) { + int32_t val = p[i]; + val = int32_to_big_endian(val); + ret = ubjson_writer_write_data(writer, &val, sizeof(val)); + return_value_if_fail(ret == RET_OK, RET_OOM); + } + + } else if (type == UBJSON_MARKER_INT64) { + int64_t* p = (int64_t*)array; + + for (uint32_t i = 0; i < count; i++) { + int64_t val = p[i]; + val = int64_to_big_endian(val); + ret = ubjson_writer_write_data(writer, &val, sizeof(val)); + return_value_if_fail(ret == RET_OK, RET_OOM); + } + + } else if (type == UBJSON_MARKER_FLOAT32) { + float* p = (float*)array; + + for (uint32_t i = 0; i < count; i++) { + float val = p[i]; + val = float_to_big_endian(val); + ret = ubjson_writer_write_data(writer, &val, sizeof(val)); + return_value_if_fail(ret == RET_OK, RET_OOM); + } + } else if (type == UBJSON_MARKER_FLOAT64) { + double* p = (double*)array; + + for (uint32_t i = 0; i < count; i++) { + double val = p[i]; + val = double_to_big_endian(val); + ret = ubjson_writer_write_data(writer, &val, sizeof(val)); + return_value_if_fail(ret == RET_OK, RET_OOM); + } + } + + /* 优化数组,没有结束标记 */ + + return RET_OK; +} + +ret_t ubjson_writer_write_array_uint8(ubjson_writer_t* writer, uint8_t* data, uint32_t count) { + return ubjson_writer_write_optimized_array(writer, UBJSON_MARKER_UINT8, count, data); +} + +ret_t ubjson_writer_write_array_int8(ubjson_writer_t* writer, int8_t* data, uint32_t count) { + return ubjson_writer_write_optimized_array(writer, UBJSON_MARKER_INT8, count, data); +} + +ret_t ubjson_writer_write_array_int16(ubjson_writer_t* writer, int16_t* data, uint32_t count) { + return ubjson_writer_write_optimized_array(writer, UBJSON_MARKER_INT16, count, data); +} + +ret_t ubjson_writer_write_array_int32(ubjson_writer_t* writer, int32_t* data, uint32_t count) { + return ubjson_writer_write_optimized_array(writer, UBJSON_MARKER_INT32, count, data); +} + +ret_t ubjson_writer_write_array_int64(ubjson_writer_t* writer, int64_t* data, uint32_t count) { + return ubjson_writer_write_optimized_array(writer, UBJSON_MARKER_INT64, count, data); +} +ret_t ubjson_writer_write_array_float32(ubjson_writer_t* writer, float* data, uint32_t count) { + return ubjson_writer_write_optimized_array(writer, UBJSON_MARKER_FLOAT32, count, data); +} + +ret_t ubjson_writer_write_array_float64(ubjson_writer_t* writer, double* data, uint32_t count) { + return ubjson_writer_write_optimized_array(writer, UBJSON_MARKER_FLOAT64, count, data); +} \ No newline at end of file diff --git a/src/ubjson/ubjson_writer.h b/src/ubjson/ubjson_writer.h index e0d250885..61beda89b 100644 --- a/src/ubjson/ubjson_writer.h +++ b/src/ubjson/ubjson_writer.h @@ -705,6 +705,91 @@ ret_t ubjson_writer_write_kv_wstr_len(ubjson_writer_t* writer, const char* key, */ ret_t ubjson_writer_write_kv_value(ubjson_writer_t* writer, const char* key, const value_t* value); + +/** + * @method ubjson_writer_write_array_uint8 + * 写入 uint8 数组。 + * + * @param {ubjson_writer_t*} writer writer对象。 + * @param {uint8_t*} data 数组。 + * @param {uint32_t} count 数组元素计数。 + * + * @return {ret_t} 返回 ret_t 值 + */ +ret_t ubjson_writer_write_array_uint8(ubjson_writer_t* writer, uint8_t* data, uint32_t count); + +/** + * @method ubjson_writer_write_array_int8 + * 写入 int8 数组。 + * + * @param {ubjson_writer_t*} writer writer对象。 + * @param {int8_t*} data 数组。 + * @param {uint32_t} count 数组元素计数。 + * + * @return {ret_t} 返回 ret_t 值 + */ +ret_t ubjson_writer_write_array_int8(ubjson_writer_t* writer, int8_t* data, uint32_t count); + +/** + * @method ubjson_writer_write_array_int16 + * 写入 int16 数组。 + * + * @param {ubjson_writer_t*} writer writer对象。 + * @param {int16_t*} data 数组。 + * @param {uint32_t} count 数组元素计数。 + * + * @return {ret_t} 返回 ret_t 值 + */ +ret_t ubjson_writer_write_array_int16(ubjson_writer_t* writer, int16_t* data, uint32_t count); + +/** + * @method ubjson_writer_write_array_int32 + * 写入 int32 数组。 + * + * @param {ubjson_writer_t*} writer writer对象。 + * @param {int32_t*} data 数组。 + * @param {uint32_t} count 数组元素计数。 + * + * @return {ret_t} 返回 ret_t 值 + */ +ret_t ubjson_writer_write_array_int32(ubjson_writer_t* writer, int32_t* data, uint32_t count); + +/** + * @method ubjson_writer_write_array_int64 + * 写入 int64 数组。 + * + * @param {ubjson_writer_t*} writer writer对象。 + * @param {int32_t*} data 数组。 + * @param {uint32_t} count 数组元素计数。 + * + * @return {ret_t} 返回 ret_t 值 + */ +ret_t ubjson_writer_write_array_int64(ubjson_writer_t* writer, int64_t* data, uint32_t count); + +/** + * @method ubjson_writer_write_array_float32 + * 写入 float32 数组。 + * + * @param {ubjson_writer_t*} writer writer对象。 + * @param {int32_t*} data 数组。 + * @param {uint32_t} count 数组元素计数。 + * + * @return {ret_t} 返回 ret_t 值 + */ +ret_t ubjson_writer_write_array_float32(ubjson_writer_t* writer, float* data, uint32_t count); + +/** + * @method ubjson_writer_write_array_float64 + * 写入 float64 数组。 + * + * @param {ubjson_writer_t*} writer writer对象。 + * @param {int32_t*} data 数组。 + * @param {uint32_t} count 数组元素计数。 + * + * @return {ret_t} 返回 ret_t 值 + */ +ret_t ubjson_writer_write_array_float64(ubjson_writer_t* writer, double* data, uint32_t count); + END_C_DECLS #endif /*TK_UBJSON_WRITER_H*/ diff --git a/tests/ubjson_parser_test.cc b/tests/ubjson_parser_test.cc index c22f7172c..05c4f2686 100644 --- a/tests/ubjson_parser_test.cc +++ b/tests/ubjson_parser_test.cc @@ -271,3 +271,99 @@ TEST(UBJsonParser, ubjson_writer_write_kv_value) { tk_object_unref(obj); } + +TEST(UBJsonParser, optimized_array_uint8) { + uint8_t buff[256]; + uint8_t data[] = {100, 200, 255}; + value_t v; + wbuffer_t wb; + ubjson_writer_t ub; + tk_object_t* obj = NULL; + wbuffer_init(&wb, buff, sizeof(buff)); + ubjson_writer_init(&ub, (ubjson_write_callback_t)wbuffer_write_binary, &wb); + + ASSERT_EQ(ubjson_writer_write_object_begin(&ub), RET_OK); + ASSERT_EQ(ubjson_writer_write_key(&ub, "values"), RET_OK); + + ASSERT_EQ(ubjson_writer_write_array_uint8(&ub, data, ARRAY_SIZE(data)), RET_OK); + + ASSERT_EQ(ubjson_writer_write_object_end(&ub), RET_OK); + + obj = object_from_ubjson(wb.data, wb.cursor); + ASSERT_EQ(tk_object_get_prop_by_path(obj, "values.0", &v), RET_OK); + ASSERT_EQ(v.type == VALUE_TYPE_UINT8, true); + ASSERT_EQ(value_int(&v), 100); + + ASSERT_EQ(tk_object_get_prop_int_by_path(obj, "values.1", 0), 200); + ASSERT_EQ(tk_object_get_prop_int_by_path(obj, "values.2", 0), 255); + ASSERT_EQ(tk_object_get_prop_int_by_path(obj, "values.size", 0), 3); + + tk_object_unref(obj); +} +TEST(UBJsonParser, optimized_array_int32) { + uint8_t buff[256]; + int32_t data[] = {100, 200, 300}; + value_t v; + wbuffer_t wb; + ubjson_writer_t ub; + tk_object_t* obj = NULL; + wbuffer_init(&wb, buff, sizeof(buff)); + ubjson_writer_init(&ub, (ubjson_write_callback_t)wbuffer_write_binary, &wb); + + ASSERT_EQ(ubjson_writer_write_object_begin(&ub), RET_OK); + ASSERT_EQ(ubjson_writer_write_key(&ub, "values"), RET_OK); + + ASSERT_EQ(ubjson_writer_write_array_int32(&ub, data, ARRAY_SIZE(data)), RET_OK); + + ASSERT_EQ(ubjson_writer_write_object_end(&ub), RET_OK); + + obj = object_from_ubjson(wb.data, wb.cursor); + ASSERT_EQ(tk_object_get_prop_by_path(obj, "values.0", &v), RET_OK); + ASSERT_EQ(v.type == VALUE_TYPE_INT32, true); + ASSERT_EQ(value_int(&v), 100); + + ASSERT_EQ(tk_object_get_prop_int_by_path(obj, "values.1", 0), 200); + ASSERT_EQ(tk_object_get_prop_int_by_path(obj, "values.2", 0), 300); + ASSERT_EQ(tk_object_get_prop_int_by_path(obj, "values.size", 0), 3); + + tk_object_unref(obj); +} + +TEST(UBJsonParser, optimized_array_float64) { + uint8_t buff[256]; + double data[] = {100.11, 200.11, 300.11}; + value_t v; + wbuffer_t wb; + ubjson_writer_t ub; + tk_object_t* obj = NULL; + wbuffer_init(&wb, buff, sizeof(buff)); + ubjson_writer_init(&ub, (ubjson_write_callback_t)wbuffer_write_binary, &wb); + + ASSERT_EQ(ubjson_writer_write_object_begin(&ub), RET_OK); + + ASSERT_EQ(ubjson_writer_write_key(&ub, "values"), RET_OK); + ASSERT_EQ(ubjson_writer_write_array_float64(&ub, data, ARRAY_SIZE(data)), RET_OK); + + ASSERT_EQ(ubjson_writer_write_kv_str(&ub, "name", "optimized_array"), RET_OK); + + ASSERT_EQ(ubjson_writer_write_object_end(&ub), RET_OK); + + obj = object_from_ubjson(wb.data, wb.cursor); + ASSERT_EQ(tk_object_get_prop_by_path(obj, "values.0", &v), RET_OK); + ASSERT_EQ(v.type == VALUE_TYPE_DOUBLE, true); + ASSERT_EQ(value_double(&v), 100.11); + + ASSERT_EQ(tk_object_get_prop_by_path(obj, "values.1", &v), RET_OK); + ASSERT_EQ(v.type == VALUE_TYPE_DOUBLE, true); + ASSERT_EQ(value_double(&v), 200.11); + + ASSERT_EQ(tk_object_get_prop_by_path(obj, "values.2", &v), RET_OK); + ASSERT_EQ(v.type == VALUE_TYPE_DOUBLE, true); + ASSERT_EQ(value_double(&v), 300.11); + + ASSERT_EQ(tk_object_get_prop_int_by_path(obj, "values.size", 0), 3); + + ASSERT_STREQ(tk_object_get_prop_str_by_path(obj, "name"), "optimized_array"); + + tk_object_unref(obj); +} diff --git a/tests/ubjson_reader_test.cc b/tests/ubjson_reader_test.cc index 18852384d..f8a47d968 100644 --- a/tests/ubjson_reader_test.cc +++ b/tests/ubjson_reader_test.cc @@ -4,7 +4,7 @@ #include "ubjson/ubjson_reader.h" #define PREPARE_TEST() \ - uint8_t buff[256]; \ + uint8_t buff[4096]; \ value_t v; \ wbuffer_t wb; \ rbuffer_t rb; \ @@ -267,3 +267,90 @@ TEST(UBJsonReader, wstring) { ubjson_reader_reset(&ur); } + +TEST(UBJsonReader, optimized_array_uint8) { + PREPARE_TEST(); + + uint8_t data[120]; + for (int i = 0; i < ARRAY_SIZE(data); i++) { + data[i] = i; + } + + ASSERT_EQ(ubjson_writer_write_array_uint8(&ub, data, ARRAY_SIZE(data)), RET_OK); + + rb.capacity = wb.cursor; + ASSERT_EQ(ubjson_reader_read(&ur, &v), RET_OK); + ASSERT_EQ(v.type == VALUE_TYPE_TOKEN, true); + ASSERT_EQ(value_token(&v), UBJSON_MARKER_ARRAY_BEGIN); + + // 优化数组的类型 + ASSERT_EQ(ubjson_reader_read(&ur, &v), RET_OK); + ASSERT_EQ(v.type == VALUE_TYPE_TOKEN, true); + ASSERT_EQ(value_token(&v), UBJSON_MARKER_UINT8); + + // 数据 + ASSERT_EQ(ubjson_reader_read(&ur, &v), RET_OK); + ASSERT_EQ(v.type, VALUE_TYPE_BINARY); + ASSERT_TRUE(memcmp(v.value.binary_data.data, data, ARRAY_SIZE(data)) == 0); + ASSERT_EQ(v.value.binary_data.size, ARRAY_SIZE(data)); + + ubjson_reader_reset(&ur); +} + +TEST(UBJsonReader, optimized_array_int32) { + PREPARE_TEST(); + + int32_t data[120]; + for (int i = 0; i < ARRAY_SIZE(data); i++) { + data[i] = i; + } + + ASSERT_EQ(ubjson_writer_write_array_int32(&ub, data, ARRAY_SIZE(data)), RET_OK); + + rb.capacity = wb.cursor; + ASSERT_EQ(ubjson_reader_read(&ur, &v), RET_OK); + ASSERT_EQ(v.type == VALUE_TYPE_TOKEN, true); + ASSERT_EQ(value_token(&v), UBJSON_MARKER_ARRAY_BEGIN); + + // 优化数组的类型 + ASSERT_EQ(ubjson_reader_read(&ur, &v), RET_OK); + ASSERT_EQ(v.type == VALUE_TYPE_TOKEN, true); + ASSERT_EQ(value_token(&v), UBJSON_MARKER_INT32); + + // 数据 + ASSERT_EQ(ubjson_reader_read(&ur, &v), RET_OK); + ASSERT_EQ(v.type, VALUE_TYPE_BINARY); + ASSERT_TRUE(memcmp(v.value.binary_data.data, data, sizeof(data)) == 0); + ASSERT_EQ(v.value.binary_data.size, sizeof(data)); + + ubjson_reader_reset(&ur); +} + +TEST(UBJsonReader, optimized_array_double) { + PREPARE_TEST(); + + double data[120]; + for (int i = 0; i < ARRAY_SIZE(data); i++) { + data[i] = i * 1.11; + } + + ASSERT_EQ(ubjson_writer_write_array_float64(&ub, data, ARRAY_SIZE(data)), RET_OK); + + rb.capacity = wb.cursor; + ASSERT_EQ(ubjson_reader_read(&ur, &v), RET_OK); + ASSERT_EQ(v.type == VALUE_TYPE_TOKEN, true); + ASSERT_EQ(value_token(&v), UBJSON_MARKER_ARRAY_BEGIN); + + // 优化数组的类型 + ASSERT_EQ(ubjson_reader_read(&ur, &v), RET_OK); + ASSERT_EQ(v.type == VALUE_TYPE_TOKEN, true); + ASSERT_EQ(value_token(&v), UBJSON_MARKER_FLOAT64); + + // 数据 + ASSERT_EQ(ubjson_reader_read(&ur, &v), RET_OK); + ASSERT_EQ(v.type, VALUE_TYPE_BINARY); + ASSERT_TRUE(memcmp(v.value.binary_data.data, data, sizeof(data)) == 0); + ASSERT_EQ(v.value.binary_data.size, sizeof(data)); + + ubjson_reader_reset(&ur); +} diff --git a/tests/ubjson_writer_test.cc b/tests/ubjson_writer_test.cc index 1034e85f2..eaaa449c0 100644 --- a/tests/ubjson_writer_test.cc +++ b/tests/ubjson_writer_test.cc @@ -1,5 +1,6 @@ #include "gtest/gtest.h" #include "tkc/buffer.h" +#include "tkc/endian.h" #include "ubjson/ubjson_writer.h" TEST(UBJsonWriter, null) { @@ -355,3 +356,85 @@ TEST(UBJsonWriter, kv_wstring_len) { ASSERT_EQ(buff[6], 'b'); ASSERT_EQ(wb.cursor, 7u); } + +TEST(UBJsonWriter, optimized_array_uint8) { + uint8_t buff[256]; + uint8_t data[120]; + wbuffer_t wb; + ubjson_writer_t ub; + wbuffer_init(&wb, buff, sizeof(buff)); + ubjson_writer_init(&ub, (ubjson_write_callback_t)wbuffer_write_binary, &wb); + + for (int i = 0; i < ARRAY_SIZE(data); i++) { + data[i] = i; + } + + ASSERT_EQ(ubjson_writer_write_array_uint8(&ub, data, ARRAY_SIZE(data)), RET_OK); + + ASSERT_EQ(wb.cursor, 6 + sizeof(data)); + ASSERT_EQ(buff[0], UBJSON_MARKER_ARRAY_BEGIN); + ASSERT_EQ(buff[1], UBJSON_MARKER_CONTAINER_TYPE); + ASSERT_EQ(buff[2], UBJSON_MARKER_UINT8); + ASSERT_EQ(buff[3], UBJSON_MARKER_CONTAINER_COUNT); + ASSERT_EQ(buff[4], UBJSON_MARKER_INT8); + ASSERT_EQ(buff[5], ARRAY_SIZE(data)); + ASSERT_EQ(memcmp(buff + 6, data, sizeof(data)), 0); +} + +TEST(UBJsonWriter, optimized_array_int32) { + uint8_t buff[256 + 120 * sizeof(int32_t)]; + int32_t data[120]; + wbuffer_t wb; + ubjson_writer_t ub; + wbuffer_init(&wb, buff, sizeof(buff)); + ubjson_writer_init(&ub, (ubjson_write_callback_t)wbuffer_write_binary, &wb); + + for (int i = 0; i < ARRAY_SIZE(data); i++) { + data[i] = i; + } + + ASSERT_EQ(ubjson_writer_write_array_int32(&ub, data, ARRAY_SIZE(data)), RET_OK); + + ASSERT_EQ(wb.cursor, 6 + sizeof(data)); + ASSERT_EQ(buff[0], UBJSON_MARKER_ARRAY_BEGIN); + ASSERT_EQ(buff[1], UBJSON_MARKER_CONTAINER_TYPE); + ASSERT_EQ(buff[2], UBJSON_MARKER_INT32); + ASSERT_EQ(buff[3], UBJSON_MARKER_CONTAINER_COUNT); + ASSERT_EQ(buff[4], UBJSON_MARKER_INT8); + ASSERT_EQ(buff[5], ARRAY_SIZE(data)); + + int32_t* p = (int32_t*)(buff + 6); + for (int i = 0; i < ARRAY_SIZE(data); i++) { + int32_t v = int32_from_big_endian(p[i]); + ASSERT_EQ(v, data[i]); + } +} + +TEST(UBJsonWriter, optimized_array_float64) { + uint8_t buff[256 + 120 * sizeof(double)]; + double data[120]; + wbuffer_t wb; + ubjson_writer_t ub; + wbuffer_init(&wb, buff, sizeof(buff)); + ubjson_writer_init(&ub, (ubjson_write_callback_t)wbuffer_write_binary, &wb); + + for (int i = 0; i < ARRAY_SIZE(data); i++) { + data[i] = i * 1.11; + } + + ASSERT_EQ(ubjson_writer_write_array_float64(&ub, data, ARRAY_SIZE(data)), RET_OK); + + ASSERT_EQ(wb.cursor, 6 + sizeof(data)); + ASSERT_EQ(buff[0], UBJSON_MARKER_ARRAY_BEGIN); + ASSERT_EQ(buff[1], UBJSON_MARKER_CONTAINER_TYPE); + ASSERT_EQ(buff[2], UBJSON_MARKER_FLOAT64); + ASSERT_EQ(buff[3], UBJSON_MARKER_CONTAINER_COUNT); + ASSERT_EQ(buff[4], UBJSON_MARKER_INT8); + ASSERT_EQ(buff[5], ARRAY_SIZE(data)); + + double* p = (double*)(buff + 6); + for (int i = 0; i < ARRAY_SIZE(data); i++) { + double v = double_from_big_endian(p[i]); + ASSERT_EQ(v, data[i]); + } +}