diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index cbd47867de..3a4476c73c 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -2355,6 +2355,25 @@ fn (mut g Gen) expr(node ast.Expr) { value_typ_str := g.typ(node.value_type) value_typ := g.table.get_type_symbol(node.value_type) size := node.vals.len + mut shared_styp := '' // only needed for shared &[]{...} + mut styp := '' + is_amp := g.is_amp + g.is_amp = false + if is_amp { + g.out.go_back(1) // delete the `&` already generated in `prefix_expr() + if g.is_shared { + mut shared_typ := node.typ.set_flag(.shared_f) + shared_styp = g.typ(shared_typ) + g.writeln('($shared_styp*)memdup(&($shared_styp){.val = ') + } else { + styp = g.typ(node.typ) + g.write('($styp*)memdup(&') // TODO: doesn't work with every compiler + } + } else { + if g.is_shared { + g.writeln('{.val = ($styp*)') + } + } if size > 0 { if value_typ.kind == .function { g.write('new_map_init($size, sizeof(voidptr), _MOV(($key_typ_str[$size]){') @@ -2378,6 +2397,14 @@ fn (mut g Gen) expr(node ast.Expr) { } else { g.write('new_map_1(sizeof($value_typ_str))') } + if g.is_shared { + g.write(', .mtx = sync__new_rwmutex()}') + if is_amp { + g.write(', sizeof($shared_styp))') + } + } else if is_amp { + g.write(', sizeof($styp))') + } } ast.None { g.write('opt_none()') @@ -3715,10 +3742,17 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { if g.is_assign_lhs && !g.is_array_set && !get_and_set_types { g.is_array_set = true g.write('map_set(') - if !left_is_ptr { + if !left_is_ptr || node.left_type.has_flag(.shared_f) { g.write('&') } g.expr(node.left) + if node.left_type.has_flag(.shared_f) { + if left_is_ptr { + g.write('->val') + } else { + g.write('.val') + } + } g.write(', ') g.expr(node.index) if elem_typ.kind == .function { @@ -3744,10 +3778,17 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { } else { g.write('(*($elem_type_str*)map_get(') } - if node.left_type.is_ptr() { + if node.left_type.is_ptr() && !node.left_type.has_flag(.shared_f) { g.write('*') } g.expr(node.left) + if node.left_type.has_flag(.shared_f) { + if left_is_ptr { + g.write('->val') + } else { + g.write('.val') + } + } g.write(', ') g.expr(node.index) if elem_typ.kind == .function { diff --git a/vlib/v/tests/shared_map_test.v b/vlib/v/tests/shared_map_test.v new file mode 100644 index 0000000000..accd15a514 --- /dev/null +++ b/vlib/v/tests/shared_map_test.v @@ -0,0 +1,36 @@ +import sync + +fn incr(shared foo map[string]int, key string, sem sync.Semaphore) { + for _ in 0 .. 100000 { + lock foo { + foo[key] = foo[key] + 1 + } + } + sem.post() +} + +fn test_shared_array() { + shared foo := &{'p': 10, 'q': 20} + sem := sync.new_semaphore() + go incr(shared foo, 'p', sem) + go incr(shared foo, 'q', sem) + go incr(shared foo, 'p', sem) + go incr(shared foo, 'q', sem) + for _ in 0 .. 50000 { + lock foo { + unsafe { + foo['p'] = foo['p'] - 2 + foo['q'] = foo['q'] + 3 + } + } + } + for _ in 0..4 { + sem.wait() + } + rlock foo { + fp := unsafe { foo['p'] } + fq := unsafe { foo['q'] } + assert fp == 100010 + assert fq == 350020 + } +}