automatic rehashing
parent
eca4310caf
commit
7265aee0d9
|
@ -339,6 +339,7 @@ namespace detail {
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
T *access_base(const U &key, octa::Size &h) const {
|
T *access_base(const U &key, octa::Size &h) const {
|
||||||
|
if (!p_size) return NULL;
|
||||||
h = get_hash()(key) & (p_size - 1);
|
h = get_hash()(key) & (p_size - 1);
|
||||||
for (Chain *c = p_data.first()[h]; c; c = c->next) {
|
for (Chain *c = p_data.first()[h]; c; c = c->next) {
|
||||||
if (get_eq()(key, B::get_key(c->value)))
|
if (get_eq()(key, B::get_key(c->value)))
|
||||||
|
@ -363,6 +364,7 @@ namespace detail {
|
||||||
|
|
||||||
template<typename ...Args>
|
template<typename ...Args>
|
||||||
octa::Pair<Range, bool> emplace(Args &&...args) {
|
octa::Pair<Range, bool> emplace(Args &&...args) {
|
||||||
|
rehash_ahead(1);
|
||||||
E elem(octa::forward<Args>(args)...);
|
E elem(octa::forward<Args>(args)...);
|
||||||
octa::Size h = get_hash()(B::get_key(elem)) & (p_size - 1);
|
octa::Size h = get_hash()(B::get_key(elem)) & (p_size - 1);
|
||||||
Chain *found = nullptr;
|
Chain *found = nullptr;
|
||||||
|
@ -379,8 +381,10 @@ namespace detail {
|
||||||
B::swap_elem(found->value, elem);
|
B::swap_elem(found->value, elem);
|
||||||
}
|
}
|
||||||
Chain **hch = p_data.first();
|
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);
|
found), ins);
|
||||||
|
rehash_up();
|
||||||
|
return octa::move(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
float load_factor() const { return float(p_len) / p_size; }
|
float load_factor() const { return float(p_len) / p_size; }
|
||||||
|
@ -435,10 +439,28 @@ namespace detail {
|
||||||
delete_chunks(chunks);
|
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) {
|
void reserve(octa::Size count) {
|
||||||
rehash(octa::Size(ceil(count / max_load_factor())));
|
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() {
|
Range each() {
|
||||||
return Range(p_data.first(), p_data.first() + bucket_count());
|
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
|
octa::detail::MapBase<K, T, A>, octa::Pair<const K, T>, K, T, H, C, A
|
||||||
>;
|
>;
|
||||||
Base p_table;
|
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:
|
public:
|
||||||
|
|
||||||
using Key = K;
|
using Key = K;
|
||||||
|
@ -72,8 +88,8 @@ public:
|
||||||
const C &eqf = C(), const A &alloc = A()
|
const C &eqf = C(), const A &alloc = A()
|
||||||
): p_table(size, hf, eqf, alloc) {}
|
): p_table(size, hf, eqf, alloc) {}
|
||||||
|
|
||||||
Map(): Map(octa::Size(1 << 10)) {}
|
Map(): Map(0) {}
|
||||||
explicit Map(const A &alloc): Map(octa::Size(1 << 10), H(), C(), alloc) {}
|
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 A &alloc): Map(size, H(), C(), alloc) {}
|
||||||
Map(octa::Size size, const H &hf, const A &alloc): Map(size, hf, 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) {}
|
Map(Map &&m, const A &alloc): p_table(octa::move(m.p_table), alloc) {}
|
||||||
|
|
||||||
template<typename R>
|
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(),
|
const C &eqf = C(), const A &alloc = A(),
|
||||||
octa::EnableIf<
|
octa::EnableIf<
|
||||||
octa::IsInputRange<R>::value &&
|
octa::IsInputRange<R>::value &&
|
||||||
octa::IsConvertible<RangeReference<R>, Value>::value,
|
octa::IsConvertible<RangeReference<R>, Value>::value,
|
||||||
bool
|
bool
|
||||||
> = true
|
> = true
|
||||||
): p_table(size, hf, eqf, alloc) {
|
): p_table(size ? size : estimate_rsize(range), hf, eqf, alloc) {
|
||||||
for (; !range.empty(); range.pop_front())
|
for (; !range.empty(); range.pop_front())
|
||||||
emplace(range.front());
|
emplace(range.front());
|
||||||
|
p_table.rehash_up();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R>
|
template<typename R>
|
||||||
|
@ -107,7 +124,7 @@ public:
|
||||||
Map(R range, octa::Size size, const H &hf, const A &alloc)
|
Map(R range, octa::Size size, const H &hf, const A &alloc)
|
||||||
: Map(range, size, hf, C(), 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()
|
const H &hf = H(), const C &eqf = C(), const A &alloc = A()
|
||||||
): Map(octa::each(init), size, hf, eqf, alloc) {}
|
): Map(octa::each(init), size, hf, eqf, alloc) {}
|
||||||
|
|
||||||
|
@ -135,14 +152,17 @@ public:
|
||||||
Map &
|
Map &
|
||||||
> operator=(R range) {
|
> operator=(R range) {
|
||||||
clear();
|
clear();
|
||||||
|
p_table.reserve_at_least(estimate_rsize(range));
|
||||||
for (; !range.empty(); range.pop_front())
|
for (; !range.empty(); range.pop_front())
|
||||||
emplace(range.front());
|
emplace(range.front());
|
||||||
|
p_table.rehash_up();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map &operator=(InitializerList<Value> il) {
|
Map &operator=(InitializerList<Value> il) {
|
||||||
Value *beg = il.begin(), *end = il.end();
|
const Value *beg = il.begin(), *end = il.end();
|
||||||
clear();
|
clear();
|
||||||
|
p_table.reserve_at_least(end - beg);
|
||||||
while (beg != end)
|
while (beg != end)
|
||||||
emplace(*beg++);
|
emplace(*beg++);
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -175,12 +195,14 @@ public:
|
||||||
octa::Size h;
|
octa::Size h;
|
||||||
T *v = p_table.access_base(key, h);
|
T *v = p_table.access_base(key, h);
|
||||||
if (v) return *v;
|
if (v) return *v;
|
||||||
|
p_table.rehash_ahead(1);
|
||||||
return p_table.insert(h, key);
|
return p_table.insert(h, key);
|
||||||
}
|
}
|
||||||
T &operator[](K &&key) {
|
T &operator[](K &&key) {
|
||||||
octa::Size h;
|
octa::Size h;
|
||||||
T *v = p_table.access_base(key, h);
|
T *v = p_table.access_base(key, h);
|
||||||
if (v) return *v;
|
if (v) return *v;
|
||||||
|
p_table.rehash_ahead(1);
|
||||||
return p_table.insert(h, octa::move(key));
|
return p_table.insert(h, octa::move(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue