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

master
Hunam 2022-05-06 19:42:01 +02:00 committed by GitHub
parent ce99a306c0
commit 0699f324b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 66 additions and 6 deletions

View File

@ -86,8 +86,8 @@ mut:
// array allocated (with `cap` bytes) on first deletion // array allocated (with `cap` bytes) on first deletion
// has non-zero element when key deleted // has non-zero element when key deleted
all_deleted &u8 all_deleted &u8
values &u8
keys &u8 keys &u8
values &u8
} }
[inline] [inline]
@ -126,8 +126,8 @@ fn (d &DenseArray) has_index(i int) bool {
[inline] [inline]
fn (mut d DenseArray) expand() int { fn (mut d DenseArray) expand() int {
old_cap := d.cap old_cap := d.cap
old_value_size := d.value_bytes * old_cap
old_key_size := d.key_bytes * old_cap old_key_size := d.key_bytes * old_cap
old_value_size := d.value_bytes * old_cap
if d.cap == d.len { if d.cap == d.len {
d.cap += d.cap >> 3 d.cap += d.cap >> 3
unsafe { unsafe {
@ -628,6 +628,31 @@ pub fn (m &map) keys() array {
return keys 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 // warning: only copies keys, does not clone
[unsafe] [unsafe]
fn (d &DenseArray) clone() DenseArray { fn (d &DenseArray) clone() DenseArray {

View File

@ -47,6 +47,16 @@ fn test_keys_many() {
assert keys == strings 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() { fn test_deletes_many() {
mut m := map[string]int{} mut m := map[string]int{}
for i, s in strings { for i, s in strings {
@ -59,6 +69,7 @@ fn test_deletes_many() {
} }
assert m.len == 0 assert m.len == 0
assert m.keys().len == 0 assert m.keys().len == 0
assert m.values().len == 0
} }
struct User { struct User {
@ -103,6 +114,13 @@ fn test_map() {
assert m['hi'] == 0 assert m['hi'] == 0
assert m.keys().len == 1 assert m.keys().len == 1
assert m.keys()[0] == 'hello' 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{} mut users := map[string]User{}
users['1'] = User{'Peter'} users['1'] = User{'Peter'}
@ -580,6 +598,7 @@ fn test_int_keys() {
4: 16 4: 16
5: 25 5: 25
} }
assert m2.values() == [9, 16, 25]
assert m2.len == 3 assert m2.len == 3
// clone // clone
@ -636,6 +655,16 @@ fn test_voidptr_keys() {
assert m.len == 2 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() { fn test_rune_keys() {
mut m := { mut m := {
`!`: 2 `!`: 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 { 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)) 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) } 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 { if left_sym.kind == .map {
return c.map_builtin_method_call(mut node, left_type, left_sym) return c.map_builtin_method_call(mut node, left_type, left_sym)
} else { } 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) ret_type = ret_type.clear_flag(.shared_f)
} }
'keys' { 'keys', 'values' {
if node.args.len != 0 { 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 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) ret_type = ast.Type(typ)
} }
'delete' { 'delete' {

View File

@ -1044,6 +1044,8 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
} else if final_left_sym.kind == .map { } else if final_left_sym.kind == .map {
if node.name == 'keys' { if node.name == 'keys' {
name = 'map_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__') if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__')