Skip to content

Commit

Permalink
builtin: add map.values() (#14301)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hunam6 committed May 6, 2022
1 parent ce99a30 commit 0699f32
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 6 deletions.
29 changes: 27 additions & 2 deletions vlib/builtin/map.v
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ mut:
// array allocated (with `cap` bytes) on first deletion
// has non-zero element when key deleted
all_deleted &u8
values &u8
keys &u8
values &u8
}

[inline]
Expand Down Expand Up @@ -126,8 +126,8 @@ fn (d &DenseArray) has_index(i int) bool {
[inline]
fn (mut d DenseArray) expand() int {
old_cap := d.cap
old_value_size := d.value_bytes * old_cap
old_key_size := d.key_bytes * old_cap
old_value_size := d.value_bytes * old_cap
if d.cap == d.len {
d.cap += d.cap >> 3
unsafe {
Expand Down Expand Up @@ -628,6 +628,31 @@ pub fn (m &map) keys() array {
return keys
}

// Returns all values in the map.
pub fn (m &map) values() array {
mut values := __new_array(m.len, 0, m.value_bytes)
mut item := unsafe { &u8(values.data) }

if m.key_values.deletes == 0 {
unsafe {
vmemcpy(item, m.key_values.values, m.value_bytes * m.key_values.len)
}
return values
}

for i := 0; i < m.key_values.len; i++ {
if !m.key_values.has_index(i) {
continue
}
unsafe {
pvalue := m.key_values.value(i)
vmemcpy(item, pvalue, m.value_bytes)
item = item + m.value_bytes
}
}
return values
}

// warning: only copies keys, does not clone
[unsafe]
fn (d &DenseArray) clone() DenseArray {
Expand Down
29 changes: 29 additions & 0 deletions vlib/builtin/map_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ fn test_keys_many() {
assert keys == strings
}

fn test_values_many() {
mut m := map[string]int{}
for i, s in strings {
m[s] = i
}
values := m.values()
assert values.len == strings.len
assert values.len == m.len
}

fn test_deletes_many() {
mut m := map[string]int{}
for i, s in strings {
Expand All @@ -59,6 +69,7 @@ fn test_deletes_many() {
}
assert m.len == 0
assert m.keys().len == 0
assert m.values().len == 0
}

struct User {
Expand Down Expand Up @@ -103,6 +114,13 @@ fn test_map() {
assert m['hi'] == 0
assert m.keys().len == 1
assert m.keys()[0] == 'hello'
// Test `.values()`
values := m.values()
assert values.len == 1
assert 80 !in values
assert 101 in values
assert m.values().len == 1
assert m.values()[0] == 101
// //
mut users := map[string]User{}
users['1'] = User{'Peter'}
Expand Down Expand Up @@ -580,6 +598,7 @@ fn test_int_keys() {
4: 16
5: 25
}
assert m2.values() == [9, 16, 25]

assert m2.len == 3
// clone
Expand Down Expand Up @@ -636,6 +655,16 @@ fn test_voidptr_keys() {
assert m.len == 2
}

fn test_voidptr_values() {
mut m := map[string]voidptr{}
v := 5
m['var'] = &v
m['map'] = &m
assert m['var'] == &v
assert m['map'] == &m
assert m.values().len == 2
}

fn test_rune_keys() {
mut m := {
`!`: 2
Expand Down
12 changes: 8 additions & 4 deletions vlib/v/checker/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -1111,7 +1111,7 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
if left_sym.kind == .array && method_name in array_builtin_methods {
return c.array_builtin_method_call(mut node, left_type, c.table.sym(left_type))
} else if (left_sym.kind == .map || final_left_sym.kind == .map)
&& method_name in ['clone', 'keys', 'move', 'delete'] {
&& method_name in ['clone', 'keys', 'values', 'move', 'delete'] {
if left_sym.kind == .map {
return c.map_builtin_method_call(mut node, left_type, left_sym)
} else {
Expand Down Expand Up @@ -1820,12 +1820,16 @@ fn (mut c Checker) map_builtin_method_call(mut node ast.CallExpr, left_type ast.
}
ret_type = ret_type.clear_flag(.shared_f)
}
'keys' {
'keys', 'values' {
if node.args.len != 0 {
c.error('`.keys()` does not have any arguments', node.args[0].pos)
c.error('`.${method_name}()` does not have any arguments', node.args[0].pos)
}
info := left_sym.info as ast.Map
typ := c.table.find_or_register_array(info.key_type)
typ := if method_name == 'keys' {
c.table.find_or_register_array(info.key_type)
} else {
c.table.find_or_register_array(info.value_type)
}
ret_type = ast.Type(typ)
}
'delete' {
Expand Down
2 changes: 2 additions & 0 deletions vlib/v/gen/c/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,8 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
} else if final_left_sym.kind == .map {
if node.name == 'keys' {
name = 'map_keys'
} else if node.name == 'values' {
name = 'map_values'
}
}
if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__')
Expand Down

0 comments on commit 0699f32

Please sign in to comment.