From f4d2389b2f4dec7f9d96b1a7c1b27deaffe90d6a Mon Sep 17 00:00:00 2001 From: yuyi Date: Wed, 26 Jun 2024 22:09:57 +0800 Subject: [PATCH] ast, cgen: fix generics map with the reference argument (#21737) --- vlib/v/ast/table.v | 2 +- vlib/v/gen/c/struct.v | 19 ++-- .../generics_map_with_reference_arg_test.v | 92 +++++++++++++++++++ 3 files changed, 103 insertions(+), 10 deletions(-) create mode 100644 vlib/v/tests/generics_map_with_reference_arg_test.v diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 5cb41fef2f6760..c8963b3a3ab350 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -1229,7 +1229,7 @@ pub fn (mut t Table) add_placeholder_type(name string, language Language) int { ph_type := TypeSymbol{ kind: .placeholder name: name - cname: util.no_dots(name) + cname: util.no_dots(name).replace_each(['&', '']) language: language mod: modname } diff --git a/vlib/v/gen/c/struct.v b/vlib/v/gen/c/struct.v index f7cba066a242c4..5db2a6c835a9b8 100644 --- a/vlib/v/gen/c/struct.v +++ b/vlib/v/gen/c/struct.v @@ -648,7 +648,8 @@ fn (mut g Gen) struct_init_field(sfield ast.StructInitField, language ast.Langua inside_cast_in_heap := g.inside_cast_in_heap g.inside_cast_in_heap = 0 // prevent use of pointers in child structs - field_unwrap_sym := g.table.sym(g.unwrap_generic(sfield.typ)) + field_unwrap_typ := g.unwrap_generic(sfield.typ) + field_unwrap_sym := g.table.sym(field_unwrap_typ) if field_unwrap_sym.kind == .array_fixed && sfield.expr in [ast.Ident, ast.SelectorExpr] { info := field_unwrap_sym.info as ast.ArrayFixed g.fixed_array_var_init(g.expr_string(sfield.expr), sfield.expr.is_auto_deref_var(), @@ -658,21 +659,21 @@ fn (mut g Gen) struct_init_field(sfield ast.StructInitField, language ast.Langua tmp_var := g.expr_with_var(sfield.expr, sfield.typ, sfield.expected_type) g.fixed_array_var_init(tmp_var, false, info.elem_type, info.size) } else { - if sfield.typ != ast.voidptr_type && sfield.typ != ast.nil_type + if field_unwrap_typ != ast.voidptr_type && field_unwrap_typ != ast.nil_type && (sfield.expected_type.is_ptr() && !sfield.expected_type.has_flag(.shared_f)) - && !sfield.expected_type.has_flag(.option) && !sfield.typ.is_any_kind_of_pointer() - && !sfield.typ.is_number() { + && !sfield.expected_type.has_flag(.option) + && !field_unwrap_typ.is_any_kind_of_pointer() && !field_unwrap_typ.is_number() { g.write('/* autoref */&') } - if (sfield.expected_type.has_flag(.option) && !sfield.typ.has_flag(.option)) - || (sfield.expected_type.has_flag(.result) && !sfield.typ.has_flag(.result)) { - g.expr_with_opt(sfield.expr, sfield.typ, sfield.expected_type) + if (sfield.expected_type.has_flag(.option) && !field_unwrap_typ.has_flag(.option)) + || (sfield.expected_type.has_flag(.result) && !field_unwrap_typ.has_flag(.result)) { + g.expr_with_opt(sfield.expr, field_unwrap_typ, sfield.expected_type) } else if sfield.expr is ast.LambdaExpr && sfield.expected_type.has_flag(.option) { - g.expr_opt_with_cast(sfield.expr, sfield.typ, sfield.expected_type) + g.expr_opt_with_cast(sfield.expr, field_unwrap_typ, sfield.expected_type) } else { g.left_is_opt = true - g.expr_with_cast(sfield.expr, sfield.typ, sfield.expected_type) + g.expr_with_cast(sfield.expr, field_unwrap_typ, sfield.expected_type) } } g.inside_cast_in_heap = inside_cast_in_heap // restore value for further struct inits diff --git a/vlib/v/tests/generics_map_with_reference_arg_test.v b/vlib/v/tests/generics_map_with_reference_arg_test.v new file mode 100644 index 00000000000000..f247d32c3a046b --- /dev/null +++ b/vlib/v/tests/generics_map_with_reference_arg_test.v @@ -0,0 +1,92 @@ +import datatypes +import time + +struct Entry[V] { +mut: + value V + load_time u32 +} + +struct Lru[T, V] { +mut: + m map[T]Entry[V] + list datatypes.DoublyLinkedList[T] + cap u32 = 1000 + ttl u32 = 3 + on_del ?fn (T, V) +pub mut: + hits u32 + miss u32 +} + +pub fn new[T, V](cap u32, ttl u32) &Lru[T, V] { + return &Lru[T, V]{ + cap: cap + ttl: ttl + } +} + +pub fn (mut l Lru[T, V]) set_on_del(on_del fn (T, V)) { + l.on_del = on_del +} + +pub fn (mut l Lru[T, V]) add(k T, v V) { + if l.m.len >= (l.cap * 97 / 100) { + l.remove_expired(0) + for l.m.len > (l.cap * 90 / 100) { + l.del(l.list.pop_back() or { return }) + } + } + l.m[k] = Entry[V]{v, u32(time.now().unix())} + l.list.push_front(k) +} + +pub fn (mut l Lru[T, V]) get(k T) ?V { + l.remove_expired(0) + if k in l.m { + l.list.delete(l.list.index(k) or { return none }) + l.list.push_front(k) + l.hits++ + return l.m[k].value + } + l.miss++ + return none +} + +pub fn (mut l Lru[T, V]) remove_expired(cnt int) { + now := u32(time.now().unix()) + iter := l.list.back_iterator() + del_cnt := 0 + for key in iter { + if e := l.m[key] { + if e.load_time + l.ttl >= now || (cnt > 0 && del_cnt >= cnt) { + break + } + l.del(key) + } + } +} + +pub fn (mut l Lru[T, V]) del(k T) { + if k in l.m { + val := l.m[k].value + l.m.delete(k) + l.list.delete(l.list.index(k) or { -1 }) + on_del := l.on_del or { return } + on_del(k, val) + } +} + +struct TT { + age int + dd int +} + +fn test_generic_map_with_reference_arg() { + mut c := new[int, &TT](10, 3) + c.add(1, &TT{2, 2}) + ret := c.get(1)? + println(ret) + assert ret.age == 2 + assert ret.dd == 2 +}