diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index e42bc1018c..faed595665 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -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] @@ -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 { @@ -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 { diff --git a/vlib/builtin/map_test.v b/vlib/builtin/map_test.v index 1ffdcd208e..672efc3b09 100644 --- a/vlib/builtin/map_test.v +++ b/vlib/builtin/map_test.v @@ -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 { @@ -59,6 +69,7 @@ fn test_deletes_many() { } assert m.len == 0 assert m.keys().len == 0 + assert m.values().len == 0 } struct User { @@ -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'} @@ -580,6 +598,7 @@ fn test_int_keys() { 4: 16 5: 25 } + assert m2.values() == [9, 16, 25] assert m2.len == 3 // clone @@ -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 diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 7c5d316134..abf4025a07 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -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 { @@ -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' { diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 95864d6304..60a7820fae 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -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__')