Skip to content

Commit

Permalink
ast, cgen: fix generics map with the reference argument (#21737)
Browse files Browse the repository at this point in the history
  • Loading branch information
yuyi98 authored Jun 26, 2024
1 parent 66c4307 commit f4d2389
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 10 deletions.
2 changes: 1 addition & 1 deletion vlib/v/ast/table.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
19 changes: 10 additions & 9 deletions vlib/v/gen/c/struct.v
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -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
Expand Down
92 changes: 92 additions & 0 deletions vlib/v/tests/generics_map_with_reference_arg_test.v
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit f4d2389

Please sign in to comment.