Browse Source

json.dumps speed enhanced 100+ times

lyon 2 years ago
parent
commit
efb0aa4e8e

+ 52 - 13
examples/json/json_speed.py

@@ -1,22 +1,61 @@
 import json
 import time
 
-json.CONFIG_USING_JSMN = False
+dict_test = {'widget0': {"type": "div", "attributes": {"class": "container", "style": {"width": 240, "height": 240, "margin": 0, "padding": 0, "border-radius": 0, "border-width": 0, "border-color": "red", "background-color": 37864}}, "nodes": [{"type": "text", "attributes": {"font-size": "30", "class": "result-text", "style": {"top": 5, "left": 5, "width": 220, "text-align": "right", "height": 30, "color": "white", "text-overflow": "longbreak", "border-width": 0, "border-color": "red", "background-color": "transparent"}}, "nodes": [], "bindings":[{"attrName": "text", "key": "result", "isText": True}], "events": [], "value":"0", "widgetName":"widget1"}, {"type": "div", "attributes": {"class": "key-wrapper", "onclick": "onclick", "style": {"width": 60, "height": 50, "border-width": 0, "border-color": "red", "background-color": "transparent", "top": 40, "left": 10}}, "nodes": [{"type": "text", "attributes": {"font-size": "30", "class": "key", "style": {"left": 0, "top": 0, "width": 50, "height": 40, "margin": 0, "padding": 0, "color": "white", "font-size": 30, "text-align": "center", "background-color": "transparent"}}, "nodes": [], "bindings":[], "events":[], "value":"1", "widgetName":"widget3"}], "bindings":[], "events":[{"onclick": "onclick"}], "widgetName": "widget2"}, {"type": "div", "attributes": {"class": "key-wrapper", "onclick": "onclick", "style": {"width": 60, "height": 50, "border-width": 0, "border-color": "red", "background-color": "transparent", "top": 40, "left": 60}}, "nodes": [{"type": "text", "attributes": {"font-size": "30", "class": "key", "style": {
+    "left": 0, "top": 0, "width": 50, "height": 40, "margin": 0, "padding": 0, "color": "white", "font-size": 30, "text-align": "center", "background-color": "transparent"}}, "nodes": [], "bindings":[], "events":[], "value":"2", "widgetName":"widget5"}], "bindings":[], "events":[{"onclick": "onclick"}], "widgetName": "widget4"}, {"type": "div", "attributes": {"class": "key-wrapper", "onclick": "onclick", "style": {"width": 60, "height": 50, "border-width": 0, "border-color": "red", "background-color": "transparent", "top": 40, "left": 110}}, "nodes": [{"type": "text", "attributes": {"font-size": "30", "class": "key", "style": {"left": 0, "top": 0, "width": 50, "height": 40, "margin": 0, "padding": 0, "color": "white", "font-size": 30, "text-align": "center", "background-color": "transparent"}}, "nodes": [], "bindings":[], "events":[], "value":"3", "widgetName":"widget7"}], "bindings":[], "events":[{"onclick": "onclick"}], "widgetName": "widget6"}, {"type": "div", "attributes": {"class": "key-wrapper", "onclick": "onclick", "style": {"width": 60, "height": 50, "border-width": 0, "border-color": "red", "background-color": "transparent", "top": 40, "left": 160}}, "nodes": [{"type": "text", "attributes": {"font-size": "30", "class": "key", "style": {"left": 0, "top": 0, "width": 50, "height": 40, "margin": 0, "padding": 0, "color": "white", "font-size": 30, "text-align": "center", "background-color": "transparent"}}, "nodes": [], "bindings":[], "events":[], "value":"+", "widgetName":"widget9"}], "bindings":[], "events":[{"onclick": "onclick"}], "widgetName": "widget8"}], "bindings": [], "events": [], "widgetName": "widget0"}}
+
+json.CONFIG_USING_CJSON = True
+print('dict_test:', dict_test)
+json_test = json.dumps(dict_test)
+print('json_test:', json_test)
+
+json.CONFIG_USING_CJSON = True
+start = time.tick_ms()
+for i in range(10):
+    res = json.loads(json_test)
+str_res_cjson = str(res)
+print('len(str_res_cjson):', len(str_res_cjson))
+end = time.tick_ms()
+time_cjson_loads = end - start
+print('loads: cjson:', time_cjson_loads, 'ms')
+
+json.CONFIG_USING_CJSON = False
+start = time.tick_ms()
+for i in range(10):
+    res = json.loads(json_test)
+str_res_jsmn = str(res)
+print('len(str_res_jsmn):', len(str_res_jsmn))
+end = time.tick_ms()
+time_jsmn_loads = end - start
+
+print('loads: jsmn:', time_jsmn_loads, 'ms')
+
+# test for dumps
+
+# test for dumps
+
+json.CONFIG_USING_CJSON = True
 start = time.tick_ms()
-for i in range(1000):
-    res = json.loads(
-        '{"a": 1, "b": 2, "c": 3, "d": {"e": 4, "f": 5}, "g": [6, 7, 8], "h": null, "i": false, "j": true, "k": "string", "l": 1.234}')
+for i in range(10):
+    res = json.dumps(dict_test)
+len_res_cjson = len(res)
+print('len(res_cjson):', len_res_cjson)
 end = time.tick_ms()
-time_cjson = end - start
-print('cjson:', time_cjson, 'ms')
+time_cjson_dumps = end - start
+print('dumps: cjson:', time_cjson_dumps, 'ms')
 
-json.CONFIG_USING_JSMN = True
+json.CONFIG_USING_CJSON = False
 start = time.tick_ms()
-for i in range(1000):
-    res = json.loads(
-        '{"a": 1, "b": 2, "c": 3, "d": {"e": 4, "f": 5}, "g": [6, 7, 8], "h": null, "i": false, "j": true, "k": "string", "l": 1.234}')
+for i in range(10):
+    res = json.dumps(dict_test)
+len_res_jsmn = len(res)
+print('len(res_jsmn):', len_res_jsmn)
 end = time.tick_ms()
-time_jsmn = end - start
-print('jsmn:', time_jsmn, 'ms')
+time_jsmn_dumps = end - start
+print('dumps: jsmn:', time_jsmn_dumps, 'ms')
 
-print('jsmn is', (time_cjson / time_jsmn), 'times faster than cjson')
+print('==================================================')
+print('loads: jsmn is', (time_cjson_loads /
+      time_jsmn_loads), 'times faster than cjson')
+print('dumps: jsmn is', (time_cjson_dumps /
+      time_jsmn_dumps), 'times faster than cjson')

+ 46 - 45
package/PikaStdLib/PikaStdData_Dict.c

