Skip to content

Commit

Permalink
refactor(json): optimize the performance of encode and decode
Browse files Browse the repository at this point in the history
  • Loading branch information
Water-Melon committed Feb 6, 2024
1 parent 6087638 commit 0b26115
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 150 deletions.
1 change: 1 addition & 0 deletions include/mln_json.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "mln_rbtree.h"

#define M_JSON_LEN 31
#define M_JSON_BUFLEN 512

#define M_JSON_V_FALSE 0
#define M_JSON_V_TRUE 1
Expand Down
238 changes: 88 additions & 150 deletions src/mln_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,8 @@ mln_json_parse_false(mln_json_t *j, char *jstr, int len, mln_uauto_t index);
static inline int
mln_json_parse_null(mln_json_t *j, char *jstr, int len, mln_uauto_t index);
static inline void mln_json_jumpoff_blank(char **jstr, int *len);
static inline mln_size_t mln_json_get_length(mln_json_t *j);
static int
mln_json_get_length_obj_iterate_handler(mln_rbtree_node_t *node, void *data);
static inline mln_size_t
mln_json_write_content(mln_json_t *j, mln_s8ptr_t buf);
static inline int
mln_json_write_content(mln_json_t *j, mln_s8ptr_t *buf, mln_size_t *size, mln_size_t *off);
static int
mln_json_write_content_obj_iterate_handler(mln_rbtree_node_t *node, void *data);
static inline int mln_json_parse_is_index(mln_string_t *s, mln_size_t *idx);
Expand Down Expand Up @@ -65,12 +62,16 @@ MLN_FUNC_VOID(static inline, void, mln_json_kv_free, (mln_json_kv_t *kv), (kv),
})


