From 4715e09f35b008794b08aa17ac4139cde9730166 Mon Sep 17 00:00:00 2001 From: q66 Date: Mon, 15 Jun 2015 00:18:08 +0100 Subject: [PATCH] hashtble rehash support --- octa/internal/hashtable.h | 48 ++++++++++++++++++++++++++++++++------- octa/map.h | 12 ++++++++++ octa/string.h | 2 +- 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/octa/internal/hashtable.h b/octa/internal/hashtable.h index 840f3f1..aa8fde4 100644 --- a/octa/internal/hashtable.h +++ b/octa/internal/hashtable.h @@ -136,7 +136,7 @@ namespace detail { ~Hashtable() { octa::allocator_deallocate(get_cpalloc(), p_data.first(), p_size); - delete_chunks(); + delete_chunks(p_chunks); } bool empty() const { return p_len == 0; } @@ -190,11 +190,11 @@ namespace detail { return false; } - void delete_chunks() { - for (Chunk *nc; p_chunks; p_chunks = nc) { - nc = p_chunks->next; - octa::allocator_destroy(get_challoc(), p_chunks); - octa::allocator_deallocate(get_challoc(), p_chunks, 1); + void delete_chunks(Chunk *chunks) { + for (Chunk *nc; chunks; chunks = nc) { + nc = chunks->next; + octa::allocator_destroy(get_challoc(), chunks); + octa::allocator_deallocate(get_challoc(), chunks, 1); } } @@ -203,7 +203,7 @@ namespace detail { memset(p_data.first(), 0, p_size * sizeof(Chain *)); p_len = 0; p_unused = nullptr; - delete_chunks(); + delete_chunks(p_chunks); } template @@ -230,13 +230,45 @@ namespace detail { return (insert(h, key) = val); } - float load_factor() const { return p_len / float(p_size); } + float load_factor() const { return float(p_len) / p_size; } float max_load_factor() const { return p_maxlf; } void max_load_factor(float lf) { p_maxlf = lf; } octa::Size bucket_count() const { return p_size; } octa::Size max_bucket_count() const { return Size(~0) / sizeof(Chain); } + void rehash(octa::Size count) { + count = octa::max(count, octa::Size(p_len / max_load_factor())); + + Chain **och = p_data.first(); + Chain **nch = octa::allocator_allocate(get_cpalloc(), count); + memset(nch, 0, count * sizeof(Chain *)); + p_data.first() = nch; + + Chunk *chunks = p_chunks; + octa::Size osize = p_size; + + p_chunks = nullptr; + p_unused = nullptr; + p_size = count; + p_len = 0; + + for (octa::Size i = 0; i < osize; ++i) { + for (Chain *oc = och[i]; oc; oc = oc->next) { + octa::Size h = get_hash()(B::get_key(oc->value)) & (count - 1); + Chain *nc = insert(h); + B::swap_elem(oc->value, nc->value); + } + } + + octa::allocator_deallocate(get_cpalloc(), och, osize); + delete_chunks(chunks); + } + + void reserve(octa::Size count) { + rehash(octa::Size(ceil(count / max_load_factor()))); + } + Range each() { return Range(p_data.first(), bucket_count()); } diff --git a/octa/map.h b/octa/map.h index 32b21a2..a5a191d 100644 --- a/octa/map.h +++ b/octa/map.h @@ -30,6 +30,10 @@ namespace detail { e.first.~K(); new ((K *)&e.first) K(octa::forward(key)); } + static inline void swap_elem(Element &a, Element &b) { + octa::swap(*((K *)&a.first), *((K *)&b.first)); + octa::swap(*((T *)&a.second), *((T *)&b.second)); + } }; } @@ -105,6 +109,14 @@ public: float max_load_factor() const { return p_table.max_load_factor(); } void max_load_factor(float lf) { p_table.max_load_factor(lf); } + void rehash(octa::Size count) { + p_table.rehash(count); + } + + void reserve(octa::Size count) { + p_table.reserve(count); + } + Range each() { return p_table.each(); } ConstRange each() const { return p_table.each(); } ConstRange ceach() const { return p_table.ceach(); } diff --git a/octa/string.h b/octa/string.h index 052b549..49c6fe2 100644 --- a/octa/string.h +++ b/octa/string.h @@ -307,7 +307,7 @@ public: } void swap(StringBase &v) { - p_buf.swap(v); + p_buf.swap(v.p_buf); } Size to_hash() const {