@@ -8,23 +8,15 @@
 #include "dataStrs.h"
 
 Arg* PikaStdData_Dict_get(PikaObj* self, char* key) {
-    pika_assert_obj_alive(self);
-    PikaDict* dict = obj_getPtr(self, "dict");
-    Arg* res = pikaDict_getArg(dict, key);
-    if (NULL == res) {
-        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
-        __platform_printf("KeyError: %s\n", key);
-    }
-    pika_assert_arg_alive(res);
-    return arg_copy(res);
+    return arg_copy(objDict_get(self, key));
 }
 
 void PikaStdData_Dict___init__(PikaObj* self) {
-    __vm_Dict___init__(self);
+    objDict_init(self);
 }
 
 void PikaStdData_Dict_set(PikaObj* self, char* key, Arg* arg) {
-    __vm_Dict_set(self, arg, key);
+    objDict_set(self, key, arg);
 }
 
 void PikaStdData_Dict_remove(PikaObj* self, char* key) {
@@ -133,44 +125,53 @@ char* PikaStdData_dict_keys___str__(PikaObj* self) {
     return obj_getStr(self, "_buf");
 }
 
-char* PikaStdData_Dict___str__(PikaObj* self) {
-    Arg* str_arg = arg_newStr("{");
+typedef struct {
+    Arg* buf;
+    int isFirst;
+} DictToStrContext;
 
-    PikaDict* keys = obj_getPtr(self, "_keys");
-    PikaDict* dict = obj_getPtr(self, "dict");
-    pika_assert(NULL != dict);
-    pika_assert(NULL != keys);
+int32_t dictToStrEachHandle(PikaObj* self,
+                            Arg* keyEach,
+                            Arg* valEach,
+                            void* context) {
+    DictToStrContext* ctx = (DictToStrContext*)context;
 
-    int i = 0;
-    while (PIKA_TRUE) {
-        Arg* item_key = args_getArgByIndex(&keys->super, i);
-        Arg* item_val = args_getArgByIndex(&dict->super, i);
-        if (NULL == item_key) {
-            break;
-        }
-        if (i != 0) {
-            str_arg = arg_strAppend(str_arg, ", ");
-        }
-        char* key_str = builtins_str(self, item_key);
-        str_arg = arg_strAppend(str_arg, "'");
-        str_arg = arg_strAppend(str_arg, key_str);
-        str_arg = arg_strAppend(str_arg, "'");
-        str_arg = arg_strAppend(str_arg, ": ");
-
-        char* val_str = builtins_str(self, item_val);
-        if (arg_getType(item_val) == ARG_TYPE_STRING) {
-            str_arg = arg_strAppend(str_arg, "'");
-        }
-        str_arg = arg_strAppend(str_arg, val_str);
-        if (arg_getType(item_val) == ARG_TYPE_STRING) {
-            str_arg = arg_strAppend(str_arg, "'");
-        }
-        i++;
+    // 判断是否需要在字符串前添加逗号
+    if (!ctx->isFirst) {
+        ctx->buf = arg_strAppend(ctx->buf, ", ");
+    } else {
+        ctx->isFirst = 0;
     }
 
-    str_arg = arg_strAppend(str_arg, "}");
-    obj_setStr(self, "_buf", arg_getStr(str_arg));
-    arg_deinit(str_arg);
+    // 将键值对添加到字符串
+    ctx->buf = arg_strAppend(ctx->buf, "'");
+    ctx->buf = arg_strAppend(ctx->buf, builtins_str(self, keyEach));
+    ctx->buf = arg_strAppend(ctx->buf, "'");
+    ctx->buf = arg_strAppend(ctx->buf, ": ");
+    if (arg_getType(valEach) == ARG_TYPE_STRING) {
+        ctx->buf = arg_strAppend(ctx->buf, "'");
+    }
+    ctx->buf = arg_strAppend(ctx->buf, builtins_str(self, valEach));
+    if (arg_getType(valEach) == ARG_TYPE_STRING) {
+        ctx->buf = arg_strAppend(ctx->buf, "'");
+    }
+
+    return 0;
+}
+
+char* PikaStdData_Dict___str__(PikaObj* self) {
+    // 初始化上下文
+    DictToStrContext context;
+    context.buf = arg_newStr("{");
+    context.isFirst = 1;
+
+    // 使用 objDict_forEach 遍历字典
+    objDict_forEach(self, dictToStrEachHandle, &context);
+
+    // 将字符串添加到结果中并返回
+    context.buf = arg_strAppend(context.buf, "}");
+    obj_setStr(self, "_buf", arg_getStr(context.buf));
+    arg_deinit(context.buf);
     return obj_getStr(self, "_buf");
 }
 

+ 38 - 31
package/PikaStdLib/PikaStdData_List.c

@@ -5,15 +5,11 @@
 #include "dataStrs.h"
 
 void PikaStdData_List_append(PikaObj* self, Arg* arg) {
-    __vm_List_append(self, arg);
+    objList_append(self, arg);
 }
 
 void PikaStdData_List_set(PikaObj* self, int i, Arg* arg) {
-    PikaList* list = obj_getPtr(self, "list");
-    if (PIKA_RES_OK != pikaList_setArg(list, i, arg)) {
-        obj_setErrorCode(self, 1);
-        obj_setSysOut(self, "Error: index exceeded lengh of list.");
-    }
+    return objList_set(self, i, arg);
 }
 
 void PikaStdData_List___setitem__(PikaObj* self, Arg* __key, Arg* __val) {
@@ -22,37 +18,48 @@ void PikaStdData_List___setitem__(PikaObj* self, Arg* __key, Arg* __val) {
 }
 
 void PikaStdData_List___init__(PikaObj* self) {
-    __vm_List___init__(self);
+    objList_init(self);
 }
 
 char* builtins_str(PikaObj* self, Arg* arg);
-char* PikaStdData_List___str__(PikaObj* self) {
-    Arg* str_arg = arg_newStr("[");
-    PikaList* list = obj_getPtr(self, "list");
+typedef struct {
+    Arg* buf;
+    int count;
+} ListToStrContext;
 
-    int i = 0;
-    while (PIKA_TRUE) {
-        Arg* item = pikaList_getArg(list, i);
-        if (NULL == item) {
-            break;
-        }
-        if (i != 0) {
-            str_arg = arg_strAppend(str_arg, ", ");
-        }
-        char* item_str = builtins_str(self, item);
-        if (arg_getType(item) == ARG_TYPE_STRING) {
-            str_arg = arg_strAppend(str_arg, "'");
-        }
-        str_arg = arg_strAppend(str_arg, item_str);
-        if (arg_getType(item) == ARG_TYPE_STRING) {
-            str_arg = arg_strAppend(str_arg, "'");
-        }
-        i++;
+int32_t listToStrEachHandle(PikaObj* self,
+                            int itemIndex,
+                            Arg* itemEach,
+                            void* context) {
+    ListToStrContext* ctx = (ListToStrContext*)context;
+
+    char* item_str = builtins_str(self, itemEach);
+    if (ctx->count != 0) {
+        ctx->buf = arg_strAppend(ctx->buf, ", ");
+    }
+    if (arg_getType(itemEach) == ARG_TYPE_STRING) {
+        ctx->buf = arg_strAppend(ctx->buf, "'");
     }
+    ctx->buf = arg_strAppend(ctx->buf, item_str);
+    if (arg_getType(itemEach) == ARG_TYPE_STRING) {
+        ctx->buf = arg_strAppend(ctx->buf, "'");
+    }
+
+    ctx->count++;
+
+    return 0;
+}
+
+char* PikaStdData_List___str__(PikaObj* self) {
+    ListToStrContext context;
+    context.buf = arg_newStr("[");
+    context.count = 0;
+
+    objList_forEach(self, listToStrEachHandle, &context);
 
-    str_arg = arg_strAppend(str_arg, "]");
-    obj_setStr(self, "_buf", arg_getStr(str_arg));
-    arg_deinit(str_arg);
+    context.buf = arg_strAppend(context.buf, "]");
+    obj_setStr(self, "_buf", arg_getStr(context.buf));
+    arg_deinit(context.buf);
     return obj_getStr(self, "_buf");
 }
 

+ 41 - 32
package/PikaStdLib/PikaStdData_Tuple.c

@@ -3,17 +3,15 @@
 #include "dataStrs.h"
 
 int PikaStdData_Tuple_len(PikaObj* self) {
-    PikaList* list = obj_getPtr(self, "list");
-    return pikaList_getSize(list);
+    return objList_getSize(self);
 }
 
 Arg* PikaStdData_Tuple_get(PikaObj* self, int i) {
-    PikaList* list = obj_getPtr(self, "list");
-    return arg_copy(pikaList_getArg(list, i));
+    return objList_get(self, i);
 }
 
 void PikaStdData_Tuple___init__(PikaObj* self) {
-    __vm_List___init__(self);
+    objList_init(self);
 }
 
 Arg* PikaStdData_Tuple___iter__(PikaObj* self) {
@@ -51,37 +49,48 @@ void PikaStdData_Tuple___del__(PikaObj* self) {
 }
 
 char* builtins_str(PikaObj* self, Arg* arg);
+typedef struct {
+    Arg* buf;
+    int count;
+} TupleToStrContext;
+
+int32_t tupleToStrEachHandle(PikaObj* self,
+                             int itemIndex,
+                             Arg* itemEach,
+                             void* context) {
+    TupleToStrContext* ctx = (TupleToStrContext*)context;
+
+    char* item_str = builtins_str(self, itemEach);
+    if (ctx->count != 0) {
+        ctx->buf = arg_strAppend(ctx->buf, ", ");
+    }
+    if (arg_getType(itemEach) == ARG_TYPE_STRING) {
+        ctx->buf = arg_strAppend(ctx->buf, "'");
+    }
+    ctx->buf = arg_strAppend(ctx->buf, item_str);
+    if (arg_getType(itemEach) == ARG_TYPE_STRING) {
+        ctx->buf = arg_strAppend(ctx->buf, "'");
+    }
+
+    ctx->count++;
+
+    return 0;
+}
+
 char* PikaStdData_Tuple___str__(PikaObj* self) {
-    Arg* str_arg = arg_newStr("(");
-    PikaList* list = obj_getPtr(self, "list");
+    TupleToStrContext context;
+    context.buf = arg_newStr("(");
+    context.count = 0;
 
-    int i = 0;
-    while (PIKA_TRUE) {
-        Arg* item = pikaList_getArg(list, i);
-        if (NULL == item) {
-            if (i == 1) {
-                // single tuple
-                str_arg = arg_strAppend(str_arg, ",");
-            }
-            break;
-        }
-        if (i != 0) {
-            str_arg = arg_strAppend(str_arg, ", ");
-        }
-        char* item_str = builtins_str(self, item);
-        if (arg_getType(item) == ARG_TYPE_STRING) {
-            str_arg = arg_strAppend(str_arg, "'");
-        }
-        str_arg = arg_strAppend(str_arg, item_str);
-        if (arg_getType(item) == ARG_TYPE_STRING) {
-            str_arg = arg_strAppend(str_arg, "'");
-        }
-        i++;
+    objTuple_forEach(self, tupleToStrEachHandle, &context);
+
+    if (context.count == 1) {
+        context.buf = arg_strAppend(context.buf, ",");
     }
 
-    str_arg = arg_strAppend(str_arg, ")");
-    obj_setStr(self, "_buf", arg_getStr(str_arg));
-    arg_deinit(str_arg);
+    context.buf = arg_strAppend(context.buf, ")");
+    obj_setStr(self, "_buf", arg_getStr(context.buf));
+    arg_deinit(context.buf);
     return obj_getStr(self, "_buf");
 }
 

+ 95 - 15
package/json/_json.c

@@ -1,10 +1,13 @@
 #include "_json.h"
+#include "../pikascript-lib/pika_cjson/cJSON.h"
 #include "jsmn.h"
 
 #if !PIKASCRIPT_VERSION_REQUIRE_MINIMUN(1, 13, 0)
 #error "pikapython version must be greater than 1.13.0"
 #endif
 
+cJSON* _cjson_decode(Arg* d);
+
 int parse_json(const char* json_string,
                jsmn_parser* parser,
                jsmntok_t** tokens) {
@@ -38,15 +41,18 @@ int parse_json(const char* json_string,
     return result;
 }
 
-void PikaStdData_List_append(PikaObj* self, Arg* arg);
-void PikaStdData_Dict_set(PikaObj* self, char* key, Arg* arg);
-
-Arg* json_to_arg_recursive(jsmntok_t* t, int* index, char* json_str) {
+Arg* json_to_arg_recursive(jsmntok_t* t,
+                           int* index,
+                           char* json_str,
+                           int token_count) {
     Arg* val;
+    pika_assert(*index >= 0);
+    pika_assert(*index < token_count);
     jsmntype_t type = t[*index].type;
     switch (type) {
         case JSMN_PRIMITIVE: {
             char buff[PIKA_NAME_BUFF_SIZE] = {0};
+            pika_assert(t[*index].end - t[*index].start < PIKA_NAME_BUFF_SIZE);
             pika_platform_memcpy(buff, json_str + t[*index].start,
                                  t[*index].end - t[*index].start);
             if (strEqu(buff, "true")) {
@@ -76,12 +82,17 @@ Arg* json_to_arg_recursive(jsmntok_t* t, int* index, char* json_str) {
             int num_keys = t[*index].size;
             (*index)++;
             for (int i = 0; i < num_keys; i++) {
+                jsmntok_t* key_tok = &t[*index];
+                char* value = json_str + key_tok->start;
+                int size = key_tok->end - key_tok->start;
+                pika_assert(key_tok->type == JSMN_STRING);
                 char key[PIKA_NAME_BUFF_SIZE] = {0};
-                pika_platform_memcpy(key, json_str + t[*index].start,
-                                     t[*index].end - t[*index].start);
+                pika_assert(size < PIKA_NAME_BUFF_SIZE);
+                pika_platform_memcpy(key, value, size);
                 (*index)++;
-                Arg* val_nested = json_to_arg_recursive(t, index, json_str);
-                PikaStdData_Dict_set(ret, key, val_nested);
+                Arg* val_nested =
+                    json_to_arg_recursive(t, index, json_str, token_count);
+                objDict_set(ret, key, val_nested);
                 arg_deinit(val_nested);
                 if (i < num_keys - 1) {
                     (*index)++;
@@ -92,11 +103,15 @@ Arg* json_to_arg_recursive(jsmntok_t* t, int* index, char* json_str) {
         }
         case JSMN_ARRAY: {
             PikaObj* ret = obj_newList(NULL);
-            int num_elements = t[*index].size;
-            (*index)++;
+            jsmntok_t* key_tok = &t[*index];
+            int num_elements = key_tok->size;
+            if (num_elements > 0) {
+                (*index)++;
+            }
             for (int i = 0; i < num_elements; i++) {
-                Arg* val_nested = json_to_arg_recursive(t, index, json_str);
-                PikaStdData_List_append(ret, val_nested);
+                Arg* val_nested =
+                    json_to_arg_recursive(t, index, json_str, token_count);
+                objList_append(ret, val_nested);
                 arg_deinit(val_nested);
                 if (i < num_elements - 1) {
                     (*index)++;
@@ -120,12 +135,77 @@ Arg* _json_loads(PikaObj* self, char* json_str) {
         ret = NULL;
         goto __exit;
     }
-    jsmntok_t tokens_[50];
-    pika_platform_memcpy(tokens_, tokens, sizeof(jsmntok_t) * token_count);
-    ret = json_to_arg_recursive(tokens, &(int){0}, json_str);
+    ret = json_to_arg_recursive(tokens, &(int){0}, json_str, token_count);
 __exit:
     if (NULL != tokens) {
         free(tokens);
     }
     return ret;
 }
+
+typedef struct {
+    cJSON* jsonArray;
+} JsonListContext;
+
+int32_t jsonListEachHandle(PikaObj* self,
+                           int itemIndex,
+                           Arg* itemEach,
+                           void* context) {
+    JsonListContext* ctx = (JsonListContext*)context;
+    cJSON_AddItemToArray(ctx->jsonArray, _cjson_decode(itemEach));
+    return 0;
+}
+
+typedef struct {
+    cJSON* jsonObject;
+} JsonDictContext;
+
+int32_t jsonDictEachHandle(PikaObj* self,
+                           Arg* keyEach,
+                           Arg* valEach,
+                           void* context) {
+    JsonDictContext* ctx = (JsonDictContext*)context;
+    cJSON_AddItemToObject(ctx->jsonObject, arg_getStr(keyEach),
+                          _cjson_decode(valEach));
+    return 0;
+}
+
+cJSON* _cjson_decode(Arg* d) {
+    ArgType type = arg_getType(d);
+    if (type == ARG_TYPE_NONE) {
+        return cJSON_CreateNull();
+    } else if (type == ARG_TYPE_INT) {
+        return cJSON_CreateNumber(arg_getInt(d));
+    } else if (type == ARG_TYPE_FLOAT) {
+        return cJSON_CreateNumber(arg_getFloat(d));
+    } else if (type == ARG_TYPE_BOOL) {
+        if (arg_getBool(d)) {
+            return cJSON_CreateTrue();
+        } else {
+            return cJSON_CreateFalse();
+        }
+    } else if (type == ARG_TYPE_STRING) {
+        return cJSON_CreateString(arg_getStr(d));
+    } else if (arg_isList(d)) {
+        JsonListContext context;
+        context.jsonArray = cJSON_CreateArray();
+        objList_forEach(arg_getObj(d), jsonListEachHandle, &context);
+        return context.jsonArray;
+    } else if (arg_isDict(d)) {
+        JsonDictContext context;
+        context.jsonObject = cJSON_CreateObject();
+        objDict_forEach(arg_getObj(d), jsonDictEachHandle, &context);
+        return context.jsonObject;
+    } else {
+        return cJSON_CreateNull();
+    }
+}
+
+char* _json_dumps(PikaObj* self, Arg* d) {
+    cJSON* json = _cjson_decode(d);
+    char* ret = cJSON_Print(json);
+    char* cached = obj_cacheStr(self, ret);
+    cJSON_Delete(json);
+    pika_platform_free(ret);
+    return cached;
+}

+ 1 - 0
package/json/_json.pyi

@@ -1,2 +1,3 @@
 
 def loads(json_str: str) -> any: ...
+def dumps(d: any) -> str: ...

+ 2 - 0
package/json/jsmn.h

@@ -36,6 +36,8 @@ extern "C" {
 #define JSMN_API extern
 #endif
 
+#define JSMN_STRICT 1
+
 /**
  * JSON type identifier. Basic types are:
  * 	o Object

+ 15 - 6
package/json/json.py

@@ -1,7 +1,8 @@
 import pika_cjson as cjson
 import _json
 
-CONFIG_USING_JSMN = False
+CONFIG_USING_CJSON = False
+
 
 def _cjson_encode(cjson: cjson.cJSON):
     if cjson == None:
@@ -15,7 +16,12 @@ def _cjson_encode(cjson: cjson.cJSON):
     elif cjson.isNull():
         return None
     elif cjson.isNumber():
-        return cjson.getValueDouble()
+        num_f = cjson.getValueDouble()
+        num_i = cjson.getValueInt()
+        if num_f == num_i:
+            return num_i
+        else:
+            return num_f
     elif cjson.isString():
         return cjson.getValueString()
     elif cjson.isArray():
@@ -38,11 +44,11 @@ def _cjson_encode(cjson: cjson.cJSON):
 
 
 def loads(json: str) -> dict:
-    if CONFIG_USING_JSMN:
-        return _json.loads(json)
-    else:
+    if CONFIG_USING_CJSON:
         cj = cjson.Parse(json)
         return _cjson_encode(cj)
+    else:
+        return _json.loads(json)
 
 
 def _cjson_decode(d: dict):
@@ -74,4 +80,7 @@ def _cjson_decode(d: dict):
 
 
 def dumps(d: dict) -> str:
-    return _cjson_decode(d).print()
+    if CONFIG_USING_CJSON:
+        return _cjson_decode(d).print()
+    else:
+        return _json.dumps(d)

+ 1 - 1
package/pika_cjson/pika_cjson.c

@@ -6,7 +6,7 @@ PikaObj* pika_cjson_Parse(PikaObj* self, char* value) {
     cJSON* item = cJSON_Parse(value);
     if (NULL == item) {
         // obj_setErrorCode(self, 3);
-        __platform_printf("Error: cJSON parse failed.\r\n");
+        // __platform_printf("Error: cJSON parse failed.\r\n");
         return NULL;
     }
     PikaObj* cjson_obj = newNormalObj(New_pika_cjson_cJSON);

+ 5 - 5
package/pika_cjson/pika_cjson_cJSON.c

@@ -126,16 +126,16 @@ Arg* pika_cjson_cJSON_getValue(PikaObj* self) {
     cJSON* item = obj_getPtr(self, "item");
     int type = item->type;
     if (type == cJSON_Invalid) {
-        return arg_newNull();
+        return arg_newNone();
     }
     if (type == cJSON_False) {
-        return arg_newInt(0);
+        return arg_newBool(0);
     }
     if (type == cJSON_True) {
-        return arg_newInt(1);
+        return arg_newBool(1);
     }
     if (type == cJSON_NULL) {
-        return arg_newNull();
+        return arg_newNone();
     }
     if (type == cJSON_Number) {
         return arg_newFloat(item->valuedouble);
@@ -143,7 +143,7 @@ Arg* pika_cjson_cJSON_getValue(PikaObj* self) {
     if (type == cJSON_String) {
         return arg_newStr(item->valuestring);
     }
-    return arg_newNull();
+    return arg_newNone();
 }
 
 PikaObj* pika_cjson_cJSON_getArrayItem(PikaObj* self, int index) {

+ 2 - 1
port/linux/.vscode/launch.json

@@ -29,7 +29,8 @@
                 // "--gtest_filter=vm.range_1"
                 // "--gtest_filter=eventloop.*"
                 // "--gtest_filter=event.event_thread"
-                "--gtest_filter=_json.loads"
+                // "--gtest_filter=_json.loads"
+                "--gtest_filter=json.speed"
             ],
             "stopAtEntry": false,
             "cwd": "${workspaceFolder}",

+ 1 - 0
port/linux/package/pikascript/_json.pyi

@@ -1,2 +1,3 @@
 
 def loads(json_str: str) -> any: ...
+def dumps(d: any) -> str: ...

+ 15 - 6
port/linux/package/pikascript/json.py

@@ -1,7 +1,8 @@
 import pika_cjson as cjson
 import _json
 
-CONFIG_USING_JSMN = False
+CONFIG_USING_CJSON = False
+
 
 def _cjson_encode(cjson: cjson.cJSON):
     if cjson == None:
@@ -15,7 +16,12 @@ def _cjson_encode(cjson: cjson.cJSON):
     elif cjson.isNull():
         return None
     elif cjson.isNumber():
-        return cjson.getValueDouble()
+        num_f = cjson.getValueDouble()
+        num_i = cjson.getValueInt()
+        if num_f == num_i:
+            return num_i
+        else:
+            return num_f
     elif cjson.isString():
         return cjson.getValueString()
     elif cjson.isArray():
@@ -38,11 +44,11 @@ def _cjson_encode(cjson: cjson.cJSON):
 
 
 def loads(json: str) -> dict:
-    if CONFIG_USING_JSMN:
-        return _json.loads(json)
-    else:
+    if CONFIG_USING_CJSON:
         cj = cjson.Parse(json)
         return _cjson_encode(cj)
+    else:
+        return _json.loads(json)
 
 
 def _cjson_decode(d: dict):
@@ -74,4 +80,7 @@ def _cjson_decode(d: dict):
 
 
 def dumps(d: dict) -> str:
-    return _cjson_decode(d).print()
+    if CONFIG_USING_CJSON:
+        return _cjson_decode(d).print()
+    else:
+        return _json.dumps(d)

+ 46 - 45
port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaStdData_Dict.c

@@ -8,23 +8,15 @@
 #include "dataStrs.h"
 
 Arg* PikaStdData_Dict_get(PikaObj* self, char* key) {
-    pika_assert_obj_alive(self);
-    PikaDict* dict = obj_getPtr(self, "dict");
-    Arg* res = pikaDict_getArg(dict, key);
-    if (NULL == res) {
-        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
-        __platform_printf("KeyError: %s\n", key);
-    }
-    pika_assert_arg_alive(res);
-    return arg_copy(res);
+    return arg_copy(objDict_get(self, key));
 }
 
 void PikaStdData_Dict___init__(PikaObj* self) {
-    __vm_Dict___init__(self);
+    objDict_init(self);
 }
 
 void PikaStdData_Dict_set(PikaObj* self, char* key, Arg* arg) {
-    __vm_Dict_set(self, arg, key);
+    objDict_set(self, key, arg);
 }
 
 void PikaStdData_Dict_remove(PikaObj* self, char* key) {
@@ -133,44 +125,53 @@ char* PikaStdData_dict_keys___str__(PikaObj* self) {
     return obj_getStr(self, "_buf");
 }
 
-char* PikaStdData_Dict___str__(PikaObj* self) {
-    Arg* str_arg = arg_newStr("{");
+typedef struct {
+    Arg* buf;
+    int isFirst;
+} DictToStrContext;
 
-    PikaDict* keys = obj_getPtr(self, "_keys");
-    PikaDict* dict = obj_getPtr(self, "dict");
-    pika_assert(NULL != dict);
-    pika_assert(NULL != keys);
+int32_t dictToStrEachHandle(PikaObj* self,
+                            Arg* keyEach,
+                            Arg* valEach,
+                            void* context) {
+    DictToStrContext* ctx = (DictToStrContext*)context;
 
-    int i = 0;
-    while (PIKA_TRUE) {
-        Arg* item_key = args_getArgByIndex(&keys->super, i);
-        Arg* item_val = args_getArgByIndex(&dict->super, i);
-        if (NULL == item_key) {
-            break;
-        }
-        if (i != 0) {
-            str_arg = arg_strAppend(str_arg, ", ");
-        }
-        char* key_str = builtins_str(self, item_key);
-        str_arg = arg_strAppend(str_arg, "'");
-        str_arg = arg_strAppend(str_arg, key_str);
-        str_arg = arg_strAppend(str_arg, "'");
-        str_arg = arg_strAppend(str_arg, ": ");
-
-        char* val_str = builtins_str(self, item_val);
-        if (arg_getType(item_val) == ARG_TYPE_STRING) {
-            str_arg = arg_strAppend(str_arg, "'");
-        }
-        str_arg = arg_strAppend(str_arg, val_str);
-        if (arg_getType(item_val) == ARG_TYPE_STRING) {
-            str_arg = arg_strAppend(str_arg, "'");
-        }
-        i++;
+    // 判断是否需要在字符串前添加逗号
+    if (!ctx->isFirst) {
+        ctx->buf = arg_strAppend(ctx->buf, ", ");
+    } else {
+        ctx->isFirst = 0;
     }
 
-    str_arg = arg_strAppend(str_arg, "}");
-    obj_setStr(self, "_buf", arg_getStr(str_arg));
-    arg_deinit(str_arg);
+    // 将键值对添加到字符串
+    ctx->buf = arg_strAppend(ctx->buf, "'");
+    ctx->buf = arg_strAppend(ctx->buf, builtins_str(self, keyEach));
+    ctx->buf = arg_strAppend(ctx->buf, "'");
+    ctx->buf = arg_strAppend(ctx->buf, ": ");
+    if (arg_getType(valEach) == ARG_TYPE_STRING) {
+        ctx->buf = arg_strAppend(ctx->buf, "'");
+    }
+    ctx->buf = arg_strAppend(ctx->buf, builtins_str(self, valEach));
+    if (arg_getType(valEach) == ARG_TYPE_STRING) {
+        ctx->buf = arg_strAppend(ctx->buf, "'");
+    }
+
+    return 0;
+}
+
+char* PikaStdData_Dict___str__(PikaObj* self) {
+    // 初始化上下文
+    DictToStrContext context;
+    context.buf = arg_newStr("{");
+    context.isFirst = 1;
+
+    // 使用 objDict_forEach 遍历字典
+    objDict_forEach(self, dictToStrEachHandle, &context);
+
+    // 将字符串添加到结果中并返回
+    context.buf = arg_strAppend(context.buf, "}");
+    obj_setStr(self, "_buf", arg_getStr(context.buf));
+    arg_deinit(context.buf);
     return obj_getStr(self, "_buf");
 }
 

+ 38 - 31
port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaStdData_List.c

@@ -5,15 +5,11 @@
 #include "dataStrs.h"
 
 void PikaStdData_List_append(PikaObj* self, Arg* arg) {
-    __vm_List_append(self, arg);
+    objList_append(self, arg);
 }
 
 void PikaStdData_List_set(PikaObj* self, int i, Arg* arg) {
-    PikaList* list = obj_getPtr(self, "list");
-    if (PIKA_RES_OK != pikaList_setArg(list, i, arg)) {
-        obj_setErrorCode(self, 1);
-        obj_setSysOut(self, "Error: index exceeded lengh of list.");
-    }
+    return objList_set(self, i, arg);
 }
 
 void PikaStdData_List___setitem__(PikaObj* self, Arg* __key, Arg* __val) {
@@ -22,37 +18,48 @@ void PikaStdData_List___setitem__(PikaObj* self, Arg* __key, Arg* __val) {
 }
 
 void PikaStdData_List___init__(PikaObj* self) {
-    __vm_List___init__(self);
+    objList_init(self);
 }
 
 char* builtins_str(PikaObj* self, Arg* arg);
-char* PikaStdData_List___str__(PikaObj* self) {
-    Arg* str_arg = arg_newStr("[");
-    PikaList* list = obj_getPtr(self, "list");
+typedef struct {
+    Arg* buf;
+    int count;
+} ListToStrContext;
 
-    int i = 0;
-    while (PIKA_TRUE) {
-        Arg* item = pikaList_getArg(list, i);
-        if (NULL == item) {
-            break;
-        }
-        if (i != 0) {
-            str_arg = arg_strAppend(str_arg, ", ");
-        }
-        char* item_str = builtins_str(self, item);
-        if (arg_getType(item) == ARG_TYPE_STRING) {
-            str_arg = arg_strAppend(str_arg, "'");
-        }
-        str_arg = arg_strAppend(str_arg, item_str);
-        if (arg_getType(item) == ARG_TYPE_STRING) {
-            str_arg = arg_strAppend(str_arg, "'");
-        }
-        i++;
+int32_t listToStrEachHandle(PikaObj* self,
+                            int itemIndex,
+                            Arg* itemEach,
+                            void* context) {
+    ListToStrContext* ctx = (ListToStrContext*)context;
+
+    char* item_str = builtins_str(self, itemEach);
+    if (ctx->count != 0) {
+        ctx->buf = arg_strAppend(ctx->buf, ", ");
+    }
+    if (arg_getType(itemEach) == ARG_TYPE_STRING) {
+        ctx->buf = arg_strAppend(ctx->buf, "'");
     }
+    ctx->buf = arg_strAppend(ctx->buf, item_str);
+    if (arg_getType(itemEach) == ARG_TYPE_STRING) {
+        ctx->buf = arg_strAppend(ctx->buf, "'");
+    }
+
+    ctx->count++;
+
+    return 0;
+}
+
+char* PikaStdData_List___str__(PikaObj* self) {
+    ListToStrContext context;
+    context.buf = arg_newStr("[");
+    context.count = 0;
+
+    objList_forEach(self, listToStrEachHandle, &context);
 
-    str_arg = arg_strAppend(str_arg, "]");
-    obj_setStr(self, "_buf", arg_getStr(str_arg));
-    arg_deinit(str_arg);
+    context.buf = arg_strAppend(context.buf, "]");
+    obj_setStr(self, "_buf", arg_getStr(context.buf));
+    arg_deinit(context.buf);
     return obj_getStr(self, "_buf");
 }
 

+ 41 - 32
port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaStdData_Tuple.c

@@ -3,17 +3,15 @@
 #include "dataStrs.h"
 
 int PikaStdData_Tuple_len(PikaObj* self) {
-    PikaList* list = obj_getPtr(self, "list");
-    return pikaList_getSize(list);
+    return objList_getSize(self);
 }
 
 Arg* PikaStdData_Tuple_get(PikaObj* self, int i) {
-    PikaList* list = obj_getPtr(self, "list");
-    return arg_copy(pikaList_getArg(list, i));
+    return objList_get(self, i);
 }
 
 void PikaStdData_Tuple___init__(PikaObj* self) {
-    __vm_List___init__(self);
+    objList_init(self);
 }
 
 Arg* PikaStdData_Tuple___iter__(PikaObj* self) {
@@ -51,37 +49,48 @@ void PikaStdData_Tuple___del__(PikaObj* self) {
 }
 
 char* builtins_str(PikaObj* self, Arg* arg);
+typedef struct {
+    Arg* buf;
+    int count;
+} TupleToStrContext;
+
+int32_t tupleToStrEachHandle(PikaObj* self,
+                             int itemIndex,
+                             Arg* itemEach,
+                             void* context) {
+    TupleToStrContext* ctx = (TupleToStrContext*)context;
+
+    char* item_str = builtins_str(self, itemEach);
+    if (ctx->count != 0) {
+        ctx->buf = arg_strAppend(ctx->buf, ", ");
+    }
+    if (arg_getType(itemEach) == ARG_TYPE_STRING) {
+        ctx->buf = arg_strAppend(ctx->buf, "'");
+    }
+    ctx->buf = arg_strAppend(ctx->buf, item_str);
+    if (arg_getType(itemEach) == ARG_TYPE_STRING) {
+        ctx->buf = arg_strAppend(ctx->buf, "'");
+    }
+
+    ctx->count++;
+
+    return 0;
+}
+
 char* PikaStdData_Tuple___str__(PikaObj* self) {
-    Arg* str_arg = arg_newStr("(");
-    PikaList* list = obj_getPtr(self, "list");
+    TupleToStrContext context;
+    context.buf = arg_newStr("(");
+    context.count = 0;
 
-    int i = 0;
-    while (PIKA_TRUE) {
-        Arg* item = pikaList_getArg(list, i);
-        if (NULL == item) {
-            if (i == 1) {
-                // single tuple
-                str_arg = arg_strAppend(str_arg, ",");
-            }
-            break;
-        }
-        if (i != 0) {
-            str_arg = arg_strAppend(str_arg, ", ");
-        }
-        char* item_str = builtins_str(self, item);
-        if (arg_getType(item) == ARG_TYPE_STRING) {
-            str_arg = arg_strAppend(str_arg, "'");
-        }
-        str_arg = arg_strAppend(str_arg, item_str);
-        if (arg_getType(item) == ARG_TYPE_STRING) {
-            str_arg = arg_strAppend(str_arg, "'");
-        }
-        i++;
+    objTuple_forEach(self, tupleToStrEachHandle, &context);
+
+    if (context.count == 1) {
+        context.buf = arg_strAppend(context.buf, ",");
     }
 
-    str_arg = arg_strAppend(str_arg, ")");
-    obj_setStr(self, "_buf", arg_getStr(str_arg));
-    arg_deinit(str_arg);
+    context.buf = arg_strAppend(context.buf, ")");
+    obj_setStr(self, "_buf", arg_getStr(context.buf));
+    arg_deinit(context.buf);
     return obj_getStr(self, "_buf");
 }
 

+ 95 - 15
port/linux/package/pikascript/pikascript-lib/json/_json.c

@@ -1,10 +1,13 @@
 #include "_json.h"
+#include "../pikascript-lib/pika_cjson/cJSON.h"
 #include "jsmn.h"
 
 #if !PIKASCRIPT_VERSION_REQUIRE_MINIMUN(1, 13, 0)
 #error "pikapython version must be greater than 1.13.0"
 #endif
 
+cJSON* _cjson_decode(Arg* d);
+
 int parse_json(const char* json_string,
                jsmn_parser* parser,
                jsmntok_t** tokens) {
@@ -38,15 +41,18 @@ int parse_json(const char* json_string,
     return result;
 }
 
-void PikaStdData_List_append(PikaObj* self, Arg* arg);
-void PikaStdData_Dict_set(PikaObj* self, char* key, Arg* arg);
-
-Arg* json_to_arg_recursive(jsmntok_t* t, int* index, char* json_str) {
+Arg* json_to_arg_recursive(jsmntok_t* t,
+                           int* index,
+                           char* json_str,
+                           int token_count) {
     Arg* val;
+    pika_assert(*index >= 0);
+    pika_assert(*index < token_count);
     jsmntype_t type = t[*index].type;
     switch (type) {
         case JSMN_PRIMITIVE: {
             char buff[PIKA_NAME_BUFF_SIZE] = {0};
+            pika_assert(t[*index].end - t[*index].start < PIKA_NAME_BUFF_SIZE);
             pika_platform_memcpy(buff, json_str + t[*index].start,
                                  t[*index].end - t[*index].start);
             if (strEqu(buff, "true")) {
@@ -76,12 +82,17 @@ Arg* json_to_arg_recursive(jsmntok_t* t, int* index, char* json_str) {
             int num_keys = t[*index].size;
             (*index)++;
             for (int i = 0; i < num_keys; i++) {
+                jsmntok_t* key_tok = &t[*index];
+                char* value = json_str + key_tok->start;
+                int size = key_tok->end - key_tok->start;
+                pika_assert(key_tok->type == JSMN_STRING);
                 char key[PIKA_NAME_BUFF_SIZE] = {0};
-                pika_platform_memcpy(key, json_str + t[*index].start,
-                                     t[*index].end - t[*index].start);
+                pika_assert(size < PIKA_NAME_BUFF_SIZE);
+                pika_platform_memcpy(key, value, size);
                 (*index)++;
-                Arg* val_nested = json_to_arg_recursive(t, index, json_str);
-                PikaStdData_Dict_set(ret, key, val_nested);
+                Arg* val_nested =
+                    json_to_arg_recursive(t, index, json_str, token_count);
+                objDict_set(ret, key, val_nested);
                 arg_deinit(val_nested);
                 if (i < num_keys - 1) {
                     (*index)++;
@@ -92,11 +103,15 @@ Arg* json_to_arg_recursive(jsmntok_t* t, int* index, char* json_str) {
         }
         case JSMN_ARRAY: {
             PikaObj* ret = obj_newList(NULL);
-            int num_elements = t[*index].size;
-            (*index)++;
+            jsmntok_t* key_tok = &t[*index];
+            int num_elements = key_tok->size;
+            if (num_elements > 0) {
+                (*index)++;
+            }
             for (int i = 0; i < num_elements; i++) {
-                Arg* val_nested = json_to_arg_recursive(t, index, json_str);
-                PikaStdData_List_append(ret, val_nested);
+                Arg* val_nested =
+                    json_to_arg_recursive(t, index, json_str, token_count);
+                objList_append(ret, val_nested);
                 arg_deinit(val_nested);
                 if (i < num_elements - 1) {
                     (*index)++;
@@ -120,12 +135,77 @@ Arg* _json_loads(PikaObj* self, char* json_str) {
         ret = NULL;
         goto __exit;
     }
-    jsmntok_t tokens_[50];
-    pika_platform_memcpy(tokens_, tokens, sizeof(jsmntok_t) * token_count);
-    ret = json_to_arg_recursive(tokens, &(int){0}, json_str);
+    ret = json_to_arg_recursive(tokens, &(int){0}, json_str, token_count);
 __exit:
     if (NULL != tokens) {
         free(tokens);
     }
     return ret;
 }
+
+typedef struct {
+    cJSON* jsonArray;
+} JsonListContext;
+
+int32_t jsonListEachHandle(PikaObj* self,
+                           int itemIndex,
+                           Arg* itemEach,
+                           void* context) {
+    JsonListContext* ctx = (JsonListContext*)context;
+    cJSON_AddItemToArray(ctx->jsonArray, _cjson_decode(itemEach));
+    return 0;
+}
+
+typedef struct {
+    cJSON* jsonObject;
+} JsonDictContext;
+
+int32_t jsonDictEachHandle(PikaObj* self,
+                           Arg* keyEach,
+                           Arg* valEach,
+                           void* context) {
+    JsonDictContext* ctx = (JsonDictContext*)context;
+    cJSON_AddItemToObject(ctx->jsonObject, arg_getStr(keyEach),
+                          _cjson_decode(valEach));
+    return 0;
+}
+
+cJSON* _cjson_decode(Arg* d) {
+    ArgType type = arg_getType(d);
+    if (type == ARG_TYPE_NONE) {
+        return cJSON_CreateNull();
+    } else if (type == ARG_TYPE_INT) {
+        return cJSON_CreateNumber(arg_getInt(d));
+    } else if (type == ARG_TYPE_FLOAT) {
+        return cJSON_CreateNumber(arg_getFloat(d));
+    } else if (type == ARG_TYPE_BOOL) {
+        if (arg_getBool(d)) {
+            return cJSON_CreateTrue();
+        } else {
+            return cJSON_CreateFalse();
+        }
+    } else if (type == ARG_TYPE_STRING) {
+        return cJSON_CreateString(arg_getStr(d));
+    } else if (arg_isList(d)) {
+        JsonListContext context;
+        context.jsonArray = cJSON_CreateArray();
+        objList_forEach(arg_getObj(d), jsonListEachHandle, &context);
+        return context.jsonArray;
+    } else if (arg_isDict(d)) {
+        JsonDictContext context;
+        context.jsonObject = cJSON_CreateObject();
+        objDict_forEach(arg_getObj(d), jsonDictEachHandle, &context);
+        return context.jsonObject;
+    } else {
+        return cJSON_CreateNull();
+    }
+}
+
+char* _json_dumps(PikaObj* self, Arg* d) {
+    cJSON* json = _cjson_decode(d);
+    char* ret = cJSON_Print(json);
+    char* cached = obj_cacheStr(self, ret);
+    cJSON_Delete(json);
+    pika_platform_free(ret);
+    return cached;
+}

+ 2 - 0
port/linux/package/pikascript/pikascript-lib/json/jsmn.h

@@ -36,6 +36,8 @@ extern "C" {
 #define JSMN_API extern
 #endif
 
+#define JSMN_STRICT 1
+
 /**
  * JSON type identifier. Basic types are:
  * 	o Object

+ 2 - 2
port/linux/package/pikascript/pikascript-lib/pika_cjson/pika_cjson_cJSON.c

@@ -129,10 +129,10 @@ Arg* pika_cjson_cJSON_getValue(PikaObj* self) {
         return arg_newNone();
     }
     if (type == cJSON_False) {
-        return arg_newInt(0);
+        return arg_newBool(0);
     }
     if (type == cJSON_True) {
-        return arg_newInt(1);
+        return arg_newBool(1);
     }
     if (type == cJSON_NULL) {
         return arg_newNone();

+ 121 - 2
src/PikaObj.c

@@ -2618,6 +2618,10 @@ int obj_importModule(PikaObj* self, char* module_name) {
     return 0;
 }
 
+PikaObj* arg_getObj(Arg* self) {
+    return (PikaObj*)arg_getPtr(self);
+}
+
 char* obj_toStr(PikaObj* self) {
     /* check method arg */
     Arg* aMethod = obj_getMethodArgWithFullPath(self, "__str__");
@@ -2844,6 +2848,7 @@ void* obj_getStruct(PikaObj* self, char* name) {
 }
 
 char* obj_cacheStr(PikaObj* self, char* str) {
+    pika_assert(self != NULL);
     return args_cacheStr(self->list, str);
 }
 
@@ -2977,6 +2982,8 @@ pika_bool builtins_bool(PikaObj* self, Arg* arg) {
 }
 
 char* builtins_str(PikaObj* self, Arg* arg) {
+    pika_assert(NULL != arg);
+    pika_assert(NULL != self);
     // if (arg_getType(arg) == ARG_TYPE_BYTES) {
     //     return obj_cacheStr(self, (char*)arg_getBytes(arg));
     // }
@@ -3104,6 +3111,27 @@ Arg* builtins___setitem__(PikaObj* self, Arg* obj, Arg* key, Arg* val) {
     return NULL;
 }
 
+pika_bool arg_isList(Arg* arg) {
+    if (!arg_isObject(arg)) {
+        return pika_false;
+    }
+    return arg_getObj(arg)->constructor == New_PikaStdData_List;
+}
+
+pika_bool arg_isDict(Arg* arg) {
+    if (!arg_isObject(arg)) {
+        return pika_false;
+    }
+    return arg_getObj(arg)->constructor == New_PikaStdData_Dict;
+}
+
+pika_bool arg_isTuple(Arg* arg) {
+    if (!arg_isObject(arg)) {
+        return pika_false;
+    }
+    return arg_getObj(arg)->constructor == New_PikaStdData_Tuple;
+}
+
 int builtins_len(PikaObj* self, Arg* arg) {
     if (ARG_TYPE_STRING == arg_getType(arg)) {
         return strGetSize(arg_getStr(arg));
@@ -3362,7 +3390,7 @@ int32_t __dir_each(Arg* argEach, void* context) {
         char* method_name =
             methodArg_getName(argEach, name_buff, sizeof(name_buff));
         Arg* arg_str = arg_newStr(method_name);
-        __vm_List_append(list, arg_str);
+        objList_append(list, arg_str);
         arg_deinit(arg_str);
     }
     return 0;
@@ -3377,7 +3405,7 @@ PikaObj* builtins_dir(PikaObj* self, Arg* arg) {
     PikaObj* obj = arg_getPtr(arg);
     PikaObj* New_PikaStdData_List(Args * args);
     PikaObj* list = newNormalObj(New_PikaStdData_List);
-    __vm_List___init__(list);
+    objList_init(list);
     Args* context = New_args(NULL);
     args_setPtr(context, "list", list);
     args_foreach(obj->list, __dir_each, context);
@@ -3845,3 +3873,94 @@ char* builtins_bytearray_decode(PikaObj* self) {
     arg_deinit(str_arg);
     return obj_getStr(self, "_buf");
 }
+
+int objList_getSize(PikaObj* self) {
+    PikaList* list = obj_getPtr(self, "list");
+    return pikaList_getSize(list);
+}
+
+void objList_set(PikaObj* self, int i, Arg* arg) {
+    PikaList* list = obj_getPtr(self, "list");
+    if (PIKA_RES_OK != pikaList_setArg(list, i, arg)) {
+        obj_setErrorCode(self, 1);
+        obj_setSysOut(self, "Error: index exceeded lengh of list.");
+    }
+}
+
+Arg* objList_get(PikaObj* self, int i) {
+    PikaList* list = obj_getPtr(self, "list");
+    return arg_copy(pikaList_getArg(list, i));
+}
+
+Arg* objDict_get(PikaObj* self, char* key) {
+    pika_assert_obj_alive(self);
+    PikaDict* dict = obj_getPtr(self, "dict");
+    Arg* res = pikaDict_getArg(dict, key);
+    if (NULL == res) {
+        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
+        __platform_printf("KeyError: %s\n", key);
+    }
+    pika_assert_arg_alive(res);
+    return res;
+}
+
+void objDict_set(PikaObj* self, char* key, Arg* arg) {
+    PikaDict* dict = obj_getPtr(self, "dict");
+    PikaDict* keys = obj_getPtr(self, "_keys");
+    Arg* arg_key = arg_setStr(NULL, key, key);
+    Arg* arg_new = arg_copy(arg);
+    arg_setName(arg_new, key);
+    pikaDict_setArg(dict, arg_new);
+    pikaDict_setArg(keys, arg_key);
+}
+
+int32_t objDict_forEach(PikaObj* self,
+                        int32_t (*eachHandle)(PikaObj* self,
+                                              Arg* keyEach,
+                                              Arg* valEach,
+                                              void* context),
+                        void* context) {
+    PikaDict* keys = obj_getPtr(self, "_keys");
+    PikaDict* dict = obj_getPtr(self, "dict");
+    pika_assert(NULL != dict);
+    pika_assert(NULL != keys);
+    int i = 0;
+    while (1) {
+        Arg* item_key = args_getArgByIndex(&keys->super, i);
+        Arg* item_val = args_getArgByIndex(&dict->super, i);
+        if (NULL == item_key) {
+            break;
+        }
+        // Call the handle function on each key-value pair
+        if (eachHandle(self, item_key, item_val, context) != 0) {
+            return -1;
+        }
+        i++;
+    }
+    return 0;
+}
+
+int32_t objList_forEach(PikaObj* self,
+                        int32_t (*eachHandle)(PikaObj* self,
+                                              int itemIndex,
+                                              Arg* itemEach,
+                                              void* context),
+                        void* context) {
+    PikaList* list = obj_getPtr(self, "list");
+    int i = 0;
+    while (PIKA_TRUE) {
+        Arg* item = pikaList_getArg(list, i);
+        if (NULL == item) {
+            break;
+        }
+        // Call the handler function with the item.
+        int32_t result = eachHandle(self, i, item, context);
+        if (result != 0) {
+            // If the handler function returns a non-zero value,
+            // stop the iteration.
+            return result;
+        }
+        i++;
+    }
+    return 0;
+}

+ 45 - 12
src/PikaObj.h

@@ -457,6 +457,11 @@ PikaObj* newNormalObj(NewFun newObjFun);
 Arg* arg_setRef(Arg* self, char* name, PikaObj* obj);
 Arg* arg_setObj(Arg* self, char* name, PikaObj* obj);
 
+PikaObj* arg_getObj(Arg* self);
+pika_bool arg_isList(Arg* arg);
+pika_bool arg_isDict(Arg* arg);
+pika_bool arg_isTuple(Arg* arg);
+
 static inline void arg_setObjFlag(Arg* self, uint8_t flag) {
     if (!arg_isObject(self)) {
         return;
@@ -509,26 +514,26 @@ enum shellCTRL obj_runChar(PikaObj* self, char inputChar);
 typedef PikaObj PikaEventListener;
 
 void pika_eventListener_registEvent(PikaEventListener* self,
-                                   uint32_t eventId,
-                                   PikaObj* eventHandleObj);
+                                    uint32_t eventId,
+                                    PikaObj* eventHandleObj);
 
 void pika_eventListener_removeEvent(PikaEventListener* self, uint32_t eventId);
 
 void _do_pika_eventListener_send(PikaEventListener* self,
-                                uint32_t eventId,
-                                Arg* eventData,
-                                pika_bool pickupWhenNoVM);
+                                 uint32_t eventId,
+                                 Arg* eventData,
+                                 pika_bool pickupWhenNoVM);
 
 void pika_eventListener_sendSignal(PikaEventListener* self,
-                                  uint32_t eventId,
-                                  int eventSignal);
+                                   uint32_t eventId,
+                                   int eventSignal);
 
 void pika_eventListener_send(PikaEventListener* self,
-                            uint32_t eventId,
-                            Arg* eventData);
+                             uint32_t eventId,
+                             Arg* eventData);
 
 PikaObj* pika_eventListener_getEventHandleObj(PikaEventListener* self,
-                                             uint32_t eventId);
+                                              uint32_t eventId);
 
 void pika_eventListener_init(PikaEventListener** p_self);
 void pika_eventListener_deinit(PikaEventListener** p_self);
@@ -680,8 +685,8 @@ Arg* __eventListener_runEvent(PikaEventListener* lisener,
                               Arg* eventData);
 
 Arg* pika_eventListener_sendSignalAwaitResult(PikaEventListener* self,
-                                             uint32_t eventId,
-                                             int eventSignal);
+                                              uint32_t eventId,
+                                              int eventSignal);
 
 #define COLOR_RED "\x1b[31m"
 #define COLOR_GREEN "\x1b[32m"
@@ -738,6 +743,34 @@ int pika_GIL_ENTER(void);
 /* builtins */
 PikaObj* New_builtins(Args* args);
 
+int objList_getSize(PikaObj* self);
+void objList_set(PikaObj* self, int i, Arg* arg);
+Arg* objList_get(PikaObj* self, int i);
+void objList_append(PikaObj* self, Arg* arg);
+void objList_init(PikaObj* self);
+void objDict_init(PikaObj* self);
+int32_t objList_forEach(PikaObj* self,
+                        int32_t (*eachHandle)(PikaObj* self,
+                                              int itemIndex,
+                                              Arg* itemEach,
+                                              void* context),
+                        void* context);
+
+#define objTuple_getSize objList_getSize
+#define objTuple_get objList_get
+#define objTuple_set objList_set
+#define objTuple_forEach objList_forEach
+#define objTuple_init objList_init
+
+Arg* objDict_get(PikaObj* self, char* key);
+void objDict_set(PikaObj* self, char* key, Arg* arg);
+int32_t objDict_forEach(PikaObj* self,
+                        int32_t (*eachHandle)(PikaObj* self,
+                                              Arg* keyEach,
+                                              Arg* valEach,
+                                              void* context),
+                        void* context);
+
 #endif
 #ifdef __cplusplus
 }

+ 15 - 33
src/PikaVM.c

@@ -781,11 +781,11 @@ Arg* _vm_slice(VMState* vm,
         if (oArg->constructor == New_PikaStdData_List ||
             oArg->constructor == New_PikaStdData_Tuple) {
             PikaObj* oSliced = newNormalObj((NewFun)oArg->constructor);
-            __vm_List___init__(oSliced);
+            objList_init(oSliced);
             for (int i = iStart; i < iEnd; i++) {
                 Arg* aIndex = arg_newInt(i);
                 Arg* aItem = _vm_get(vm, self, aIndex, aObj);
-                __vm_List_append(oSliced, aItem);
+                objList_append(oSliced, aItem);
                 arg_deinit(aItem);
                 arg_deinit(aIndex);
             }
@@ -1638,16 +1638,6 @@ exit:
     return f.n_arg;
 }
 
-void __vm_List_append(PikaObj* self, Arg* arg) {
-    PikaList* list = obj_getPtr(self, "list");
-    pikaList_append(list, arg);
-}
-
-void __vm_List___init__(PikaObj* self) {
-    PikaList* list = New_pikaList();
-    obj_setPtr(self, "list", list);
-}
-
 #if PIKA_BUILTIN_STRUCT_ENABLE
 PikaObj* New_PikaStdData_List(Args* args);
 PikaObj* New_PikaStdData_Tuple(Args* args);
@@ -1660,7 +1650,7 @@ static Arg* _vm_create_list_or_tuple(PikaObj* self,
     NewFun constructor = is_list ? New_PikaStdData_List : New_PikaStdData_Tuple;
     uint8_t n_arg = VMState_getInputArgNum(vm);
     PikaObj* list = newNormalObj(constructor);
-    __vm_List___init__(list);
+    objList_init(list);
     Stack stack = {0};
     stack_init(&stack);
     /* load to local stack to change sort */
@@ -1672,7 +1662,7 @@ static Arg* _vm_create_list_or_tuple(PikaObj* self,
     for (int i = 0; i < n_arg; i++) {
         Arg* arg = stack_popArg_alloc(&stack);
         pika_assert(arg != NULL);
-        __vm_List_append(list, arg);
+        objList_append(list, arg);
         arg_deinit(arg);
     }
     stack_deinit(&stack);
@@ -1696,23 +1686,13 @@ static Arg* VM_instruction_handler_TPL(PikaObj* self,
     return _vm_create_list_or_tuple(self, vm, pika_false);
 }
 
-void __vm_Dict___init__(PikaObj* self) {
+void objDict_init(PikaObj* self) {
     PikaDict* dict = New_pikaDict();
     PikaDict* keys = New_pikaDict();
     obj_setPtr(self, "dict", dict);
     obj_setPtr(self, "_keys", keys);
 }
 
-void __vm_Dict_set(PikaObj* self, Arg* arg, char* key) {
-    PikaDict* dict = obj_getPtr(self, "dict");
-    PikaDict* keys = obj_getPtr(self, "_keys");
-    Arg* arg_key = arg_setStr(NULL, key, key);
-    Arg* arg_new = arg_copy(arg);
-    arg_setName(arg_new, key);
-    pikaDict_setArg(dict, arg_new);
-    pikaDict_setArg(keys, arg_key);
-}
-
 #if PIKA_BUILTIN_STRUCT_ENABLE
 PikaObj* New_PikaStdData_Dict(Args* args);
 #endif
@@ -1724,7 +1704,7 @@ static Arg* VM_instruction_handler_DCT(PikaObj* self,
 #if PIKA_BUILTIN_STRUCT_ENABLE
     uint8_t n_arg = VMState_getInputArgNum(vm);
     PikaObj* dict = newNormalObj(New_PikaStdData_Dict);
-    __vm_Dict___init__(dict);
+    objDict_init(dict);
     Stack stack = {0};
     stack_init(&stack);
     /* load to local stack to change sort */
@@ -1735,7 +1715,7 @@ static Arg* VM_instruction_handler_DCT(PikaObj* self,
     for (int i = 0; i < n_arg / 2; i++) {
         Arg* key_arg = stack_popArg_alloc(&stack);
         Arg* val_arg = stack_popArg_alloc(&stack);
-        __vm_Dict_set(dict, val_arg, arg_getStr(key_arg));
+        objDict_set(dict, arg_getStr(key_arg), val_arg);
         arg_deinit(key_arg);
         arg_deinit(val_arg);
     }
@@ -2736,16 +2716,18 @@ static void _OPT_POW(OperatorInfo* op) {
     if (op->t1 == ARG_TYPE_INT && op->t2 == ARG_TYPE_INT) {
         int lhs = op->i1;
         int rhs = op->i2;
-        if(rhs < 0) rhs = -rhs;
+        if (rhs < 0)
+            rhs = -rhs;
         int64_t ret = 1;
-        while(rhs){
-            if(rhs & 1) ret *= lhs;
+        while (rhs) {
+            if (rhs & 1)
+                ret *= lhs;
             lhs *= lhs;
             rhs >>= 1;
         }
-        if(op->i2 < 0){
-            op->res = arg_setFloat(op->res, "", 1.0/ret);
-        }else{
+        if (op->i2 < 0) {
+            op->res = arg_setFloat(op->res, "", 1.0 / ret);
+        } else {
             op->res = arg_setInt(op->res, "", ret);
         }
         return;

+ 0 - 4
src/PikaVM.h

@@ -362,10 +362,6 @@ void _do_byteCodeFrame_loadByteCode(ByteCodeFrame* self,
                                     uint8_t* bytes,
                                     pika_bool is_const);
 Arg* _vm_get(VMState* vm, PikaObj* self, Arg* key, Arg* obj);
-void __vm_List_append(PikaObj* self, Arg* arg);
-void __vm_List___init__(PikaObj* self);
-void __vm_Dict_set(PikaObj* self, Arg* arg, char* key);
-void __vm_Dict___init__(PikaObj* self);
 VM_SIGNAL_CTRL VMSignal_getCtrl(void);
 void pika_vm_exit(void);
 void pika_vmSignal_setCtrlClear(void);

+ 6 - 5
src/dataArg.c

@@ -165,11 +165,11 @@ static Arg* arg_create(char* name,
     return arg_create_hash(nameHash, type, content, size, next);
 }
 
-static Arg* arg_set(Arg* self,
-                    char* name,
-                    ArgType type,
-                    uint8_t* content,
-                    uint32_t size) {
+Arg* arg_set(Arg* self,
+             char* name,
+             ArgType type,
+             uint8_t* content,
+             uint32_t size) {
     Hash nameHash = hash_time33(name);
     return _arg_set_hash(self, nameHash, type, content, size, NULL);
 }
@@ -489,6 +489,7 @@ void* arg_getPtr(Arg* self) {
     }
     return *(void**)arg_getContent(self);
 }
+
 char* arg_getStr(Arg* self) {
     return (char*)arg_getContent(self);
 }

+ 10 - 0
src/dataArgs.c

@@ -637,6 +637,16 @@ size_t pikaList_getSize(PikaList* self) {
     return args_getInt(&self->super, "top");
 }
 
+void objList_append(PikaObj* self, Arg* arg) {
+    PikaList* list = obj_getPtr(self, "list");
+    pikaList_append(list, arg);
+}
+
+void objList_init(PikaObj* self) {
+    PikaList* list = New_pikaList();
+    obj_setPtr(self, "list", list);
+}
+
 void pikaList_reverse(PikaList* self) {
     pika_assert(NULL != self);
     int top = pikaList_getSize(self);

+ 17 - 0
test/json-test.cpp

@@ -39,6 +39,23 @@ TEST_RUN_SINGLE_FILE_PASS(_json, loads, "test/python/json/_json_loads.py")
 
 TEST_RUN_SINGLE_FILE(json, speed, "test/python/json/json_speed.py")
 
+TEST(json, speed_diff) {
+    g_PikaMemInfo.heapUsedMax = 0;
+    PikaObj* pikaMain = newRootObj("pikaMain", New_PikaMain);
+    extern unsigned char pikaModules_py_a[];
+    obj_linkLibrary(pikaMain, pikaModules_py_a);
+    /* run */
+    __platform_printf("BEGIN\r\n");
+    pikaVM_runSingleFile(pikaMain, "test/python/json/json_speed.py");
+    /* assert */
+    char* str_res_cjson = obj_getStr(pikaMain, "str_res_cjson");
+    char* str_res_jsmn = obj_getStr(pikaMain, "str_res_jsmn");
+    ASSERT_STREQ(str_res_cjson, str_res_jsmn);
+    /* deinit */
+    obj_deinit(pikaMain);
+    EXPECT_EQ(pikaMemNow(), 0);
+}
+
 #endif
 #endif
 

+ 52 - 13
test/python/json/json_speed.py

@@ -1,22 +1,61 @@
 import json
 import time
 
-json.CONFIG_USING_JSMN = False
+dict_test = {'widget0': {"type": "div", "attributes": {"class": "container", "style": {"width": 240, "height": 240, "margin": 0, "padding": 0, "border-radius": 0, "border-width": 0, "border-color": "red", "background-color": 37864}}, "nodes": [{"type": "text", "attributes": {"font-size": "30", "class": "result-text", "style": {"top": 5, "left": 5, "width": 220, "text-align": "right", "height": 30, "color": "white", "text-overflow": "longbreak", "border-width": 0, "border-color": "red", "background-color": "transparent"}}, "nodes": [], "bindings":[{"attrName": "text", "key": "result", "isText": True}], "events": [], "value":"0", "widgetName":"widget1"}, {"type": "div", "attributes": {"class": "key-wrapper", "onclick": "onclick", "style": {"width": 60, "height": 50, "border-width": 0, "border-color": "red", "background-color": "transparent", "top": 40, "left": 10}}, "nodes": [{"type": "text", "attributes": {"font-size": "30", "class": "key", "style": {"left": 0, "top": 0, "width": 50, "height": 40, "margin": 0, "padding": 0, "color": "white", "font-size": 30, "text-align": "center", "background-color": "transparent"}}, "nodes": [], "bindings":[], "events":[], "value":"1", "widgetName":"widget3"}], "bindings":[], "events":[{"onclick": "onclick"}], "widgetName": "widget2"}, {"type": "div", "attributes": {"class": "key-wrapper", "onclick": "onclick", "style": {"width": 60, "height": 50, "border-width": 0, "border-color": "red", "background-color": "transparent", "top": 40, "left": 60}}, "nodes": [{"type": "text", "attributes": {"font-size": "30", "class": "key", "style": {
+    "left": 0, "top": 0, "width": 50, "height": 40, "margin": 0, "padding": 0, "color": "white", "font-size": 30, "text-align": "center", "background-color": "transparent"}}, "nodes": [], "bindings":[], "events":[], "value":"2", "widgetName":"widget5"}], "bindings":[], "events":[{"onclick": "onclick"}], "widgetName": "widget4"}, {"type": "div", "attributes": {"class": "key-wrapper", "onclick": "onclick", "style": {"width": 60, "height": 50, "border-width": 0, "border-color": "red", "background-color": "transparent", "top": 40, "left": 110}}, "nodes": [{"type": "text", "attributes": {"font-size": "30", "class": "key", "style": {"left": 0, "top": 0, "width": 50, "height": 40, "margin": 0, "padding": 0, "color": "white", "font-size": 30, "text-align": "center", "background-color": "transparent"}}, "nodes": [], "bindings":[], "events":[], "value":"3", "widgetName":"widget7"}], "bindings":[], "events":[{"onclick": "onclick"}], "widgetName": "widget6"}, {"type": "div", "attributes": {"class": "key-wrapper", "onclick": "onclick", "style": {"width": 60, "height": 50, "border-width": 0, "border-color": "red", "background-color": "transparent", "top": 40, "left": 160}}, "nodes": [{"type": "text", "attributes": {"font-size": "30", "class": "key", "style": {"left": 0, "top": 0, "width": 50, "height": 40, "margin": 0, "padding": 0, "color": "white", "font-size": 30, "text-align": "center", "background-color": "transparent"}}, "nodes": [], "bindings":[], "events":[], "value":"+", "widgetName":"widget9"}], "bindings":[], "events":[{"onclick": "onclick"}], "widgetName": "widget8"}], "bindings": [], "events": [], "widgetName": "widget0"}}
+
+json.CONFIG_USING_CJSON = True
+print('dict_test:', dict_test)
+json_test = json.dumps(dict_test)
+print('json_test:', json_test)
+
+json.CONFIG_USING_CJSON = True
+start = time.tick_ms()
+for i in range(10):
+    res = json.loads(json_test)
+str_res_cjson = str(res)
+print('len(str_res_cjson):', len(str_res_cjson))
+end = time.tick_ms()
+time_cjson_loads = end - start
+print('loads: cjson:', time_cjson_loads, 'ms')
+
+json.CONFIG_USING_CJSON = False
+start = time.tick_ms()
+for i in range(10):
+    res = json.loads(json_test)
+str_res_jsmn = str(res)
+print('len(str_res_jsmn):', len(str_res_jsmn))
+end = time.tick_ms()
+time_jsmn_loads = end - start
+
+print('loads: jsmn:', time_jsmn_loads, 'ms')
+
+# test for dumps
+
+# test for dumps
+
+json.CONFIG_USING_CJSON = True
 start = time.tick_ms()
-for i in range(1000):
-    res = json.loads(
-        '{"a": 1, "b": 2, "c": 3, "d": {"e": 4, "f": 5}, "g": [6, 7, 8], "h": null, "i": false, "j": true, "k": "string", "l": 1.234}')
+for i in range(10):
+    res = json.dumps(dict_test)
+len_res_cjson = len(res)
+print('len(res_cjson):', len_res_cjson)
 end = time.tick_ms()
-time_cjson = end - start
-print('cjson:', time_cjson, 'ms')
+time_cjson_dumps = end - start
+print('dumps: cjson:', time_cjson_dumps, 'ms')
 
-json.CONFIG_USING_JSMN = True
+json.CONFIG_USING_CJSON = False
 start = time.tick_ms()
-for i in range(1000):
-    res = json.loads(
-        '{"a": 1, "b": 2, "c": 3, "d": {"e": 4, "f": 5}, "g": [6, 7, 8], "h": null, "i": false, "j": true, "k": "string", "l": 1.234}')
+for i in range(10):
+    res = json.dumps(dict_test)
+len_res_jsmn = len(res)
+print('len(res_jsmn):', len_res_jsmn)
 end = time.tick_ms()
-time_jsmn = end - start
-print('jsmn:', time_jsmn, 'ms')
+time_jsmn_dumps = end - start
+print('dumps: jsmn:', time_jsmn_dumps, 'ms')
 
-print('jsmn is', (time_cjson / time_jsmn), 'times faster than cjson')
+print('==================================================')
+print('loads: jsmn is', (time_cjson_loads /
+      time_jsmn_loads), 'times faster than cjson')
+print('dumps: jsmn is', (time_cjson_dumps /
+      time_jsmn_dumps), 'times faster than cjson')