MLN_FUNC(, int, mln_json_obj_init, (mln_json_t *j), (j), {
MLN_FUNC(static inline, int, __mln_json_obj_init, (mln_json_t *j), (j), {
j->type = M_JSON_OBJECT;
if ((j->data.m_j_obj = mln_rbtree_new(NULL)) == NULL) return -1;
return 0;
})

MLN_FUNC(, int, mln_json_obj_init, (mln_json_t *j), (j), {
return __mln_json_obj_init(j);
})

MLN_FUNC(, int, mln_json_obj_update, \
(mln_json_t *j, mln_json_t *key, mln_json_t *val), (j, key, val), \
{
Expand Down Expand Up @@ -136,7 +137,7 @@ MLN_FUNC_VOID(, void, mln_json_obj_remove, (mln_json_t *j, mln_string_t *key), (
})


MLN_FUNC(, int, mln_json_array_init, (mln_json_t *j), (j), {
MLN_FUNC(static inline, int, __mln_json_array_init, (mln_json_t *j), (j), {
struct mln_array_attr attr;

attr.pool = NULL;
Expand All @@ -151,6 +152,10 @@ MLN_FUNC(, int, mln_json_array_init, (mln_json_t *j), (j), {
return 0;
})

MLN_FUNC(, int, mln_json_array_init, (mln_json_t *j), (j), {
return __mln_json_array_init(j);
})

MLN_FUNC(, mln_json_t *, mln_json_array_search, (mln_json_t *j, mln_uauto_t index), (j, index), {
if (!mln_json_is_array(j)) return NULL;

Expand Down Expand Up @@ -361,7 +366,7 @@ MLN_FUNC(static inline, int, mln_json_parse_obj, \
return -1;
}

if (mln_json_obj_init(val) < 0) return -1;
if (__mln_json_obj_init(val) < 0) return -1;

again:
mln_json_init(&key);
Expand Down Expand Up @@ -454,7 +459,7 @@ MLN_FUNC(static inline, int, mln_json_parse_array, \
mln_json_t j;
mln_uauto_t cnt = 0;

if (mln_json_array_init(val) < 0) return -1;
if (__mln_json_array_init(val) < 0) return -1;

++jstr;
if (--len <= 0) {
Expand Down Expand Up @@ -823,222 +828,155 @@ MLN_FUNC_VOID(static inline, void, mln_json_jumpoff_blank, \


MLN_FUNC(, mln_string_t *, mln_json_encode, (mln_json_t *j), (j), {
mln_u32_t size = mln_json_get_length(j), n;
mln_s8ptr_t buf;
mln_size_t size = M_JSON_BUFLEN, pos = 0;;
mln_string_t *s;

buf = (mln_s8ptr_t)malloc(size);
if (buf == NULL) return NULL;

n = mln_json_write_content(j, buf);
buf[n] = 0;
if (mln_json_write_content(j, &buf, &size, &pos) < 0) {
free(buf);
return NULL;
}

s = mln_string_const_ndup(buf, n);
s = mln_string_const_ndup(buf, pos);
free(buf);
if (s == NULL) return NULL;

return s;
})

MLN_FUNC(static inline, mln_size_t, mln_json_get_length, (mln_json_t *j), (j), {
if (j == NULL) return 0;

char num_str[512] = {0};
mln_size_t length = 1;
mln_u8ptr_t p, end;

switch (j->type) {
case M_JSON_OBJECT:
length += 2;
mln_rbtree_iterate(mln_json_object_data_get(j), mln_json_get_length_obj_iterate_handler, &length);
break;
case M_JSON_ARRAY:
{
mln_json_t *el = (mln_json_t *)mln_array_elts(mln_json_array_data_get(j));
mln_json_t *elend = el + mln_array_nelts(mln_json_array_data_get(j));
length += 2;
for (; el < elend; ++el) {
length += (mln_json_get_length(el) + 1);
}
break;
}
case M_JSON_STRING:
length += 2;
if (j->data.m_j_string != NULL) {
p = j->data.m_j_string->data;
end = p + j->data.m_j_string->len;
for (; p < end; ++p) {
if (*p == '\"' || *p == '\\')
++length;
}
length += j->data.m_j_string->len;
}
break;
case M_JSON_NUM:
length += snprintf(num_str, sizeof(num_str), "%f", j->data.m_j_number);
break;
case M_JSON_TRUE:
length += 4;
break;
case M_JSON_FALSE:
length += 5;
break;
case M_JSON_NULL:
length += 4;
break;
default:
break;
}

return length;
})
struct mln_json_tmp_s {
void *ptr1;
void *ptr2;
void *ptr3;
};

MLN_FUNC(static, int, mln_json_get_length_obj_iterate_handler, \
(mln_rbtree_node_t *node, void *data), (node, data), \
MLN_FUNC(static inline, int, mln_json_write_byte, \
(mln_s8ptr_t *buf, mln_size_t *size, mln_size_t *off, mln_u8ptr_t s, mln_size_t n), \
(buf, size, off, s, n), \
{
mln_json_kv_t *kv = (mln_json_kv_t *)mln_rbtree_node_data_get(node);
mln_size_t *length = (mln_size_t *)data;

(*length) += (mln_json_get_length(&(kv->key)) + mln_json_get_length(&(kv->val)) + 2);
if (*size < *off + n) {
mln_s8ptr_t tmp = (mln_s8ptr_t)realloc(*buf, (*size) << 1);
if (tmp == NULL) return -1;
*buf = tmp;
*size <<= 1;
}
memcpy(*buf + *off, s, n);
*off += n;
return 0;
})

struct mln_json_tmp_s {
void *ptr1;
void *ptr2;
};
#define mln_json_write_back(_off, _n) ({\
mln_size_t o = (_off), n = (_n);\
(_off) = o < n? 0: (o - n);\
})

MLN_FUNC(static inline, mln_size_t, mln_json_write_content, \
(mln_json_t *j, mln_s8ptr_t buf), (j, buf), \
MLN_FUNC(static inline, int, mln_json_write_content, \
(mln_json_t *j, mln_s8ptr_t *buf, mln_size_t *size, mln_size_t *off), \
(j, buf, size, off), \
{
if (j == NULL) return 0;

int n;
mln_size_t length = 0, save;
mln_string_t *s;
struct mln_json_tmp_s tmp;
mln_u8ptr_t p, end;
mln_size_t save;

switch (j->type) {
case M_JSON_OBJECT:
*buf++ = '{';
++length;
tmp.ptr1 = &length;
tmp.ptr2 = &buf;
save = length;
{
struct mln_json_tmp_s tmp;
if (mln_json_write_byte(buf, size, off, (mln_u8ptr_t)"{", 1) < 0) return -1;
tmp.ptr1 = buf;
tmp.ptr2 = size;
tmp.ptr3 = off;
save = *off;
mln_rbtree_iterate(mln_json_object_data_get(j), mln_json_write_content_obj_iterate_handler, &tmp);
if (save < length) {
--buf;
--length;
*buf = 0;
}
*buf++ = '}';
++length;
if (save < *off) mln_json_write_back(*off, 1);
if (mln_json_write_byte(buf, size, off, (mln_u8ptr_t)"}", 1) < 0) return -1;
break;
}
case M_JSON_ARRAY:
{
mln_json_t *el = (mln_json_t *)mln_array_elts(mln_json_array_data_get(j));
mln_json_t *elend = el + mln_array_nelts(mln_json_array_data_get(j));

*buf++ = '[';
++length;
save = length;
if (mln_json_write_byte(buf, size, off, (mln_u8ptr_t)"[", 1) < 0) return -1;
save = *off;
for (; el < elend; ++el) {
n = mln_json_write_content(el, buf);
buf += n;
length += n;

*buf++ = ',';
length += 1;
}
if (save < length) {
--buf;
--length;
*buf = 0;
if (mln_json_write_content(el, buf, size, off) < 0) return-1;
if (mln_json_write_byte(buf, size, off, (mln_u8ptr_t)",", 1) < 0) return -1;
}
*buf++ = ']';
++length;
if (save < *off) mln_json_write_back(*off, 1);
if (mln_json_write_byte(buf, size, off, (mln_u8ptr_t)"]", 1) < 0) return -1;
break;
}
case M_JSON_STRING:
*buf++ = '\"';
++length;
{
mln_string_t *s;
mln_u8ptr_t p, end;
if (mln_json_write_byte(buf, size, off, (mln_u8ptr_t)"\"", 1) < 0) return -1;
if ((s = j->data.m_j_string) != NULL) {
p = j->data.m_j_string->data;
end = p + j->data.m_j_string->len;
for (; p < end; ) {
if (*p == '\"' || *p == '\\') {
*buf++ = '\\';
++length;
if (mln_json_write_byte(buf, size, off, (mln_u8ptr_t)"\\", 1) < 0) return -1;
}
*buf++ = *p++;
++length;
if (mln_json_write_byte(buf, size, off, p++, 1) < 0) return -1;
}
}
*buf++ = '\"';
++length;
if (mln_json_write_byte(buf, size, off, (mln_u8ptr_t)"\"", 1) < 0) return -1;
break;
}
case M_JSON_NUM:
{
int n;
char tmp[M_JSON_BUFLEN];
mln_s64_t i = (mln_s64_t)(j->data.m_j_number);
if (i == j->data.m_j_number)
#if defined(WIN32) && defined(__pentiumpro__)
n = snprintf(buf, 512, "%I64d", i);
n = snprintf(tmp, sizeof(tmp) - 1, "%I64d", i);
#elif defined(WIN32) || defined(i386) || defined(__arm__) || defined(__wasm__)
n = snprintf(buf, 512, "%lld", i);
n = snprintf(tmp, sizeof(tmp) - 1, "%lld", i);
#else
n = snprintf(buf, 512, "%ld", i);
n = snprintf(tmp, sizeof(tmp) - 1, "%ld", i);
#endif
else
n = snprintf(buf, 512, "%f", j->data.m_j_number);
buf += n;
length += n;
n = snprintf(tmp, sizeof(tmp) - 1, "%f", j->data.m_j_number);
if (mln_json_write_byte(buf, size, off, (mln_u8ptr_t)tmp, n) < 0) return -1;
break;
}
case M_JSON_TRUE:
memcpy(buf, "true", 4);
buf += 4;
length += 4;
if (mln_json_write_byte(buf, size, off, (mln_u8ptr_t)"true", 4) < 0) return -1;
break;
case M_JSON_FALSE:
memcpy(buf, "false", 5);
buf += 5;
length += 5;
if (mln_json_write_byte(buf, size, off, (mln_u8ptr_t)"false", 5) < 0) return -1;
break;
case M_JSON_NULL:
memcpy(buf, "null", 4);
buf += 4;
length += 4;
if (mln_json_write_byte(buf, size, off, (mln_u8ptr_t)"null", 4) < 0) return -1;
break;
default:
break;
}

return length;
return 0;
})

MLN_FUNC(static, int, mln_json_write_content_obj_iterate_handler, \
(mln_rbtree_node_t *node, void *data), (node, data), \
{
mln_json_kv_t *kv = (mln_json_kv_t *)mln_rbtree_node_data_get(node);
struct mln_json_tmp_s *tmp = (struct mln_json_tmp_s *)data;
mln_size_t *length = (mln_size_t *)(tmp->ptr1);
mln_s8ptr_t *buf = (mln_s8ptr_t *)(tmp->ptr2);
mln_size_t n;
mln_s8ptr_t *buf = (mln_s8ptr_t *)(tmp->ptr1);
mln_size_t *size = (mln_size_t *)(tmp->ptr2);
mln_size_t *off = (mln_size_t *)(tmp->ptr3);

if (kv == NULL) return 0;

n = mln_json_write_content(&(kv->key), *buf);
(*buf) += n;
(*length) += n;
*(*buf)++ = ':';
++(*length);
n = mln_json_write_content(&(kv->val), *buf);
(*buf) += n;
(*length) += n;

*(*buf)++ = ',';
(*length) += 1;
if (mln_json_write_content(&(kv->key), buf, size, off) < 0) return -1;
if (mln_json_write_byte(buf, size, off, (mln_u8ptr_t)":", 1) < 0) return -1;
if (mln_json_write_content(&(kv->val), buf, size, off) < 0) return -1;
if (mln_json_write_byte(buf, size, off, (mln_u8ptr_t)",", 1) < 0) return -1;

return 0;
})
Expand Down Expand Up @@ -1121,7 +1059,7 @@ MLN_FUNC(static inline, int, mln_json_obj_generate, \
double d;
struct mln_json_call_attr *ca;

if (mln_json_is_none(j) && mln_json_obj_init(j) < 0) return -1;
if (mln_json_is_none(j) && __mln_json_obj_init(j) < 0) return -1;
if (!mln_json_is_object(j)) return -1;
++f;

Expand Down Expand Up @@ -1289,7 +1227,7 @@ MLN_FUNC(static inline, int, mln_json_array_generate, \
double d;
struct mln_json_call_attr *ca;

if (mln_json_is_none(j) && mln_json_array_init(j) < 0) return -1;
if (mln_json_is_none(j) && __mln_json_array_init(j) < 0) return -1;
if (!mln_json_is_array(j)) return -1;
++f;

Expand Down

0 comments on commit 0b26115

Please sign in to comment.