diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index 85d741ba21..4eed937b7f 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -7,6 +7,9 @@ import ( strings hash.wyhash ) + +fn C.strcmp(byteptr, byteptr) int + /* This is a very fast hashmap implementation. It has several properties that in combination makes it very fast. Here is a short explanation of each property. @@ -241,7 +244,7 @@ fn (m mut map) set(key string, value voidptr) { // While we might have a match for meta == m.metas[index] { kv_index := m.metas[index + 1] - if key == m.key_values.data[kv_index].key { + if C.strcmp(key.str, m.key_values.data[kv_index].key.str) == 0 { C.memcpy(m.key_values.data[kv_index].value, value, m.value_bytes) return } @@ -317,7 +320,7 @@ fn (m map) get3(key string, zero voidptr) voidptr { index,meta = m.meta_less(index, meta) for meta == m.metas[index] { kv_index := m.metas[index + 1] - if key == m.key_values.data[kv_index].key { + if C.strcmp(key.str, m.key_values.data[kv_index].key.str) == 0 { out := malloc(m.value_bytes) C.memcpy(out, m.key_values.data[kv_index].value, m.value_bytes) return out @@ -336,7 +339,7 @@ fn (m map) exists(key string) bool { index,meta = m.meta_less(index, meta) for meta == m.metas[index] { kv_index := m.metas[index + 1] - if key == m.key_values.data[kv_index].key { + if C.strcmp(key.str, m.key_values.data[kv_index].key.str) == 0 { return true } index += 2 @@ -351,7 +354,7 @@ pub fn (m mut map) delete(key string) { // Perform backwards shifting for meta == m.metas[index] { kv_index := m.metas[index + 1] - if key == m.key_values.data[kv_index].key { + if C.strcmp(key.str, m.key_values.data[kv_index].key.str) == 0 { for (m.metas[index + 2]>>hashbits) > 1 { m.metas[index] = m.metas[index + 2] - probe_inc m.metas[index + 1] = m.metas[index + 3] diff --git a/vlib/v/gen/cheaders.v b/vlib/v/gen/cheaders.v index 393f4c2254..6ebe05a0c4 100644 --- a/vlib/v/gen/cheaders.v +++ b/vlib/v/gen/cheaders.v @@ -212,12 +212,22 @@ void _vcleanup(); #define _ARR_LEN(a) ( (sizeof(a)) / (sizeof(a[0])) ) // ============== wyhash ============== -//Author: Wang Yi +//Author: Wang Yi #ifndef wyhash_version_gamma #define wyhash_version_gamma +#define WYHASH_CONDOM 0 #include #include +#if defined(_MSC_VER) && defined(_M_X64) +#include +#pragma intrinsic(_umul128) +#endif const uint64_t _wyp0=0xa0761d6478bd642full, _wyp1=0xe7037ed1a0b428dbull; +#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) +#define _likely_(x) __builtin_expect(x, 1) +#else +#define _likely_(x) (x) +#endif #ifndef WYHASH_LITTLE_ENDIAN #if defined(_WIN32) || defined(__LITTLE_ENDIAN__) || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) #define WYHASH_LITTLE_ENDIAN 1 @@ -226,58 +236,78 @@ const uint64_t _wyp0=0xa0761d6478bd642full, _wyp1=0xe7037ed1a0b428dbull; #endif #endif #if (WYHASH_LITTLE_ENDIAN) -static inline uint64_t _wyread64(const uint8_t *p){ uint64_t v; memcpy(&v, p, 8); return v;} +static inline uint64_t _wyr8(const uint8_t *p) { uint64_t v; memcpy(&v, p, 8); return v;} +static inline uint64_t _wyr4(const uint8_t *p) { unsigned v; memcpy(&v, p, 4); return v;} #else #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) -static inline uint64_t _wyread64(const uint8_t *p){ uint64_t v; memcpy(&v, p, 8); return __builtin_bswap64(v);} +static inline uint64_t _wyr8(const uint8_t *p) { uint64_t v; memcpy(&v, p, 8); return __builtin_bswap64(v);} +static inline uint64_t _wyr4(const uint8_t *p) { unsigned v; memcpy(&v, p, 4); return __builtin_bswap32(v);} #elif defined(_MSC_VER) -static inline uint64_t _wyread64(const uint8_t *p){ uint64_t v; memcpy(&v, p, 8); return _byteswap_uint64(v);} +static inline uint64_t _wyr8(const uint8_t *p) { uint64_t v; memcpy(&v, p, 8); return _byteswap_uint64(v);} +static inline uint64_t _wyr4(const uint8_t *p) { unsigned v; memcpy(&v, p, 4); return _byteswap_ulong(v);} +#endif +#endif +static inline uint64_t _wyr3(const uint8_t *p, unsigned k) { return (((uint64_t)p[0]) << 16) | (((uint64_t)p[k >> 1]) << 8) | p[k - 1];} +static inline uint64_t _wyrotr(uint64_t v, unsigned k) { return (v >> k) | (v << (64 - k));} +static inline void _wymix128(uint64_t A, uint64_t B, uint64_t *C, uint64_t *D){ + A^=*C; B^=*D; +#ifdef UNOFFICIAL_WYHASH_32BIT + uint64_t hh=(A>>32)*(B>>32), hl=(A>>32)*(unsigned)B, lh=(unsigned)A*(B>>32), ll=(uint64_t)(unsigned)A*(unsigned)B; + *C=_wyrotr(hl,32)^hh; *D=_wyrotr(lh,32)^ll; #else -static inline uint64_t _wyread64(const uint8_t *p){ uint64_t v; memcpy(&v, p, 8); return v;} +#ifdef __SIZEOF_INT128__ + __uint128_t r=A; r*=B; *C=(uint64_t)r; *D=(uint64_t)(r>>64); +#elif defined(_MSC_VER) && defined(_M_X64) + A=_umul128(A,B,&B); *C=A; *D=B; +#else + uint64_t ha=A>>32, hb=B>>32, la=(uint32_t)A, lb=(uint32_t)B, hi, lo; + uint64_t rh=ha*hb, rm0=ha*lb, rm1=hb*la, rl=la*lb, t=rl+(rm0<<32), c=t>32)+(rm1>>32)+c; + *C=lo; *D=hi; #endif #endif - -static inline uint64_t _wyrot32(uint64_t x){ return (x>>32)|(x<<32); } - -static inline uint64_t _wymix64(uint64_t x){ return x*_wyrot32(x); } - +} static inline uint64_t wyhash(const void *key, uint64_t len, uint64_t seed){ const uint8_t *p=(const uint8_t *)key; - uint64_t see1=seed, len0=len; - for(;len>16;len-=16,p+=16){ - seed=_wymix64(_wyread64(p)^seed^_wyp0); - see1=_wymix64(_wyread64(p+8)^see1^_wyp1); + uint64_t i=len, see1=seed; + start: + if(_likely_(i<=16)){ + #ifndef WYHASH_CONDOM + uint64_t shift=(i<8)*((8-i)<<3); + //WARNING: intended reading outside buffer, trading for speed. + _wymix128((_wyr8(p)<>shift)^_wyp1, &seed, &see1); + #else + if(_likely_(i<=8)){ + if(_likely_(i>=4)) _wymix128(_wyr4(p)^_wyp0,_wyr4(p+i-4)^_wyp1, &seed, &see1); + else if (_likely_(i)) _wymix128(_wyr3(p,i)^_wyp0,_wyp1, &seed, &see1); + else _wymix128(_wyp0,_wyp1, &seed, &see1); + } + else _wymix128(_wyr8(p)^_wyp0,_wyr8(p+i-8)^_wyp1, &seed, &see1); + #endif + _wymix128(len,_wyp0, &seed, &see1); + return seed^see1; } - //intended unsafe read, trade for great speed. - uint64_t d0=_wyread64(p), d1=_wyread64(p+len-8); - len=(len<8)*((8-len)<<3); - d0<<=len; d1>>=len; - seed=_wymix64(d0^seed^_wyp0); - see1=_wymix64(d1^see1^_wyp1); - return _wyrot32(_wymix64(len0^seed^see1)) - ^_wymix64(_wyp1^_wyrot32(seed)^see1); + _wymix128(_wyr8(p)^_wyp0,_wyr8(p+8)^_wyp1, &seed, &see1); + i-=16; p+=16; goto start; } - -static inline unsigned wyhash2(unsigned A, unsigned B){ - uint64_t c=(((uint64_t)A)<<32)|B; - c=_wymix64(_wymix64(c^_wyp0)); - return (c>>32)^(unsigned)c; +static inline uint64_t wyhash64(uint64_t A, uint64_t B){ + _wymix128(_wyp0,_wyp1,&A,&B); + _wymix128(0,0,&A,&B); + return A^B; } - -static inline unsigned wyrand(uint64_t *seed){ - *seed+=_wyp0; - uint64_t x=_wymix64(*seed^_wyp1); - return (x>>32)^(unsigned)x; +static inline uint64_t wyrand(uint64_t *seed){ + *seed+=_wyp0; + uint64_t a=0, b=0; + _wymix128(*seed,*seed^_wyp1,&a,&b); + return a^b; } - -static inline float wy2u01(unsigned r){ - const float _wynorm=1.0f/(1ull<<23); - return (r>>9)*_wynorm; +static inline double wy2u01(uint64_t r) { + const double _wynorm=1.0/(1ull<<52); + return (r>>12)*_wynorm; } - -static inline float wy2gau(unsigned r){ - const float _wynorm=1.0f/(1ull<<9); - return ((r&0x3ff)+((r>>10)&0x3ff)+((r>>20)&0x3ff))*_wynorm-3.0f; +static inline double wy2gau(uint64_t r) { + const double _wynorm=1.0/(1ull<<20); + return ((r&0x1fffff)+((r>>21)&0x1fffff)+((r>>42)&0x1fffff))*_wynorm-3.0; } #endif