From f9c4365dc751fab8ffe7664aac901d09c69fbf4a Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 8 Jun 2021 16:54:18 +0300 Subject: [PATCH] v.gen.c: free `indents` in autogenerated .str() methods --- vlib/strings/builder.v | 10 +- vlib/v/gen/c/auto_str_methods.v | 17 ++-- vlib/v/gen/c/auto_str_struct.v | 156 ++++++++++++++++---------------- 3 files changed, 95 insertions(+), 88 deletions(-) diff --git a/vlib/strings/builder.v b/vlib/strings/builder.v index 855319f645..ea0fff5472 100644 --- a/vlib/strings/builder.v +++ b/vlib/strings/builder.v @@ -17,6 +17,9 @@ pub fn new_builder(initial_size int) Builder { // write_ptr writes `len` bytes provided byteptr to the accumulated buffer [unsafe] pub fn (mut b Builder) write_ptr(ptr &byte, len int) { + if len == 0 { + return + } unsafe { b.push_many(ptr, len) } } @@ -27,6 +30,9 @@ pub fn (mut b Builder) write_b(data byte) { // write implements the Writer interface pub fn (mut b Builder) write(data []byte) ?int { + if data.len == 0 { + return 0 + } b << data return data.len } @@ -85,7 +91,9 @@ pub fn (mut b Builder) writeln(s string) { // for c in s { // b.buf << c // } - unsafe { b.push_many(s.str, s.len) } + if s.len > 0 { + unsafe { b.push_many(s.str, s.len) } + } // b.buf << []byte(s) // TODO b << byte(`\n`) } diff --git a/vlib/v/gen/c/auto_str_methods.v b/vlib/v/gen/c/auto_str_methods.v index b8298de81c..fecfa6b78e 100644 --- a/vlib/v/gen/c/auto_str_methods.v +++ b/vlib/v/gen/c/auto_str_methods.v @@ -231,17 +231,16 @@ fn (mut g Gen) gen_str_for_alias(info ast.Alias, styp string, str_fn_name string g.auto_str_funcs.writeln('static string ${str_fn_name}($styp it) { return indent_${str_fn_name}(it, 0); }') g.type_definitions.writeln('static string indent_${str_fn_name}($styp it, int indent_count); // auto') g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp it, int indent_count) {') - g.auto_str_funcs.writeln('\tstring indents = _SLIT("");') - g.auto_str_funcs.writeln('\tfor (int i = 0; i < indent_count; ++i) {') - g.auto_str_funcs.writeln('\t\tindents = string__plus(indents, _SLIT(" "));') - g.auto_str_funcs.writeln('\t}') - - g.auto_str_funcs.writeln('\treturn str_intp(3, _MOV((StrIntpData[]){ + g.auto_str_funcs.writeln('\tstring indents = string_repeat(_SLIT(" "), indent_count);') + g.auto_str_funcs.writeln('\tstring tmp_ds = ${parent_str_fn_name}(it);') + g.auto_str_funcs.writeln('\tstring res = str_intp(3, _MOV((StrIntpData[]){ {_SLIT0, $c.si_s_code, {.d_s = indents }}, - {_SLIT("${clean_type_v_type_name}("), $c.si_s_code, {.d_s = ${parent_str_fn_name}(it) }}, + {_SLIT("${clean_type_v_type_name}("), $c.si_s_code, {.d_s = tmp_ds }}, {_SLIT(")"), 0, {.d_c = 0 }} - }));\n') - + }));') + g.auto_str_funcs.writeln('\tstring_free(&indents);') + g.auto_str_funcs.writeln('\tstring_free(&tmp_ds);') + g.auto_str_funcs.writeln('\treturn res;') g.auto_str_funcs.writeln('}') } diff --git a/vlib/v/gen/c/auto_str_struct.v b/vlib/v/gen/c/auto_str_struct.v index b0052f0c5e..5751fed006 100644 --- a/vlib/v/gen/c/auto_str_struct.v +++ b/vlib/v/gen/c/auto_str_struct.v @@ -81,86 +81,86 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name stri } clean_struct_v_type_name = util.strip_main_name(clean_struct_v_type_name) // generate ident / indent length = 4 spaces - g.auto_str_funcs.writeln('\tstring indents = _SLIT("");') - g.auto_str_funcs.writeln('\tfor (int i = 0; i < indent_count; ++i) {') - g.auto_str_funcs.writeln('\t\tindents = string__plus(indents, _SLIT(" "));') - g.auto_str_funcs.writeln('\t}') if info.fields.len == 0 { - g.auto_str_funcs.write_string('\treturn _SLIT("$clean_struct_v_type_name{}");') - } else { - g.auto_str_funcs.write_string('\treturn str_intp( ${info.fields.len * 4 + 3}, _MOV((StrIntpData[]){\n') - g.auto_str_funcs.write_string('\t\t{_SLIT("$clean_struct_v_type_name{\\n"), 0, {.d_c=0}},\n') - - for i, field in info.fields { - mut ptr_amp := if field.typ.is_ptr() { '&' } else { '' } - base_fmt := g.type_to_fmt1(g.unwrap_generic(field.typ)) - - // manage prefix and quote symbol for the filed - mut quote_str := '' - mut prefix := '' - sym := g.table.get_type_symbol(g.unwrap_generic(field.typ)) - if sym.kind == .string { - quote_str = "'" - } else if field.typ in ast.charptr_types { - quote_str = '\\"' - prefix = 'C' - } - - // first fields doesn't need \n - if i == 0 { - g.auto_str_funcs.write_string('\t\t{_SLIT0, $si_s_code, {.d_s=indents}}, {_SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ') - } else { - g.auto_str_funcs.write_string('\t\t{_SLIT("\\n"), $si_s_code, {.d_s=indents}}, {_SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ') - } - - // custom methods management - has_custom_str := sym.has_method('str') - mut field_styp := g.typ(field.typ).replace('*', '') - field_styp_fn_name := if has_custom_str { - '${field_styp}_str' - } else { - fnames2strfunc[field_styp] - } - - // manage the fact hat with float we use always the g representation - if sym.kind !in [.f32, .f64] { - g.auto_str_funcs.write_string('{_SLIT("$quote_str"), ${int(base_fmt)}, {.${data_str(base_fmt)}=') - } else { - g_fmt := '0x' + (u32(base_fmt) | u32(0x7F) << 9).hex() - g.auto_str_funcs.write_string('{_SLIT("$quote_str"), $g_fmt, {.${data_str(base_fmt)}=') - } - - mut func := struct_auto_str_func1(sym, field.typ, field_styp_fn_name, field.name) - - // manage reference types can be "nil" - if field.typ.is_ptr() && !(field.typ in ast.charptr_types - || field.typ in ast.byteptr_types - || field.typ == ast.voidptr_type_idx) { - g.auto_str_funcs.write_string('isnil(it.${c_name(field.name)})') - g.auto_str_funcs.write_string(' ? _SLIT("nil") : ') - // struct, floats and ints have a special case through the _str function - if sym.kind != .struct_ && !field.typ.is_int_valptr() - && !field.typ.is_float_valptr() { - g.auto_str_funcs.write_string('*') - } - } - // handle circular ref type of struct to the struct itself - if styp == field_styp { - g.auto_str_funcs.write_string('_SLIT("")') - } else { - // manage C charptr - if field.typ in ast.charptr_types { - g.auto_str_funcs.write_string('tos2((byteptr)$func)') - } else { - g.auto_str_funcs.write_string(func) - } - } - - g.auto_str_funcs.write_string('}}, {_SLIT("$quote_str"), 0, {.d_c=0}},\n') - } - g.auto_str_funcs.write_string('\t\t{_SLIT("\\n"), $si_s_code, {.d_s=indents}}, {_SLIT("}"), 0, {.d_c=0}},\n') - g.auto_str_funcs.write_string('\t}));\n') + g.auto_str_funcs.writeln('\treturn _SLIT("$clean_struct_v_type_name{}");') + g.auto_str_funcs.writeln('}') + g.auto_str_funcs.writeln('') + return } + + g.auto_str_funcs.writeln('\tstring indents = string_repeat(_SLIT(" "), indent_count);') + g.auto_str_funcs.writeln('\tstring res = str_intp( ${info.fields.len * 4 + 3}, _MOV((StrIntpData[]){') + g.auto_str_funcs.writeln('\t\t{_SLIT("$clean_struct_v_type_name{\\n"), 0, {.d_c=0}},') + + for i, field in info.fields { + mut ptr_amp := if field.typ.is_ptr() { '&' } else { '' } + base_fmt := g.type_to_fmt1(g.unwrap_generic(field.typ)) + + // manage prefix and quote symbol for the filed + mut quote_str := '' + mut prefix := '' + sym := g.table.get_type_symbol(g.unwrap_generic(field.typ)) + if sym.kind == .string { + quote_str = "'" + } else if field.typ in ast.charptr_types { + quote_str = '\\"' + prefix = 'C' + } + + // first fields doesn't need \n + if i == 0 { + g.auto_str_funcs.write_string('\t\t{_SLIT0, $si_s_code, {.d_s=indents}}, {_SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ') + } else { + g.auto_str_funcs.write_string('\t\t{_SLIT("\\n"), $si_s_code, {.d_s=indents}}, {_SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ') + } + + // custom methods management + has_custom_str := sym.has_method('str') + mut field_styp := g.typ(field.typ).replace('*', '') + field_styp_fn_name := if has_custom_str { + '${field_styp}_str' + } else { + fnames2strfunc[field_styp] + } + + // manage the fact hat with float we use always the g representation + if sym.kind !in [.f32, .f64] { + g.auto_str_funcs.write_string('{_SLIT("$quote_str"), ${int(base_fmt)}, {.${data_str(base_fmt)}=') + } else { + g_fmt := '0x' + (u32(base_fmt) | u32(0x7F) << 9).hex() + g.auto_str_funcs.write_string('{_SLIT("$quote_str"), $g_fmt, {.${data_str(base_fmt)}=') + } + + mut func := struct_auto_str_func1(sym, field.typ, field_styp_fn_name, field.name) + + // manage reference types can be "nil" + if field.typ.is_ptr() && !(field.typ in ast.charptr_types + || field.typ in ast.byteptr_types || field.typ == ast.voidptr_type_idx) { + g.auto_str_funcs.write_string('isnil(it.${c_name(field.name)})') + g.auto_str_funcs.write_string(' ? _SLIT("nil") : ') + // struct, floats and ints have a special case through the _str function + if sym.kind != .struct_ && !field.typ.is_int_valptr() && !field.typ.is_float_valptr() { + g.auto_str_funcs.write_string('*') + } + } + // handle circular ref type of struct to the struct itself + if styp == field_styp { + g.auto_str_funcs.write_string('_SLIT("")') + } else { + // manage C charptr + if field.typ in ast.charptr_types { + g.auto_str_funcs.write_string('tos2((byteptr)$func)') + } else { + g.auto_str_funcs.write_string(func) + } + } + + g.auto_str_funcs.writeln('}}, {_SLIT("$quote_str"), 0, {.d_c=0}},') + } + g.auto_str_funcs.writeln('\t\t{_SLIT("\\n"), $si_s_code, {.d_s=indents}}, {_SLIT("}"), 0, {.d_c=0}},') + g.auto_str_funcs.writeln('\t}));') + g.auto_str_funcs.writeln('\tstring_free(&indents);') + g.auto_str_funcs.writeln('\treturn res;') g.auto_str_funcs.writeln('}') }