automatic rehashing
parent
eca4310caf
commit
7265aee0d9
|
@ -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());
|
||||
}
|
||||
|
|
34
octa/map.h
34
octa/map.h
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue