From 38e5569503f13fe663f8380404bee5c3cc602336 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Sat, 18 Jul 2020 11:14:03 +0200 Subject: [PATCH] all: cached modules fixes --- 0.3_roadmap.txt | 3 +- vlib/builtin/map.v | 5 +- vlib/hash/wyhash.v | 139 +++++++++++++++++++++++++++++++++++++++++ vlib/strconv/f32_str.v | 2 +- vlib/v/builder/cc.v | 2 +- vlib/v/gen/cgen.v | 10 +-- vlib/v/gen/fn.v | 9 ++- vlib/v/util/util.v | 4 +- 8 files changed, 160 insertions(+), 14 deletions(-) create mode 100644 vlib/hash/wyhash.v diff --git a/0.3_roadmap.txt b/0.3_roadmap.txt index dc8f159bda..1a4e4c01bb 100644 --- a/0.3_roadmap.txt +++ b/0.3_roadmap.txt @@ -6,11 +6,12 @@ - thread safe arrays/maps - C2V translator - doom.v -- rune type, replace ustring with []rune +- rune type, replace `ustring` with `[]rune`, fix `byte.str()` - maps with non-string keys - iOS/Android support - make `-autofree` the default - parallel parser (and maybe checker/gen?) +- `recover()` from panics diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index 3b65e4f4df..410c8dd861 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -4,7 +4,8 @@ module builtin import strings -import hash.wyhash +//import hash.wyhash as hash +import hash /* This is a highly optimized hashmap implementation. It has several traits that @@ -225,7 +226,7 @@ fn new_map_init(n, value_bytes int, keys &string, values voidptr) map { [inline] fn (m &map) key_to_index(key string) (u32,u32) { - hash := wyhash.wyhash_c(key.str, u64(key.len), 0) + hash := hash.wyhash_c(key.str, u64(key.len), 0) index := hash & m.cap meta := ((hash >> m.shift) & hash_mask) | probe_inc return u32(index),u32(meta) diff --git a/vlib/hash/wyhash.v b/vlib/hash/wyhash.v new file mode 100644 index 0000000000..4ca53e780f --- /dev/null +++ b/vlib/hash/wyhash.v @@ -0,0 +1,139 @@ +// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +// +// this is an implementation of wyhash v4 +// from https://github.com/wangyi-fudan/wyhash +// +// TODO: use u128 once implemented +// currently the C version performs slightly better +// because it uses 128 bit int when available and +// branch prediction hints. the C version will be +// removed once the perfomance is matched. +// you can test performance by running: +// `v run cmd/tools/bench/wyhash.v` +// try running with and without the `-prod` flag +module hash + +//#flag -I @VROOT/thirdparty/wyhash +//#include "wyhash.h" +fn C.wyhash(byteptr, u64, u64) u64 + + +const ( + wyp0 = u64(0xa0761d6478bd642f) + wyp1 = u64(0xe7037ed1a0b428db) + wyp2 = u64(0x8ebc6af09c88c6e3) + wyp3 = u64(0x589965cc75374cc3) + wyp4 = u64(0x1d8e4e27c47d124f) +) + +[inline] +pub fn wyhash_c(key byteptr, len, seed u64) u64 { + return C.wyhash(key, len, seed) +} + +[inline] +pub fn sum64_string(key string, seed u64) u64 { + return wyhash64(key.str, u64(key.len), seed) +} + +[inline] +pub fn sum64(key []byte, seed u64) u64 { + return wyhash64(byteptr(key.data), u64(key.len), seed) +} + +[inline] +fn wyhash64(key byteptr, len, seed_ u64) u64 { + if len == 0 { + return 0 + } + mut p := key + mut seed := seed_ + mut i := len & 63 + unsafe { + if i < 4 { + seed = wymum(wyr3(p, i) ^ seed ^ wyp0, seed ^ wyp1) + } + else if i <= 8 { + seed = wymum(wyr4(p) ^ seed ^ wyp0, wyr4(p + i - 4) ^ seed ^ wyp1) + } + else if i <= 16 { + seed = wymum(wyr8(p) ^ seed ^ wyp0, wyr8(p + i - 8) ^ seed ^ wyp1) + } + else if i <= 24 { + seed = wymum(wyr8(p) ^ seed ^ wyp0, wyr8(p + 8) ^ seed ^ wyp1) ^ wymum(wyr8(p + i - 8) ^ seed ^ wyp2, seed ^ wyp3) + } + else if i <= 32 { + seed = wymum(wyr8(p) ^ seed ^ wyp0, wyr8(p + 8) ^ seed ^ wyp1) ^ wymum(wyr8(p + 16) ^ seed ^ wyp2, wyr8(p + i - 8) ^ seed ^ wyp3) + } + else { + seed = wymum(wyr8(p) ^ seed ^ wyp0, wyr8(p + 8) ^ seed ^ wyp1) ^ wymum(wyr8(p + 16) ^ seed ^ wyp2, wyr8(p + 24) ^ seed ^ wyp3) ^ wymum(wyr8(p + i - 32) ^ seed ^ wyp1, wyr8(p + i - 24) ^ seed ^ wyp2) ^ wymum(wyr8(p + i - 16) ^ seed ^ wyp3, wyr8(p + i - 8) ^ seed ^ wyp0) + } + } + if i == len { + return wymum(seed, len ^ wyp4) + } + mut see1 := seed + mut see2 := seed + mut see3 := seed + unsafe { + p = p + i + for i = len - i; i >= 64; i -= 64 { + seed = wymum(wyr8(p) ^ seed ^ wyp0, wyr8(p + 8) ^ seed ^ wyp1) + see1 = wymum(wyr8(p + 16) ^ see1 ^ wyp2, wyr8(p + 24) ^ see1 ^ wyp3) + see2 = wymum(wyr8(p + 32) ^ see2 ^ wyp1, wyr8(p + 40) ^ see2 ^ wyp2) + see3 = wymum(wyr8(p + 48) ^ see3 ^ wyp3, wyr8(p + 56) ^ see3 ^ wyp0) + p = p + 64 + } + } + return wymum(seed ^ see1 ^ see2, see3 ^ len ^ wyp4) +} + +[inline] +fn wyrotr(v u64, k u32) u64 { + return (v>>k) | (v<<(64 - k)) +} + +[inline] +pub fn wymum(a, b u64) u64 { + /* + mut r := u128(a) + r = r*b + return (r>>64)^r + */ + mask32 := u32(4294967295) + x0 := a & mask32 + x1 := a>>32 + y0 := b & mask32 + y1 := b>>32 + w0 := x0 * y0 + t := x1 * y0 + (w0>>32) + mut w1 := t & mask32 + w2 := t>>32 + w1 += x0 * y1 + hi := x1 * y1 + w2 + (w1>>32) + lo := a * b + return hi ^ lo +} + +[inline] +fn wyr3(p byteptr, k u64) u64 { + unsafe { + return (u64(p[0])<<16) | (u64(p[k>>1])<<8) | u64(p[k - 1]) + } +} + +[inline] +fn wyr4(p byteptr) u64 { + unsafe { + return u32(p[0]) | (u32(p[1])<