summaryrefslogtreecommitdiff
path: root/extmod/modujson.c
diff options
context:
space:
mode:
authorScott Shawcroft <scott@adafruit.com>2020-12-23 12:56:19 -0800
committerGitHub <noreply@github.com>2020-12-23 12:56:19 -0800
commitbaa053b8b2bf4be381fcd44df5e8a4d94efdb57d (patch)
treebe3949426650091509c2815cafb5b79fe963e941 /extmod/modujson.c
parent3266720f155819b46351b15913532b1a964ae76e (diff)
parentfc1f47d0d24e1069c03671c94d5c994c0eae128c (diff)
Merge pull request #3870 from dhalbert/speedup_json-6.0.x
Speed up JSON parsing with readinto (#3728 for 6.0.x)
Diffstat (limited to 'extmod/modujson.c')
-rw-r--r--extmod/modujson.c36
1 files changed, 27 insertions, 9 deletions
diff --git a/extmod/modujson.c b/extmod/modujson.c
index 431b5e0cf..3bb4b3301 100644
--- a/extmod/modujson.c
+++ b/extmod/modujson.c
@@ -57,6 +57,8 @@ typedef struct _ujson_stream_t {
int errcode;
mp_obj_t python_readinto[2 + 1];
mp_obj_array_t bytearray_obj;
+ size_t start;
+ size_t end;
byte cur;
} ujson_stream_t;
@@ -77,28 +79,44 @@ STATIC byte ujson_stream_next(ujson_stream_t *s) {
return s->cur;
}
+// We read from an object's `readinto` method in chunks larger than the json
+// parser needs to reduce the number of function calls done.
+
+#define CIRCUITPY_JSON_READ_CHUNK_SIZE 64
+
STATIC mp_uint_t ujson_python_readinto(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode) {
+ (void) size; // Ignore size because we know it's always 1.
ujson_stream_t* s = obj;
- s->bytearray_obj.items = buf;
- s->bytearray_obj.len = size;
- *errcode = 0;
- mp_obj_t ret = mp_call_method_n_kw(1, 0, s->python_readinto);
- if (ret == mp_const_none) {
- *errcode = MP_EAGAIN;
- return MP_STREAM_ERROR;
+
+ if (s->start == s->end) {
+ *errcode = 0;
+ mp_obj_t ret = mp_call_method_n_kw(1, 0, s->python_readinto);
+ if (ret == mp_const_none) {
+ *errcode = MP_EAGAIN;
+ return MP_STREAM_ERROR;
+ }
+ s->start = 0;
+ s->end = mp_obj_get_int(ret);
}
- return mp_obj_get_int(ret);
+
+ *((uint8_t *)buf) = ((uint8_t*) s->bytearray_obj.items)[s->start];
+ s->start++;
+ return 1;
}
STATIC mp_obj_t _mod_ujson_load(mp_obj_t stream_obj, bool return_first_json) {
const mp_stream_p_t *stream_p = mp_proto_get(MP_QSTR_protocol_stream, stream_obj);
ujson_stream_t s;
+ uint8_t character_buffer[CIRCUITPY_JSON_READ_CHUNK_SIZE];
if (stream_p == NULL) {
+ s.start = 0;
+ s.end = 0;
mp_load_method(stream_obj, MP_QSTR_readinto, s.python_readinto);
s.bytearray_obj.base.type = &mp_type_bytearray;
s.bytearray_obj.typecode = BYTEARRAY_TYPECODE;
+ s.bytearray_obj.len = CIRCUITPY_JSON_READ_CHUNK_SIZE;
s.bytearray_obj.free = 0;
- // len and items are set at read time
+ s.bytearray_obj.items = character_buffer;
s.python_readinto[2] = MP_OBJ_FROM_PTR(&s.bytearray_obj);
s.stream_obj = &s;
s.read = ujson_python_readinto;