From: Attractive Chaos Date: Thu, 26 Dec 2019 03:41:55 +0000 (-0500) Subject: added specialized hash table types (map, set, etc) X-Git-Url: http://www.kaiwu.me/postgresql/commit/static/gitweb.js?a=commitdiff_plain;h=6649d98ba8929b15291290936616f429a7ffb976;p=klib.git added specialized hash table types (map, set, etc) --- diff --git a/cpp/khashl.hpp b/cpp/khashl.hpp index 318eb70..d9c12ca 100644 --- a/cpp/khashl.hpp +++ b/cpp/khashl.hpp @@ -1,15 +1,19 @@ #ifndef __AC_KHASHL_HPP #define __AC_KHASHL_HPP -#include +#include // for std::equal_to #include #include #include namespace klib { +/*********** + * HashSet * + ***********/ + template, typename khint_t = uint32_t> -class KHashL { +class KHashSet { khint_t bits, count; uint32_t *used; T *keys; @@ -17,15 +21,15 @@ class KHashL { static inline void __kh_set_used(uint32_t *flag, khint_t i) { flag[i>>5] |= 1U<<(i&0x1fU); }; static inline void __kh_set_unused(uint32_t *flag, khint_t i) { flag[i>>5] &= ~(1U<<(i&0x1fU)); }; static inline khint_t __kh_fsize(khint_t m) { return m<32? 1 : m>>5; } - static inline uint32_t __kh_h2b(uint32_t hash, khint_t bits) { return hash * 2654435769U >> (32 - bits); } - static inline uint64_t __kh_h2b(uint64_t hash, khint_t bits) { return hash * 11400714819323198485ULL >> (64 - bits); } + static inline khint_t __kh_h2b(uint32_t hash, khint_t bits) { return hash * 2654435769U >> (32 - bits); } + static inline khint_t __kh_h2b(uint64_t hash, khint_t bits) { return hash * 11400714819323198485ULL >> (64 - bits); } public: - KHashL() : bits(0), count(0), used(0), keys(0) {}; - ~KHashL() { std::free(used); std::free(keys); }; + KHashSet() : bits(0), count(0), used(0), keys(0) {}; + ~KHashSet() { std::free(used); std::free(keys); }; inline khint_t n_buckets() const { return used? khint_t(1) << bits : 0; } inline khint_t end() const { return n_buckets(); } inline khint_t size() const { return count; } - inline T &at(khint_t x) { return keys[x]; }; + inline T &key(khint_t x) { return keys[x]; }; inline bool exist(khint_t x) const { return (__kh_used(used, x) != 0); } void clear(void) { if (!used) return; @@ -125,6 +129,99 @@ public: return 1; } }; + +/*********** + * HashMap * + ***********/ + +template +struct KHashMapBucket { KType key; VType val; }; + +template +struct KHashMapHash { khint_t operator() (const T &a) const { return Hash()(a.key); } }; + +template +struct KHashMapEq { bool operator() (const T &a, const T &b) const { return Eq()(a.key, b.key); } }; + +template, typename khint_t=uint32_t> +class KHashMap : public KHashSet, + KHashMapHash, Hash, khint_t>, + KHashMapEq, Eq>, khint_t> +{ + typedef KHashMapBucket bucket_t; + typedef KHashSet, KHashMapEq, khint_t> hashset_t; +public: + khint_t get(const KType &key) const { + bucket_t t = { .key = key }; + return hashset_t::get(t); + } + khint_t put(const KType &key, int *absent) { + bucket_t t = { .key = key }; + return hashset_t::put(t, absent); + } + inline KType &key(khint_t i) { return hashset_t::key(i).key; } + inline VType &value(khint_t i) { return hashset_t::key(i).val; } +}; + +/**************************** + * HashSet with cached hash * + ****************************/ + +template +struct KHashSetCachedBucket { KType key; khint_t hash; }; + +template +struct KHashCachedHash { khint_t operator() (const T &a) const { return a.hash; } }; + +template +struct KHashCachedEq { bool operator() (const T &a, const T &b) const { return a.hash == b.hash && Eq()(a.key, b.key); } }; + +template, typename khint_t = uint32_t> +class KHashSetCached : public KHashSet, + KHashCachedHash, khint_t>, + KHashCachedEq, Eq>, khint_t> +{ + typedef KHashSetCachedBucket bucket_t; + typedef KHashSet, KHashCachedEq, khint_t> hashset_t; +public: + khint_t get(const KType &key) const { + bucket_t t = { .key = key, .hash = Hash()(key) }; + return hashset_t::get(t); + } + khint_t put(const KType &key, int *absent) { + bucket_t t = { .key = key, .hash = Hash()(key) }; + return hashset_t::put(t, absent); + } + inline KType &key(khint_t i) { return hashset_t::key(i).key; } +}; + +/**************************** + * HashMap with cached hash * + ****************************/ + +template +struct KHashMapCachedBucket { KType key; VType val; khint_t hash; }; + +template, typename khint_t = uint32_t> +class KHashMapCached : public KHashSet, + KHashCachedHash, khint_t>, + KHashCachedEq, Eq>, khint_t> +{ + typedef KHashMapCachedBucket bucket_t; + typedef KHashSet, KHashCachedEq, khint_t> hashset_t; +public: + khint_t get(const KType &key) const { + bucket_t t = { .key = key, .hash = Hash()(key) }; + return hashset_t::get(t); + } + khint_t put(const KType &key, int *absent) { + bucket_t t = { .key = key, .hash = Hash()(key) }; + return hashset_t::put(t, absent); + } + inline KType &key(khint_t i) { return hashset_t::key(i).key; } + inline VType &value(khint_t i) { return hashset_t::key(i).val; } +}; + } #endif /* __AC_KHASHL_HPP */ diff --git a/khashl.h b/khashl.h index 6dc0e18..7731488 100644 --- a/khashl.h +++ b/khashl.h @@ -174,9 +174,8 @@ static kh_inline khint_t __kh_h2b(khint_t hash, khint_t bits) { return hash * 26 key = h->keys[j]; \ __kh_set_unused(h->used, j); \ while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \ - khint_t k, i; \ - k = __hash_fn(key); \ - i = __kh_h2b(k, new_bits); \ + khint_t i; \ + i = __kh_h2b(__hash_fn(key), new_bits); \ while (__kh_used(new_used, i)) i = (i + 1) & new_mask; \ __kh_set_used(new_used, i); \ if (i < n_buckets && __kh_used(h->used, i)) { /* kick out the existing element */ \