builtin: add `map.values()` (#14301)

Hunam 2022-05-06 19:42:01 +02:00 committed by Jef Roosens
parent 57b490706b
commit 2572c30d13
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
4 changed files with 66 additions and 6 deletions

View File

@ -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 {

View File

@ -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

View File

@ -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' {

View File

@ -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__')