automatic rehashing

master
Daniel Kolesa 2015-06-16 21:36:16 +01:00
parent eca4310caf
commit 7265aee0d9
2 changed files with 51 additions and 7 deletions

View File

@ -339,6 +339,7 @@ namespace detail {
template<typename U>
T *access_base(const U &key, octa::Size &h) const {
if (!p_size) return NULL;
h = get_hash()(key) & (p_size - 1);
for (Chain *c = p_data.first()[h]; c; c = c->next) {
if (get_eq()(key, B::get_key(c->value)))
@ -363,6 +364,7 @@ namespace detail {
template<typename ...Args>
octa::Pair<Range, bool> emplace(Args &&...args) {
rehash_ahead(1);
E elem(octa::forward<Args>(args)...);
octa::Size h = get_hash()(B::get_key(elem)) & (p_size - 1);
Chain *found = nullptr;
@ -379,8 +381,10 @@ namespace detail {
B::swap_elem(found->value, elem);
}
Chain **hch = p_data.first();
return octa::make_pair(Range(hch + h + 1, hch + bucket_count(),
auto ret = octa::make_pair(Range(hch + h + 1, hch + bucket_count(),
found), ins);
rehash_up();
return octa::move(ret);
}
float load_factor() const { return float(p_len) / p_size; }
@ -435,10 +439,28 @@ namespace detail {
delete_chunks(chunks);
}
void rehash_up() {
if (load_factor() <= max_load_factor()) return;
rehash(octa::Size(size() / max_load_factor()) * 2);
}
void reserve(octa::Size count) {
rehash(octa::Size(ceil(count / max_load_factor())));
}
void reserve_at_least(octa::Size count) {
octa::Size nc = octa::Size(ceil(count / max_load_factor()));
if (p_size > nc) return;
rehash(nc);
}
void rehash_ahead(octa::Size n) {
if (!bucket_count())
reserve(n);
else if ((float(size() + n) / bucket_count()) > max_load_factor())
rehash(octa::Size((size() + 1) / max_load_factor()) * 2);
}
Range each() {
return Range(p_data.first(), p_data.first() + bucket_count());
}

View File

@ -50,6 +50,22 @@ private:
octa::detail::MapBase<K, T, A>, octa::Pair<const K, T>, K, T, H, C, A
>;
Base p_table;
template<typename R>
octa::Size estimate_rsize(const R &range,
octa::EnableIf<octa::IsFiniteRandomAccessRange<R>::value, bool> = true
) {
return range.size();
}
template<typename R>
octa::Size estimate_rsize(const R &,
octa::EnableIf<!octa::IsFiniteRandomAccessRange<R>::value, bool> = true
) {
/* we have no idea how big the range actually is */
return 16;
}
public:
using Key = K;
@ -72,8 +88,8 @@ public:
const C &eqf = C(), const A &alloc = A()
): p_table(size, hf, eqf, alloc) {}
Map(): Map(octa::Size(1 << 10)) {}
explicit Map(const A &alloc): Map(octa::Size(1 << 10), H(), C(), alloc) {}
Map(): Map(0) {}
explicit Map(const A &alloc): Map(0, H(), C(), alloc) {}
Map(octa::Size size, const A &alloc): Map(size, H(), C(), alloc) {}
Map(octa::Size size, const H &hf, const A &alloc): Map(size, hf, C(), alloc) {}
@ -87,16 +103,17 @@ public:
Map(Map &&m, const A &alloc): p_table(octa::move(m.p_table), alloc) {}
template<typename R>
Map(R range, octa::Size size = 1 << 10, const H &hf = H(),
Map(R range, octa::Size size = 0, const H &hf = H(),
const C &eqf = C(), const A &alloc = A(),
octa::EnableIf<
octa::IsInputRange<R>::value &&
octa::IsConvertible<RangeReference<R>, Value>::value,
bool
> = true
): p_table(size, hf, eqf, alloc) {
): p_table(size ? size : estimate_rsize(range), hf, eqf, alloc) {
for (; !range.empty(); range.pop_front())
emplace(range.front());
p_table.rehash_up();
}
template<typename R>
@ -107,7 +124,7 @@ public:
Map(R range, octa::Size size, const H &hf, const A &alloc)
: Map(range, size, hf, C(), alloc) {}
Map(octa::InitializerList<Value> init, octa::Size size = 1 << 10,
Map(octa::InitializerList<Value> init, octa::Size size = 0,
const H &hf = H(), const C &eqf = C(), const A &alloc = A()
): Map(octa::each(init), size, hf, eqf, alloc) {}
@ -135,14 +152,17 @@ public:
Map &
> operator=(R range) {
clear();
p_table.reserve_at_least(estimate_rsize(range));
for (; !range.empty(); range.pop_front())
emplace(range.front());
p_table.rehash_up();
return *this;
}
Map &operator=(InitializerList<Value> il) {
Value *beg = il.begin(), *end = il.end();
const Value *beg = il.begin(), *end = il.end();
clear();
p_table.reserve_at_least(end - beg);
while (beg != end)
emplace(*beg++);
return *this;
@ -175,12 +195,14 @@ public:
octa::Size h;
T *v = p_table.access_base(key, h);
if (v) return *v;
p_table.rehash_ahead(1);
return p_table.insert(h, key);
}
T &operator[](K &&key) {
octa::Size h;
T *v = p_table.access_base(key, h);
if (v) return *v;
p_table.rehash_ahead(1);
return p_table.insert(h, octa::move(key));
}