mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-25 18:40:18 -04:00
Replace khash with custom hash set
This commit is contained in:
parent
4c9a9d7e15
commit
cdadda5eb9
1 changed files with 125 additions and 19 deletions
144
src/hashset.hpp
144
src/hashset.hpp
|
|
@ -19,42 +19,49 @@
|
|||
#pragma once
|
||||
|
||||
#include "base_types.h"
|
||||
#include "khash/khash.h"
|
||||
#include "rapidhash/rapidhash.h"
|
||||
|
||||
KHASH_SET_INIT_INT64(hashset);
|
||||
#include <cstring>
|
||||
|
||||
|
||||
// Stores 64-bit hashes only, not keys. Relies on collision
|
||||
// probability being extremely low at 64-bit width.
|
||||
class HashSet
|
||||
{
|
||||
private:
|
||||
static constexpr size_t INLINE_CAPACITY = 8;
|
||||
static constexpr size_t INITIAL_CAPACITY = 128;
|
||||
|
||||
private:
|
||||
u64 _inline[INLINE_CAPACITY] = {};
|
||||
u64 *_table = nullptr;
|
||||
size_t _size = 0;
|
||||
size_t _capacity = 0;
|
||||
size_t _mask = 0;
|
||||
|
||||
public:
|
||||
HashSet()
|
||||
{
|
||||
_set = kh_init(hashset);
|
||||
}
|
||||
HashSet() = default;
|
||||
|
||||
~HashSet()
|
||||
{
|
||||
kh_destroy(hashset,_set);
|
||||
delete[] _table;
|
||||
}
|
||||
|
||||
HashSet(const HashSet&) = delete;
|
||||
HashSet& operator=(const HashSet&) = delete;
|
||||
|
||||
inline
|
||||
int
|
||||
put(const char *str_,
|
||||
cu64 len_)
|
||||
{
|
||||
int rv;
|
||||
u64 h;
|
||||
khint_t key;
|
||||
|
||||
h = rapidhash(str_,len_);
|
||||
if(h == 0)
|
||||
h = 1;
|
||||
|
||||
key = kh_put(hashset,_set,h,&rv);
|
||||
if(rv == 0)
|
||||
return 0;
|
||||
|
||||
kh_key(_set,key) = h;
|
||||
|
||||
return rv;
|
||||
return _put_hash(h);
|
||||
}
|
||||
|
||||
inline
|
||||
|
|
@ -66,11 +73,110 @@ public:
|
|||
|
||||
inline
|
||||
int
|
||||
size(void)
|
||||
size(void) const
|
||||
{
|
||||
return kh_size(_set);
|
||||
return _size;
|
||||
}
|
||||
|
||||
private:
|
||||
khash_t(hashset) *_set;
|
||||
inline
|
||||
int
|
||||
_put_hash(const u64 h_)
|
||||
{
|
||||
if(_table == nullptr)
|
||||
{
|
||||
for(size_t i = 0; i < _size; ++i)
|
||||
{
|
||||
if(_inline[i] == h_)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(_size < INLINE_CAPACITY)
|
||||
{
|
||||
_inline[_size++] = h_;
|
||||
return 1;
|
||||
}
|
||||
|
||||
_grow(INITIAL_CAPACITY);
|
||||
}
|
||||
|
||||
// 75% was benchmarked to be best generally
|
||||
if(((_size + 1) * 4) >= (_capacity * 3))
|
||||
_grow(_capacity * 2);
|
||||
|
||||
size_t idx = h_ & _mask;
|
||||
while(true)
|
||||
{
|
||||
const u64 cur = _table[idx];
|
||||
|
||||
if(cur == 0)
|
||||
{
|
||||
_table[idx] = h_;
|
||||
++_size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(cur == h_)
|
||||
return 0;
|
||||
|
||||
idx = ((idx + 1) & _mask);
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
_grow(size_t min_capacity_)
|
||||
{
|
||||
size_t cap = 1;
|
||||
u64 *table;
|
||||
size_t mask;
|
||||
|
||||
while(cap < min_capacity_)
|
||||
cap <<= 1;
|
||||
|
||||
table = new u64[cap]();
|
||||
mask = cap - 1;
|
||||
|
||||
if(_table == nullptr)
|
||||
{
|
||||
for(size_t i = 0; i < _size; ++i)
|
||||
_insert_existing(table,
|
||||
mask,
|
||||
_inline[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(size_t i = 0; i < _capacity; ++i)
|
||||
{
|
||||
const u64 h = _table[i];
|
||||
if(h == 0)
|
||||
continue;
|
||||
|
||||
_insert_existing(table,
|
||||
mask,
|
||||
h);
|
||||
}
|
||||
|
||||
delete[] _table;
|
||||
}
|
||||
|
||||
_table = table;
|
||||
_capacity = cap;
|
||||
_mask = mask;
|
||||
}
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_insert_existing(u64 *table_,
|
||||
size_t mask_,
|
||||
u64 h_)
|
||||
{
|
||||
size_t idx = h_ & mask_;
|
||||
|
||||
while(table_[idx] != 0)
|
||||
idx = ((idx + 1) & mask_);
|
||||
|
||||
table_[idx] = h_;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue