diff --git a/py/misc.h b/py/misc.h index c0fd293de..df017f44a 100644 --- a/py/misc.h +++ b/py/misc.h @@ -135,8 +135,6 @@ char *vstr_str(vstr_t *vstr); size_t vstr_len(vstr_t *vstr); void vstr_hint_size(vstr_t *vstr, size_t size); char *vstr_extend(vstr_t *vstr, size_t size); -bool vstr_set_size(vstr_t *vstr, size_t size); -bool vstr_shrink(vstr_t *vstr); char *vstr_add_len(vstr_t *vstr, size_t len); void vstr_add_byte(vstr_t *vstr, byte v); void vstr_add_char(vstr_t *vstr, unichar chr); diff --git a/py/modbuiltins.c b/py/modbuiltins.c index b739503ad..68a22934b 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -449,11 +449,10 @@ STATIC mp_obj_t mp_builtin___repl_print__(mp_obj_t o) { MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin___repl_print___obj, mp_builtin___repl_print__); STATIC mp_obj_t mp_builtin_repr(mp_obj_t o_in) { - vstr_t *vstr = vstr_new(); - mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))vstr_printf, vstr, o_in, PRINT_REPR); - mp_obj_t s = mp_obj_new_str(vstr->buf, vstr->len, false); - vstr_free(vstr); - return s; + vstr_t vstr; + vstr_init(&vstr, 16); + mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))vstr_printf, &vstr, o_in, PRINT_REPR); + return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_repr_obj, mp_builtin_repr); diff --git a/py/obj.h b/py/obj.h index 042404859..d0ea4c112 100644 --- a/py/obj.h +++ b/py/obj.h @@ -400,6 +400,7 @@ mp_obj_t mp_obj_new_int_from_str_len(const char **str, mp_uint_t len, bool neg, mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception) mp_obj_t mp_obj_new_int_from_ull(unsigned long long val); // this must return a multi-precision integer object (or raise an overflow exception) mp_obj_t mp_obj_new_str(const char* data, mp_uint_t len, bool make_qstr_if_not_already); +mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr); mp_obj_t mp_obj_new_bytes(const byte* data, mp_uint_t len); mp_obj_t mp_obj_new_bytearray(mp_uint_t n, void *items); mp_obj_t mp_obj_new_bytearray_by_ref(mp_uint_t n, void *items); diff --git a/py/objexcept.c b/py/objexcept.c index e872db341..f2f4012bc 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -351,13 +351,13 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char } else { // render exception message and store as .args[0] // TODO: optimize bufferbloat - vstr_t *vstr = vstr_new(); + vstr_t vstr; + vstr_init(&vstr, 16); va_list ap; va_start(ap, fmt); - vstr_vprintf(vstr, fmt, ap); + vstr_vprintf(&vstr, fmt, ap); va_end(ap); - o->args->items[0] = mp_obj_new_str(vstr->buf, vstr->len, false); - vstr_free(vstr); + o->args->items[0] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } } diff --git a/py/objstr.c b/py/objstr.c index 2aea44b68..b67913e51 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -132,8 +132,6 @@ STATIC void str_print(void (*print)(void *env, const char *fmt, ...), void *env, #if !MICROPY_PY_BUILTINS_STR_UNICODE || MICROPY_CPYTHON_COMPAT STATIC mp_obj_t str_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { - (void)type_in; - #if MICROPY_CPYTHON_COMPAT if (n_kw != 0) { mp_arg_error_unimpl_kw(); @@ -147,11 +145,10 @@ STATIC mp_obj_t str_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, return MP_OBJ_NEW_QSTR(MP_QSTR_); case 1: { - vstr_t *vstr = vstr_new(); - mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, args[0], PRINT_STR); - mp_obj_t s = mp_obj_new_str(vstr->buf, vstr->len, false); - vstr_free(vstr); - return s; + vstr_t vstr; + vstr_init(&vstr, 16); + mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, &vstr, args[0], PRINT_STR); + return mp_obj_new_str_from_vstr(type_in, &vstr); } default: // 2 or 3 args @@ -159,7 +156,7 @@ STATIC mp_obj_t str_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, if (MP_OBJ_IS_TYPE(args[0], &mp_type_bytes)) { GET_STR_DATA_LEN(args[0], str_data, str_len); GET_STR_HASH(args[0], str_hash); - mp_obj_str_t *o = mp_obj_new_str_of_type(&mp_type_str, NULL, str_len); + mp_obj_str_t *o = mp_obj_new_str_of_type(type_in, NULL, str_len); o->data = str_data; o->hash = str_hash; return o; @@ -216,40 +213,23 @@ STATIC mp_obj_t bytes_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_k return mp_obj_new_str_of_type(&mp_type_bytes, bufinfo.buf, bufinfo.len); } - mp_int_t len; - byte *data; - vstr_t *vstr = NULL; - mp_obj_t o = MP_OBJ_NULL; + vstr_t vstr; // Try to create array of exact len if initializer len is known mp_obj_t len_in = mp_obj_len_maybe(args[0]); if (len_in == MP_OBJ_NULL) { - len = -1; - vstr = vstr_new(); + vstr_init(&vstr, 16); } else { - len = MP_OBJ_SMALL_INT_VALUE(len_in); - o = mp_obj_str_builder_start(&mp_type_bytes, len, &data); + mp_int_t len = MP_OBJ_SMALL_INT_VALUE(len_in); + vstr_init(&vstr, len + 1); } mp_obj_t iterable = mp_getiter(args[0]); mp_obj_t item; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - if (len == -1) { - vstr_add_char(vstr, MP_OBJ_SMALL_INT_VALUE(item)); - } else { - *data++ = MP_OBJ_SMALL_INT_VALUE(item); - } + vstr_add_char(&vstr, MP_OBJ_SMALL_INT_VALUE(item)); } - if (len == -1) { - vstr_shrink(vstr); - // TODO: Optimize, borrow buffer from vstr - len = vstr_len(vstr); - o = mp_obj_str_builder_start(&mp_type_bytes, len, &data); - memcpy(data, vstr_str(vstr), len); - vstr_free(vstr); - } - - return mp_obj_str_builder_end(o); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); wrong_args: nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "wrong number of arguments")); @@ -837,16 +817,17 @@ mp_obj_t mp_obj_str_format(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwa GET_STR_DATA_LEN(args[0], str, len); int arg_i = 0; - vstr_t *vstr = vstr_new(); + vstr_t vstr; + vstr_init(&vstr, 16); pfenv_t pfenv_vstr; - pfenv_vstr.data = vstr; + pfenv_vstr.data = &vstr; pfenv_vstr.print_strn = pfenv_vstr_add_strn; for (const byte *top = str + len; str < top; str++) { if (*str == '}') { str++; if (str < top && *str == '}') { - vstr_add_char(vstr, '}'); + vstr_add_char(&vstr, '}'); continue; } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { @@ -857,13 +838,13 @@ mp_obj_t mp_obj_str_format(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwa } } if (*str != '{') { - vstr_add_char(vstr, *str); + vstr_add_char(&vstr, *str); continue; } str++; if (str < top && *str == '{') { - vstr_add_char(vstr, '{'); + vstr_add_char(&vstr, '{'); continue; } @@ -996,10 +977,10 @@ mp_obj_t mp_obj_str_format(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwa "unknown conversion specifier %c", conversion)); } } - vstr_t *arg_vstr = vstr_new(); - mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, arg_vstr, arg, print_kind); - arg = mp_obj_new_str(vstr_str(arg_vstr), vstr_len(arg_vstr), false); - vstr_free(arg_vstr); + vstr_t arg_vstr; + vstr_init(&arg_vstr, 16); + mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, &arg_vstr, arg, print_kind); + arg = mp_obj_new_str_from_vstr(&mp_type_str, &arg_vstr); } char sign = '\0'; @@ -1243,7 +1224,7 @@ mp_obj_t mp_obj_str_format(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwa switch (type) { case '\0': - mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, arg, PRINT_STR); + mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, &vstr, arg, PRINT_STR); break; case 's': { @@ -1271,9 +1252,7 @@ mp_obj_t mp_obj_str_format(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwa } } - mp_obj_t s = mp_obj_new_str(vstr->buf, vstr->len, false); - vstr_free(vstr); - return s; + return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, mp_uint_t n_args, const mp_obj_t *args, mp_obj_t dict) { @@ -1282,22 +1261,23 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, mp_uint_t n_args, const mp_o GET_STR_DATA_LEN(pattern, str, len); const byte *start_str = str; int arg_i = 0; - vstr_t *vstr = vstr_new(); + vstr_t vstr; + vstr_init(&vstr, 16); pfenv_t pfenv_vstr; - pfenv_vstr.data = vstr; + pfenv_vstr.data = &vstr; pfenv_vstr.print_strn = pfenv_vstr_add_strn; for (const byte *top = str + len; str < top; str++) { mp_obj_t arg = MP_OBJ_NULL; if (*str != '%') { - vstr_add_char(vstr, *str); + vstr_add_char(&vstr, *str); continue; } if (++str >= top) { break; } if (*str == '%') { - vstr_add_char(vstr, '%'); + vstr_add_char(&vstr, '%'); continue; } @@ -1426,18 +1406,19 @@ not_enough_args: case 'r': case 's': { - vstr_t *arg_vstr = vstr_new(); + vstr_t arg_vstr; + vstr_init(&arg_vstr, 16); mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, - arg_vstr, arg, *str == 'r' ? PRINT_REPR : PRINT_STR); - uint vlen = vstr_len(arg_vstr); + &arg_vstr, arg, *str == 'r' ? PRINT_REPR : PRINT_STR); + uint vlen = arg_vstr.len; if (prec < 0) { prec = vlen; } if (vlen > (uint)prec) { vlen = prec; } - pfenv_print_strn(&pfenv_vstr, vstr_str(arg_vstr), vlen, flags, ' ', width); - vstr_free(arg_vstr); + pfenv_print_strn(&pfenv_vstr, arg_vstr.buf, vlen, flags, ' ', width); + vstr_clear(&arg_vstr); break; } @@ -1461,9 +1442,7 @@ not_enough_args: nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "not all arguments converted during string formatting")); } - mp_obj_t s = mp_obj_new_str(vstr->buf, vstr->len, false); - vstr_free(vstr); - return s; + return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } STATIC mp_obj_t str_replace(mp_uint_t n_args, const mp_obj_t *args) { @@ -1746,7 +1725,7 @@ STATIC mp_obj_t bytes_decode(mp_uint_t n_args, const mp_obj_t *args) { args = new_args; n_args++; } - return str_make_new(NULL, n_args, 0, args); + return str_make_new((mp_obj_t)&mp_type_str, n_args, 0, args); } // TODO: should accept kwargs too @@ -1920,6 +1899,28 @@ mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, mp_ return o; } +mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr) { + // if not a bytes object, look if a qstr with this data already exists + if (type == &mp_type_str) { + qstr q = qstr_find_strn(vstr->buf, vstr->len); + if (q != MP_QSTR_NULL) { + vstr_clear(vstr); + vstr->alloc = 0; + return MP_OBJ_NEW_QSTR(q); + } + } + + // make a new str/bytes object + mp_obj_str_t *o = m_new_obj(mp_obj_str_t); + o->base.type = type; + o->len = vstr->len; + o->hash = qstr_compute_hash((byte*)vstr->buf, vstr->len); + o->data = (byte*)m_renew(char, vstr->buf, vstr->alloc, vstr->len + 1); + vstr->buf = NULL; + vstr->alloc = 0; + return o; +} + mp_obj_t mp_obj_new_str(const char* data, mp_uint_t len, bool make_qstr_if_not_already) { if (make_qstr_if_not_already) { // use existing, or make a new qstr diff --git a/py/objstrunicode.c b/py/objstrunicode.c index 49eddcca3..348eaff39 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -114,8 +114,6 @@ STATIC mp_obj_t uni_unary_op(mp_uint_t op, mp_obj_t self_in) { } STATIC mp_obj_t str_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { - (void)type_in; - #if MICROPY_CPYTHON_COMPAT if (n_kw != 0) { mp_arg_error_unimpl_kw(); @@ -126,13 +124,11 @@ STATIC mp_obj_t str_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, case 0: return MP_OBJ_NEW_QSTR(MP_QSTR_); - case 1: - { - vstr_t *vstr = vstr_new(); - mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, args[0], PRINT_STR); - mp_obj_t s = mp_obj_new_str(vstr->buf, vstr->len, false); - vstr_free(vstr); - return s; + case 1: { + vstr_t vstr; + vstr_init(&vstr, 16); + mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, &vstr, args[0], PRINT_STR); + return mp_obj_new_str_from_vstr(type_in, &vstr); } case 2: @@ -142,7 +138,7 @@ STATIC mp_obj_t str_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, if (MP_OBJ_IS_TYPE(args[0], &mp_type_bytes)) { GET_STR_DATA_LEN(args[0], str_data, str_len); GET_STR_HASH(args[0], str_hash); - mp_obj_str_t *o = mp_obj_new_str_of_type(&mp_type_str, NULL, str_len); + mp_obj_str_t *o = mp_obj_new_str_of_type(type_in, NULL, str_len); o->data = str_data; o->hash = str_hash; return o; diff --git a/py/stream.c b/py/stream.c index c57b7981a..b7d4a9000 100644 --- a/py/stream.c +++ b/py/stream.c @@ -156,9 +156,7 @@ STATIC mp_obj_t stream_read(mp_uint_t n_args, const mp_obj_t *args) { } } - mp_obj_t ret = mp_obj_new_str_of_type(&mp_type_str, (byte*)vstr.buf, vstr.len); - vstr_clear(&vstr); - return ret; + return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } #endif @@ -251,8 +249,9 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) { } mp_uint_t total_size = 0; - vstr_t *vstr = vstr_new_size(DEFAULT_BUFFER_SIZE); - char *p = vstr_str(vstr); + vstr_t vstr; + vstr_init(&vstr, DEFAULT_BUFFER_SIZE); + char *p = vstr.buf; mp_uint_t current_read = DEFAULT_BUFFER_SIZE; while (true) { int error; @@ -278,7 +277,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) { p += out_sz; } else { current_read = DEFAULT_BUFFER_SIZE; - p = vstr_extend(vstr, current_read); + p = vstr_extend(&vstr, current_read); if (p == NULL) { // TODO nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError/*&mp_type_RuntimeError*/, "Out of memory")); @@ -286,9 +285,9 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) { } } - mp_obj_t s = mp_obj_new_str_of_type(STREAM_CONTENT_TYPE(o->type->stream_p), (byte*)vstr->buf, total_size); - vstr_free(vstr); - return s; + vstr.len = total_size; + vstr.buf[vstr.len] = '\0'; // XXX is there enough space? + return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(o->type->stream_p), &vstr); } // Unbuffered, inefficient implementation of readline() for raw I/O files. @@ -348,8 +347,7 @@ done: break; } } - // TODO need a string creation API that doesn't copy the given data - mp_obj_t ret = mp_obj_new_str_of_type(STREAM_CONTENT_TYPE(o->type->stream_p), (byte*)vstr->buf, vstr->len); + mp_obj_t ret = mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(o->type->stream_p), vstr); vstr_free(vstr); return ret; } diff --git a/py/vstr.c b/py/vstr.c index 1f9f13637..6856cfe39 100644 --- a/py/vstr.c +++ b/py/vstr.c @@ -136,26 +136,6 @@ char *vstr_extend(vstr_t *vstr, size_t size) { return p; } -// Shrink vstr to be given size -bool vstr_set_size(vstr_t *vstr, size_t size) { - if (vstr->fixed_buf) { - return false; - } - char *new_buf = m_renew(char, vstr->buf, vstr->alloc, size); - if (new_buf == NULL) { - vstr->had_error = true; - return false; - } - vstr->buf = new_buf; - vstr->alloc = vstr->len = size; - return true; -} - -// Shrink vstr allocation to its actual length -bool vstr_shrink(vstr_t *vstr) { - return vstr_set_size(vstr, vstr->len); -} - STATIC bool vstr_ensure_extra(vstr_t *vstr, size_t size) { if (vstr->len + size + 1 > vstr->alloc) { if (vstr->fixed_buf) {