From b9df7aae4d11926953581f8685e155d875249c43 Mon Sep 17 00:00:00 2001 From: ka-weihe Date: Sun, 27 Dec 2020 18:31:50 +0100 Subject: [PATCH] map: cleanup (#7621) --- vlib/builtin/map.v | 56 ++++++++++++++++++++++++------------ vlib/v/gen/auto_eq_methods.v | 6 ++-- vlib/v/gen/cgen.v | 53 ++++++++++++++++++++++++++++++---- vlib/v/gen/cheaders.v | 2 +- 4 files changed, 89 insertions(+), 28 deletions(-) diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index 1c4559b60a..df075f0aca 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -308,11 +308,29 @@ fn map_free_string(pkey voidptr) { fn map_free_nop(_ voidptr) { } -// bootstrap -fn new_map_1(value_bytes int) map { - return new_map(int(sizeof(string)), value_bytes) +fn new_map_2(key_bytes int, value_bytes int, hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn) map { + metasize := int(sizeof(u32) * (init_capicity + extra_metas_inc)) + // for now assume anything bigger than a pointer is a string + has_string_keys := key_bytes > sizeof(voidptr) + return map{ + key_bytes: key_bytes + value_bytes: value_bytes + even_index: init_even_index + cached_hashbits: max_cached_hashbits + shift: init_log_capicity + key_values: new_dense_array(key_bytes, value_bytes) + metas: &u32(vcalloc(metasize)) + extra_metas: extra_metas_inc + len: 0 + has_string_keys: has_string_keys + hash_fn: hash_fn + key_eq_fn: key_eq_fn + clone_fn: clone_fn + free_fn: free_fn + } } +// delete this fn new_map(key_bytes int, value_bytes int) map { metasize := int(sizeof(u32) * (init_capicity + extra_metas_inc)) // for now assume anything bigger than a pointer is a string @@ -372,10 +390,22 @@ fn new_map(key_bytes int, value_bytes int) map { } } -fn new_map_init(n int, value_bytes int, keys &string, values voidptr) map { - return new_map_init_1(n, int(sizeof(string)), value_bytes, keys, values) +fn new_map_init_2(hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn, n int, key_bytes int, value_bytes int, keys voidptr, values voidptr) map { + mut out := new_map_2(key_bytes, value_bytes, hash_fn, key_eq_fn, clone_fn, free_fn) + // TODO pre-allocate n slots + mut pkey := byteptr(keys) + mut pval := byteptr(values) + for _ in 0 .. n { + unsafe { + out.set_1(pkey, pval) + pkey += key_bytes + pval += value_bytes + } + } + return out } +// delete this fn new_map_init_1(n int, key_bytes int, value_bytes int, keys voidptr, values voidptr) map { mut out := new_map(key_bytes, value_bytes) // TODO pre-allocate n slots @@ -454,11 +484,6 @@ fn (mut m map) ensure_extra_metas(probe_count u32) { } } -// bootstrap -fn (mut m map) set(key string, value voidptr) { - m.set_1(&key, value) -} - // Insert new element to the map. The element is inserted if its key is // not equivalent to the key of any other element already in the container. // If the key already exists, its value is changed to the value of the new element. @@ -554,10 +579,6 @@ fn (mut m map) cached_rehash(old_cap u32) { unsafe { free(old_metas) } } -fn (mut m map) get_and_set(key string, zero voidptr) voidptr { - return m.get_and_set_1(&key, zero) -} - // This method is used for assignment operators. If the argument-key // does not exist in the map, it's added to the map along with the zero/default value. // If the key exists, its respective value is returned. @@ -585,10 +606,6 @@ fn (mut m map) get_and_set_1(key voidptr, zero voidptr) voidptr { return voidptr(0) } -fn (m map) get(key string, zero voidptr) voidptr { - return m.get_1(&key, zero) -} - // If `key` matches the key of an element in the container, // the method returns a reference to its mapped value. // If not, a zero/default value is returned. @@ -611,6 +628,7 @@ fn (m &map) get_1(key voidptr, zero voidptr) voidptr { return zero } +// delete this fn (m map) exists(key string) bool { return m.exists_1(&key) } @@ -646,6 +664,7 @@ fn (mut d DenseArray) delete(i int) { } } +// delete this pub fn (mut m map) delete(key string) { m.delete_1(&key) } @@ -690,6 +709,7 @@ pub fn (mut m map) delete_1(key voidptr) { } // bootstrap +// delete this pub fn (m &map) keys() []string { mut keys := []string{len: m.len} mut item := unsafe { byteptr(keys.data) } diff --git a/vlib/v/gen/auto_eq_methods.v b/vlib/v/gen/auto_eq_methods.v index 8fe203a90f..656b441c23 100644 --- a/vlib/v/gen/auto_eq_methods.v +++ b/vlib/v/gen/auto_eq_methods.v @@ -130,9 +130,9 @@ fn (mut g Gen) gen_map_equality_fn(left table.Type) string { fn_builder.writeln('\t\t$value_typ v = (*($value_typ*)map_get_1(&a, &k, &($value_typ[]){ 0 }));') } match value_sym.kind { - .string { fn_builder.writeln('\t\tif (!map_exists(b, k) || string_ne((*(string*)map_get_1(&b, &k, &(string[]){_SLIT("")})), v)) {') } - .function { fn_builder.writeln('\t\tif (!map_exists(b, k) || (*(voidptr*)map_get_1(&b, &k, &(voidptr[]){ 0 })) != v) {') } - else { fn_builder.writeln('\t\tif (!map_exists(b, k) || (*($value_typ*)map_get_1(&b, &k, &($value_typ[]){ 0 })) != v) {') } + .string { fn_builder.writeln('\t\tif (!map_exists_1(&b, &k) || string_ne((*(string*)map_get_1(&b, &k, &(string[]){_SLIT("")})), v)) {') } + .function { fn_builder.writeln('\t\tif (!map_exists_1(&b, &k) || (*(voidptr*)map_get_1(&b, &k, &(voidptr[]){ 0 })) != v) {') } + else { fn_builder.writeln('\t\tif (!map_exists_1(&b, &k) || (*($value_typ*)map_get_1(&b, &k, &($value_typ[]){ 0 })) != v) {') } } fn_builder.writeln('\t\t\treturn false;') fn_builder.writeln('\t\t}') diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index c21339bf7d..d972f2d66f 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -2325,6 +2325,45 @@ fn (mut g Gen) gen_anon_fn_decl(it ast.AnonFn) { g.definitions.write(fn_body) } +fn (mut g Gen) map_fn_ptrs(key_typ table.TypeSymbol) (string, string, string, string) { + mut hash_fn := '' + mut key_eq_fn := '' + mut clone_fn := '' + mut free_fn := '&map_free_nop' + match key_typ.kind { + .byte, .bool, .i8, .char { + hash_fn = '&map_hash_int_2' + key_eq_fn = '&map_eq_int_2' + clone_fn = '&map_clone_int_2' + } + .i16, .u16 { + hash_fn = '&map_hash_int_2' + key_eq_fn = '&map_eq_int_2' + clone_fn = '&map_clone_int_2' + } + .int, .u32 { + hash_fn = '&map_hash_int_4' + key_eq_fn = '&map_eq_int_4' + clone_fn = '&map_clone_int_4' + } + .byteptr, .charptr, .voidptr, .u64, .i64 { + hash_fn = '&map_hash_int_8' + key_eq_fn = '&map_eq_int_8' + clone_fn = '&map_clone_int_8' + } + .string { + hash_fn = '&map_hash_string' + key_eq_fn = '&map_eq_string' + clone_fn = '&map_clone_string' + free_fn = '&map_free_string' + } + else { + verror('map key type not supported') + } + } + return hash_fn, key_eq_fn, clone_fn, free_fn +} + fn (mut g Gen) expr(node ast.Expr) { // println('cgen expr() line_nr=$node.pos.line_nr') // NB: please keep the type names in the match here in alphabetical order: @@ -2513,6 +2552,8 @@ fn (mut g Gen) expr(node ast.Expr) { key_typ_str := g.typ(node.key_type) value_typ_str := g.typ(node.value_type) value_typ := g.table.get_type_symbol(node.value_type) + key_typ := g.table.get_type_symbol(node.key_type) + hash_fn, key_eq_fn, clone_fn, free_fn := g.map_fn_ptrs(key_typ) size := node.vals.len mut shared_styp := '' // only needed for shared &[]{...} mut styp := '' @@ -2535,9 +2576,9 @@ fn (mut g Gen) expr(node ast.Expr) { } if size > 0 { if value_typ.kind == .function { - g.write('new_map_init_1($size, sizeof($key_typ_str), sizeof(voidptr), _MOV(($key_typ_str[$size]){') + g.write('new_map_init_2($hash_fn, $key_eq_fn, $clone_fn, $free_fn, $size, sizeof($key_typ_str), sizeof(voidptr), _MOV(($key_typ_str[$size]){') } else { - g.write('new_map_init_1($size, sizeof($key_typ_str), sizeof($value_typ_str), _MOV(($key_typ_str[$size]){') + g.write('new_map_init_2($hash_fn, $key_eq_fn, $clone_fn, $free_fn, $size, sizeof($key_typ_str), sizeof($value_typ_str), _MOV(($key_typ_str[$size]){') } for expr in node.keys { g.expr(expr) @@ -2554,7 +2595,7 @@ fn (mut g Gen) expr(node ast.Expr) { } g.write('}))') } else { - g.write('new_map(sizeof($key_typ_str), sizeof($value_typ_str))') + g.write('new_map_2(sizeof($key_typ_str), sizeof($value_typ_str), $hash_fn, $key_eq_fn, $clone_fn, $free_fn)') } if g.is_shared { g.write(', .mtx = sync__new_rwmutex()}') @@ -5130,9 +5171,9 @@ fn (mut g Gen) type_default(typ_ table.Type) string { } if sym.kind == .map { info := sym.map_info() - key_type_str := g.typ(info.key_type) - value_type_str := g.typ(info.value_type) - return 'new_map(sizeof($key_type_str), sizeof($value_type_str))' + key_typ := g.table.get_type_symbol(info.key_type) + hash_fn, key_eq_fn, clone_fn, free_fn := g.map_fn_ptrs(key_typ) + return 'new_map_2(sizeof(${g.typ(info.key_type)}), sizeof(${g.typ(info.value_type)}), $hash_fn, $key_eq_fn, $clone_fn, $free_fn)' } // User struct defined in another module. // if typ.contains('__') { diff --git a/vlib/v/gen/cheaders.v b/vlib/v/gen/cheaders.v index 91f25d063e..2430d08346 100644 --- a/vlib/v/gen/cheaders.v +++ b/vlib/v/gen/cheaders.v @@ -272,7 +272,7 @@ static void* g_live_info = NULL; // take the address of an rvalue #define ADDR(type, expr) (&((type[]){expr}[0])) #define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array_push_many(arr, tmp.data, tmp.len);} -#define _IN_MAP(val, m) map_exists(m, val) +#define _IN_MAP(val, m) map_exists_1(&m, &val) // unsigned/signed comparisons static inline bool _us32_gt(uint32_t a, int32_t b) { return a > INT32_MAX || (int32_t)a > b; }