8000 Merge pull request #3870 from dhalbert/speedup_json-6.0.x · russbot/circuitpython@baa053b · GitHub
[go: up one dir, main page]

Skip to content

Commit baa053b

Browse files
authored
Merge pull request adafruit#3870 from dhalbert/speedup_json-6.0.x
Speed up JSON parsing with readinto (adafruit#3728 for 6.0.x)
2 parents 3266720 + fc1f47d commit baa053b

File tree

1 file changed

+27
-9
lines changed

1 file changed

+27
-9
lines changed

extmod/modujson.c

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ typedef struct _ujson_stream_t {
5757
int errcode;
5858
mp_obj_t python_readinto[2 + 1];
5959
mp_obj_array_t bytearray_obj;
60+
size_t start;
61+
size_t end;
6062
byte cur;
6163
} ujson_stream_t;
6264

@@ -77,28 +79,44 @@ STATIC byte ujson_stream_next(ujson_stream_t *s) {
7779
return s->cur;
7880
}
7981

82+
// We read from an object's `readinto` method in chunks larger than the json
83+
// parser needs to reduce the number of function calls done.
84+
85+
#define CIRCUITPY_JSON_READ_CHUNK_SIZE 64
86+
8087
STATIC mp_uint_t ujson_python_readinto(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode) {
88+
(void) size; // Ignore size because we know it's always 1.
8189
ujson_stream_t* s = obj;
82-
s->bytearray_obj.items = buf;
83-
s->bytearray_obj.len = size;
84-
*errcode = 0;
85-
mp_obj_t ret = mp_call_method_n_kw(1, 0, s->python_readinto);
86-
if (ret == mp_const_none) {
87-
*errcode = MP_EAGAIN;
88-
return MP_STREAM_ERROR;
90+
91+
if (s->start == s->end) {
92+
*errcode = 0;
93+
mp_obj_t ret = mp_call_method_n_kw(1, 0, s->python_readinto);
94+
if (ret == mp_const_none) {
95+
*errcode = MP_EAGAIN;
96+
return MP_STREAM_ERROR;
97+
}
98+
s->start = 0;
99+
s->end = mp_obj_get_int(ret);
89100
}
90-
return mp_obj_get_int(ret);
101+
102+
*((uint8_t *)buf) = ((uint8_t*) s->bytearray_obj.items)[s->start];
103+
s->start++;
104+
return 1;
91105
}
92106

93107
STATIC mp_obj_t _mod_ujson_load(mp_obj_t stream_obj, bool return_first_json) {
94108
const mp_stream_p_t *stream_p = mp_proto_get(MP_QSTR_protocol_stream, stream_obj);
95109
ujson_stream_t s;
110+
uint8_t character_buffer[CIRCUITPY_JSON_READ_CHUNK_SIZE];
96111
if (stream_p == NULL) {
112+
s.start = 0;
113+
s.end = 0;
97114
mp_load_method(stream_obj, MP_QSTR_readinto, s.python_readinto);
98115
s.bytearray_obj.base.type = &mp_type_bytearray;
99116
s.bytearray_obj.typecode = BYTEARRAY_TYPECODE;
117+
s.bytearray_obj.len = CIRCUITPY_JSON_READ_CHUNK_SIZE;
100118
s.bytearray_obj.free = 0;
101-
// len and items are set at read time
119+
s.bytearray_obj.items = character_buffer;
102120
s.python_readinto[2] = MP_OBJ_FROM_PTR(&s.bytearray_obj);
103121
s.stream_obj = &s;
104122
s.read = ujson_python_readinto;

0 commit comments

Comments
 (0)
0