mirror of
https://github.com/attractivechaos/klib
synced 2024-11-23 14:49:50 +03:00
added specialized hash table types (map, set, etc)
This commit is contained in:
parent
2d766f4d12
commit
6649d98ba8
111
cpp/khashl.hpp
111
cpp/khashl.hpp
@ -1,15 +1,19 @@
|
||||
#ifndef __AC_KHASHL_HPP
|
||||
#define __AC_KHASHL_HPP
|
||||
|
||||
#include <functional>
|
||||
#include <functional> // for std::equal_to
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace klib {
|
||||
|
||||
/***********
|
||||
* HashSet *
|
||||
***********/
|
||||
|
||||
template<class T, class Hash, class Eq = std::equal_to<T>, 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<class KType, class VType>
|
||||
struct KHashMapBucket { KType key; VType val; };
|
||||
|
||||
template<class T, class Hash, typename khint_t>
|
||||
struct KHashMapHash { khint_t operator() (const T &a) const { return Hash()(a.key); } };
|
||||
|
||||
template<class T, class Eq>
|
||||
struct KHashMapEq { bool operator() (const T &a, const T &b) const { return Eq()(a.key, b.key); } };
|
||||
|
||||
template<class KType, class VType, class Hash, class Eq=std::equal_to<KType>, typename khint_t=uint32_t>
|
||||
class KHashMap : public KHashSet<KHashMapBucket<KType, VType>,
|
||||
KHashMapHash<KHashMapBucket<KType, VType>, Hash, khint_t>,
|
||||
KHashMapEq<KHashMapBucket<KType, VType>, Eq>, khint_t>
|
||||
{
|
||||
typedef KHashMapBucket<KType, VType> bucket_t;
|
||||
typedef KHashSet<bucket_t, KHashMapHash<bucket_t, Hash, khint_t>, KHashMapEq<bucket_t, Eq>, 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<class KType, typename khint_t>
|
||||
struct KHashSetCachedBucket { KType key; khint_t hash; };
|
||||
|
||||
template<class T, typename khint_t>
|
||||
struct KHashCachedHash { khint_t operator() (const T &a) const { return a.hash; } };
|
||||
|
||||
template<class T, class Eq>
|
||||
struct KHashCachedEq { bool operator() (const T &a, const T &b) const { return a.hash == b.hash && Eq()(a.key, b.key); } };
|
||||
|
||||
template<class KType, class Hash, class Eq = std::equal_to<KType>, typename khint_t = uint32_t>
|
||||
class KHashSetCached : public KHashSet<KHashSetCachedBucket<KType, khint_t>,
|
||||
KHashCachedHash<KHashSetCachedBucket<KType, khint_t>, khint_t>,
|
||||
KHashCachedEq<KHashSetCachedBucket<KType, khint_t>, Eq>, khint_t>
|
||||
{
|
||||
typedef KHashSetCachedBucket<KType, khint_t> bucket_t;
|
||||
typedef KHashSet<bucket_t, KHashCachedHash<bucket_t, khint_t>, KHashCachedEq<bucket_t, Eq>, 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<class KType, class VType, typename khint_t>
|
||||
struct KHashMapCachedBucket { KType key; VType val; khint_t hash; };
|
||||
|
||||
template<class KType, class VType, class Hash, class Eq = std::equal_to<KType>, typename khint_t = uint32_t>
|
||||
class KHashMapCached : public KHashSet<KHashMapCachedBucket<KType, VType, khint_t>,
|
||||
KHashCachedHash<KHashMapCachedBucket<KType, VType, khint_t>, khint_t>,
|
||||
KHashCachedEq<KHashMapCachedBucket<KType, VType, khint_t>, Eq>, khint_t>
|
||||
{
|
||||
typedef KHashMapCachedBucket<KType, VType, khint_t> bucket_t;
|
||||
typedef KHashSet<bucket_t, KHashCachedHash<bucket_t, khint_t>, KHashCachedEq<bucket_t, Eq>, 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 */
|
||||
|
5
khashl.h
5
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 */ \
|
||||
|
Loading…
Reference in New Issue
Block a user