[libgee/coalesed-hash: 5/6] Temp



commit 66bc6d59326d835e3b84e14da6c41a6aa26a2599
Author: Maciej Piechotka <uzytkownik2 gmail com>
Date:   Sat Jan 5 01:36:21 2013 +0100

    Temp

 gee/hash.vala       | 1127 ++++++++++++++++++++++++++-------------------------
 gee/hashset.vala    |   99 +++---
 tests/testdata.vala |    2 +-
 3 files changed, 620 insertions(+), 608 deletions(-)
---
diff --git a/gee/hash.vala b/gee/hash.vala
index 48e2784..f195828 100644
--- a/gee/hash.vala
+++ b/gee/hash.vala
@@ -47,460 +47,623 @@ class Gee.Hash {
         *      This code contains relativy low level operations. 
         *      Before modifing please read about strict aliasing.
         */
-       internal static inline void init (Flags flags, out char *data) {
-               data = GLib.Slice.alloc (_get_buckets_no (0) * BucketStructure (flags, 0).total_size);
+       internal static inline void init (Flags flags, out void *data) {
+               data = GLib.Slice.alloc0 (11 * BucketStructure (flags, true).total_size);
        }
 
-       internal static inline void cleanup<K, V> (Flags flags, char *data, int dummy_size, int real_size, 
int first) {
-               BucketStructure bs = BucketStructure (flags, dummy_size);
-               for (Bucket curr = _get_first (bs, data, first, dummy_size, real_size); !curr.is_null; curr = 
_get_next (curr, dummy_size, real_size)) {
-                       K key = (owned)curr.key;
-                       K key2 = (owned)key;
-                       key = (owned)key2;
-                       if ((flags & Flags.MAP) != 0) {
-                               V val = (owned)curr.value;
-                               V val2 = (owned)val;
-                               val = (owned)val2;
-                       }
+       internal static inline void cleanup<K, V> (Flags flags, void *data, int dummy_size, int real_size, 
int first) {
+               if (dummy_size < ARRAY_THRESHOLD) {
+                       _cleanup_array<K, V> (flags, data, dummy_size, real_size);
+               } else {
+                       _cleanup_linked<K, V> (flags, data, dummy_size);
                }
        }
 
-       internal static inline bool lookup (Flags flags, char *data, int dummy_size, int real_size, void 
*key, HashDataFunc hash, EqualDataFunc equal, out uint id = null) {
-               id = 0;
-               Bucket bucket = _lookup (BucketStructure (flags, dummy_size), data, dummy_size, real_size, 
key, hash (key), equal);
-               if (!bucket.is_null) {
-                       id = bucket.id;
-                       return true;
+       internal static inline bool lookup (Flags flags, void *data, int dummy_size, int real_size, void 
*key, HashDataFunc hash, EqualDataFunc equal, out void *ptr) {
+               if (dummy_size < ARRAY_THRESHOLD) {
+                       return _lookup_array (flags, data, dummy_size, real_size, key, hash (key), equal, out 
ptr);
                } else {
-                       return false;
+                       ptr = *_lookup_linked (flags, data, dummy_size, key, hash (key), equal);
+                       return ptr != null;
                }
        }
 
-       internal static inline void rehash (Flags flags, ref char *data, ref int dummy_size, ref int 
real_size, int new_size, HashDataFunc hash, EqualDataFunc equal, ref uint first, ref uint last, ref uint 
cellar_free, ref uint address_free) {
-               BucketStructure old_bs = BucketStructure (flags, dummy_size);
-               BucketStructure new_bs = BucketStructure (flags, new_size);
-               _rehash (flags, old_bs, new_bs, ref data, dummy_size, real_size, new_size, hash, equal, ref 
first, ref last, ref cellar_free, ref address_free);
-               dummy_size = real_size = new_size;
+       internal static inline InsertResult insert<K, V> (Flags flags, ref void *data, ref int dummy_size, 
ref int real_size, K key, V? value, HashDataFunc<K> hash, EqualDataFunc<K> equal, bool replace, ref void 
*first, ref void *last) {
+               if (dummy_size < ARRAY_THRESHOLD) {
+                       return _insert_array<K, V> (flags, ref data, ref dummy_size, ref real_size, key, 
value, hash (key), hash, equal, replace, ref first, ref last, true);
+               } else {
+                       return _insert_linked<K, V> (flags, ref data, ref dummy_size, ref real_size, key, 
value, hash (key), hash, equal, replace, ref first, ref last, true);
+               }
        }
 
-       internal static inline InsertResult insert<K, V> (Flags flags, ref char *data, ref int dummy_size, 
ref int real_size, K key, V? value, HashDataFunc<K> hash, EqualDataFunc<K> equal, bool replace, ref uint 
first, ref uint last, ref uint cellar_free, ref uint address_free) {
-               BucketStructure bs = BucketStructure (flags, dummy_size);
-               return _insert<K, V> (flags, bs, ref data, ref dummy_size, ref real_size, key, value, hash 
(key), hash, equal, replace, ref first, ref last, ref cellar_free, ref address_free);
+       internal static inline bool delete<K, V> (Flags flags, ref void *data, ref int dummy_size, ref int 
real_size, K key, out V? value, HashDataFunc<K> hash, EqualDataFunc<K> equal, ref void *first, ref void 
*last) {
+               if (dummy_size < ARRAY_THRESHOLD) {
+                       return _delete_array<K, V> (flags, ref data, ref dummy_size, ref real_size, key, out 
value, hash (key), hash, equal, ref first, ref last);
+               } else {
+                       return _delete_linked<K, V> (flags, ref data, ref dummy_size, ref real_size, key, out 
value, hash (key), hash, equal, ref first, ref last);
+               }
        }
 
-       internal static inline bool delete<K, V> (Flags flags, ref char *data, ref int dummy_size, ref int 
real_size, K key, out V? value, HashDataFunc<K> hash, EqualDataFunc<K> equal, ref uint first, ref uint last, 
ref uint cellar_free, ref uint address_free, bool allow_rehash = true) {
-               BucketStructure bs = BucketStructure (flags, dummy_size);
-               return _delete<K, V> (flags, bs, ref data, ref dummy_size, ref real_size, key, out value, 
hash (key), hash, equal, ref first, ref last, ref cellar_free, ref address_free, allow_rehash);
+       internal static inline void *delete_iter<K, V> (Flags flags, ref char *data, ref int dummy_size, ref 
int real_size, ref void **iter_base, void *iter_ptr, out V value, HashDataFunc<K> hash, EqualDataFunc<K> 
equal, ref void *first, ref void *last) {
+               if (dummy_size < ARRAY_THRESHOLD) {
+                       return _delete_iter_array<K, V> (flags, ref data, ref dummy_size, ref real_size,ref 
iter_base, iter_ptr, out value, hash, equal, ref first, ref last);
+               } else {
+                       return _delete_iter_linked<K, V> (flags, ref data, ref dummy_size, ref real_size,ref 
iter_base, iter_ptr, out value, hash, equal, ref first, ref last);
+               }
        }
 
-       internal static inline int get_first (Flags flags, char *data, int dummy_size, int real_size, int 
first) {
-               Bucket b = _get_first (BucketStructure (flags, dummy_size), data, first, dummy_size, 
real_size);
-               return b.is_null ? -1 : (int)b.id;
+       internal static inline void *get_first (Flags flags, void *data, int dummy_size, int real_size, void 
*first, out void *iter_base) {
+               if (dummy_size < ARRAY_THRESHOLD) {
+                       return (iter_base = _get_first_array (flags, data, dummy_size, real_size));
+               } else {
+                       return _get_first_linked (flags, data, dummy_size, real_size, first, out iter_base);
+               }
        }
 
-       internal static inline int get_next (Flags flags, char *data, int dummy_size, int real_size, int 
curr) {
-               Bucket b = _get_next (Bucket (BucketStructure (flags, dummy_size), data, curr), dummy_size, 
real_size);
-               return b.is_null ? -1 : (int)b.id;
+       internal static inline void get_next (Flags flags, void *data, int dummy_size, int real_size, ref 
void *curr_base, ref void *curr_ptr) {
+               if (dummy_size < ARRAY_THRESHOLD) {
+                       curr_ptr = _get_next_array (flags, data, dummy_size, real_size, curr_ptr);
+               } else {
+                       curr_ptr = _get_next_linked (flags, data, dummy_size, real_size, ref curr_base, 
curr_ptr);
+               }
        }
 
-       internal static inline unowned K get_key<K> (Flags flags, char *data, int size, int curr) {
-               return Bucket (BucketStructure (flags, size), data, curr).key;
+       internal static inline unowned K get_key<K> (Flags flags, void *data, int size, void *curr_ptr) {
+               return Bucket (BucketStructure (flags, size < ARRAY_THRESHOLD), curr_ptr).key;
        }
 
-#if DEBUG
-       internal static inline void dump (Flags flags, char *data, int dummy_size, int real_size, uint first, 
uint last, uint cellar_free, uint address_free) {
-               BucketStructure bs = BucketStructure (flags, dummy_size);
-               stderr.printf ("#    Dumping hashtable...\n");
-               if (bs.next_offset != -1) {
-                       if ((flags & Flags.LINKED_HASH) != 0) {
-                               stderr.printf ("#    First element: %s\n", first != LINK_END ? 
first.to_string () : "(null)");
-                               stderr.printf ("#    Last element: %s\n", last != LINK_END ? last.to_string 
() : "(null)");
+       /**********************************************************************
+        * Linked section                                                     *
+        **********************************************************************/
+
+       private static inline void **_lookup_linked (Flags flags, void *data, int dummy_size, void *key, uint 
hash, EqualDataFunc equal) {
+               BucketStructure bs = BucketStructure (flags, dummy_size < ARRAY_THRESHOLD);
+#if ASSERT
+               assert (bs.next_offset != -1);
+#endif
+               void **curr_ptr = (void **)((char *)data + sizeof(void *) * (_folded_hash (hash, dummy_size) 
% _get_buckets_no (dummy_size)));
+               bool skip_hash = !((flags & Flags.CACHE_HASH) != 0 && (flags & 
Flags.CACHE_HASH_ONLY_IN_ARRAY) == 0);
+               while (*curr_ptr != null) {
+                       Bucket curr = Bucket (bs, *curr_ptr);
+                       if ((skip_hash || curr.hash == hash) && equal (curr.key, key)) {
+                               return curr_ptr;
                        }
-                       stderr.printf ("#    First free element in cellar region: %s\n", cellar_free != 
LINK_END ? cellar_free.to_string () : "(null)");
-                       stderr.printf ("#    First free element in address region: %s\n", address_free != 
LINK_END ? address_free.to_string () : "(null)");
-                       stderr.printf("#    
==========================================================================\n");
-                       int digits_id = (int)GLib.Math.log10(_get_buckets_no (dummy_size));
+                       curr_ptr = curr.next_ptr;
+               }
+               return curr_ptr;
+       }
+
+       private static inline void *_get_first_linked (Flags flags, void *data, int dummy_size, int 
real_size, void *first, out void *curr_base) {
+#if ASSERT
+               BucketStructure bs = BucketStructure (flags, false);
+               assert (bs.next_offset != -1);
+#endif
+               if ((Flags.LINKED_HASH & flags) != 0) {
+                       return first;
+               } else {
                        for (int i = 0; i < _get_buckets_no (dummy_size); i++) {
-                               Bucket b = Bucket (bs, data, i);
-                               if (b.next.is_null && !b.present) {
-                                       stderr.printf ("#     %*d FREE: prev. free = %*d, next free = %*d\n", 
digits_id, i, digits_id, b.fprev_id != LINK_END ? b.fprev_id : -1, digits_id, b.fnext_id != LINK_END ? 
b.fnext_id : -1);
-                               } else if (!b.present) {
-                                       stderr.printf ("#     %*d DELETED: next = %*d\n", digits_id, i, 
digits_id, b.next_id);
-                               } else {
-                                       stderr.printf ("#     %*d OCCUPIED: key = \"%s\"%s%s, next = %*d\n", 
digits_id, i, (string)b.key, (flags & Flags.MAP) != 0 ? ", value = \"%s\"".printf((string)b.value) : "", 
(flags & Flags.LINKED_HASH) != 0 ? ", iter. prev. = %*d, iter. next = %*d".printf (digits_id, b.iprev, 
digits_id, b.inext) : "", digits_id, b.next_id != LINK_END ? b.next_id : -1);
-                               }
-                               if (i + 1 == _get_primary_bucket_no (dummy_size)) {
-                                       stderr.printf("#    
--------------------------------------------------------------------------\n");
+                               void **curr_base_ = (void **)((char *)data + sizeof(void *) * i);
+                               if (*curr_base_ != null) {
+                                       curr_base = curr_base_;
+                                       return *curr_base_;
                                }
                        }
-                       stderr.printf("#    
==========================================================================\n");
+                       return null;
+               }
+       }
+
+       private static inline void *_get_next_linked (Flags flags, void *data, int dummy_size, int real_size, 
ref void *curr_base, void *curr_ptr) {
+               BucketStructure bs = BucketStructure (flags, false);
+#if ASSERT
+               assert (bs.next_offset != -1);
+#endif
+               if ((Flags.LINKED_HASH & flags) != 0) {
+                       return *Bucket (bs, curr_ptr).inext_ptr;
                } else {
-                       stderr.printf("#    
==========================================================================\n");
-                       int digits_id = (int)GLib.Math.log10(ARRAY_THRESHOLD);
-                       for (int i = 0; i < real_size; i++) {
-                               Bucket b = Bucket (bs, data, i);
-                               stderr.printf ("#     %*d OCCUPIED: key = \"%s\"%s\n",  digits_id, i, 
(string)b.key, (flags & Flags.MAP) != 0 ? ", value = \"%s\"".printf((string)b.value) : "");
-                       }
-                       stderr.printf("#    
--------------------------------------------------------------------------\n");
-                       for (int i = real_size; i < ARRAY_THRESHOLD; i++) {
-                               stderr.printf ("#     %*d FREE\n", digits_id, i);
+                       Bucket curr = Bucket (bs, curr_ptr);
+                       if (*curr.next_ptr != null) {
+                               return *curr.next_ptr;
+                       }
+                       for (int i = (int)(((char *)curr_base - (char *)data)/sizeof(void *) + 1); i < 
_get_buckets_no (dummy_size); i++) {
+                               void **_curr_base = (void **)((char *)data + sizeof(void *) * i);
+                               if (*_curr_base != null) {
+                                       curr_base = _curr_base;
+                                       return *_curr_base;
+                               }
                        }
-                       stderr.printf("#    
==========================================================================\n");
+                       curr_base = null;
+                       return null;
                }
        }
-#endif
 
-       private static inline Bucket _lookup (BucketStructure bs, char *data, int dummy_size, int real_size, 
void *key, uint hash, EqualDataFunc equal, out Bucket insert_prev = null, out Bucket delete_prev = null, out 
Bucket first_deleted = null) {
-               insert_prev = Bucket.null (bs, data);
-               delete_prev = Bucket.null (bs, data);
-               first_deleted = Bucket.null (bs, data);
-               if (bs.next_offset != -1) {
-                       Bucket curr = Bucket (bs, data, _folded_hash (hash, dummy_size) % 
_get_primary_bucket_no (dummy_size));
-                       while (!curr.is_null) {
-                               if (curr.present) {
-                                       if ((bs.hash_offset == -1 || curr.hash == hash) && equal (curr.key, 
key)) {
-                                               return curr;
-                                       }
-                               } else if (first_deleted.is_null) {
-                                       first_deleted = curr;
-                               }
-                               if (insert_prev.is_null || curr.id >= _get_primary_bucket_no (dummy_size)) {
-                                       insert_prev = curr;
+       private static inline InsertResult _insert_linked<K, V> (Flags flags, ref char *data, ref int 
dummy_size, ref int real_size, K key, V? value, uint khash, HashDataFunc<K> hash, EqualDataFunc<K> equal, 
bool replace, ref void *first, ref void *last, bool allow_rehash = true) {
+               BucketStructure bs = BucketStructure (flags, false);
+#if ASSERT
+               assert (bs.next_offset != -1);
+#endif
+               void **bucket = _lookup_linked (flags, data, dummy_size, key, khash, equal);
+               if (*bucket != null) {
+                       if (replace) {
+                               Bucket curr = Bucket (bs, *bucket);
+                               K k = (owned)curr.key;
+                               k = key;
+                               curr.key = (owned)k;
+                               if ((flags & Flags.MAP) != 0) {
+                                       V v = (owned)curr.value;
+                                       v = value;
+                                       curr.value = (owned)v;
                                }
-                               assert (curr.id != curr.next.id);
-                               delete_prev = curr;
-                               curr = curr.next;
+                               return InsertResult.REPLACE;
+                       } else {
+                               return InsertResult.FAIL;
                        }
-                       return curr;
                } else {
-                       for (int i = 0; i < real_size; i++) {
-                               Bucket curr = Bucket (bs, data, i);
-                               if ((bs.hash_offset == -1 || curr.hash == hash) && equal (curr.key, key)) {
-                                       return curr;
+                       Bucket curr = Bucket (bs, GLib.Slice.alloc (bs.total_size));
+                       K k = key;
+                       curr.key = (owned)k;
+                       if ((flags & Flags.MAP) != 0) {
+                               V v = value;
+                               curr.value = (owned)v;
+                       }
+                       if ((flags & Flags.CACHE_HASH) != 0 && (flags & Flags.CACHE_HASH_ONLY_IN_ARRAY) == 0) 
{
+                               curr.hash = khash;
+                       }
+                       if ((flags & Flags.LINKED_HASH) != 0) {
+                               if (first == null) {
+#if ASSERT
+                                       assert (last == null)
+#endif
+                                       first = curr._data;
+                                       last = curr._data;
+                                       *curr.iprev_ptr = null;
+                               } else {
+                                       Bucket last_bucket = Bucket (bs, last);
+#if ASSERT
+                                       assert (*last_bucket.inext_ptr == null)
+#endif
+                                       *last_bucket.inext_ptr = curr._data;
                                }
+                               *curr.inext_ptr = null;
+                       }
+                       *curr.next_ptr = null;
+                       *bucket = curr._data;
+                       real_size++;
+                       if (allow_rehash  && 3 * _get_buckets_no (dummy_size) < _get_buckets_no (real_size) 
|| 3 * _get_buckets_no (real_size) < _get_buckets_no (dummy_size)) {
+                               _rehash_linked<K, V> (flags, ref data, ref dummy_size, ref real_size, 
real_size, hash, equal, ref first, ref last, false);
                        }
-                       return Bucket.null (bs, data);
+                       return InsertResult.INSERT;
                }
        }
 
-       private static inline Bucket _get_first (BucketStructure bs, char *data, uint first, int dummy_size, 
int real_size) {
-               if (bs.inext_offset != -1) {
-                       return Bucket (bs, data, first);
-               } else {
-                       return _get_next (Bucket (bs, data, -1), dummy_size, real_size);
+       private static inline bool _delete_linked<K, V> (Flags flags, ref char *data, ref int dummy_size, ref 
int real_size, K key, out V? value, uint khash, HashDataFunc<K> hash, EqualDataFunc<K> equal, ref void 
*first, ref void *last, bool allow_rehash = true) {
+               BucketStructure bs = BucketStructure (flags, false);
+#if ASSERT
+               assert (bs.next_offset != -1);
+#endif
+               value = null;
+               void **location = _lookup_linked (flags, data, dummy_size, key, khash, equal);
+               if (*location == null) {
+                       return false;
+               }
+               Bucket curr = Bucket (bs, *location);
+               K k = (owned)curr.key;
+               _delete_helper<K> ((owned)k);
+               if ((flags & Flags.MAP) != 0) {
+                       V v = (owned)curr.value;
+                       _delete_helper<V> ((owned)v);
                }
+               if ((flags & Flags.LINKED_HASH) != 0) {
+#if ASSERT
+                       assert ((first == *location) == (*curr.iprev_ptr == null));
+                       assert ((last  == *location) == (*curr.inext_ptr == null));
+#endif
+                       if (first == *location) {
+                               first = *curr.inext_ptr;
+                       } else {
+                               *curr.iprev.inext_ptr = *curr.inext_ptr;
+                       }
+                       if (last == *location) {
+                               last = *curr.iprev_ptr;
+                       } else {
+                               *curr.inext.iprev_ptr = *curr.iprev_ptr;
+                       }
+               }
+               *location = *curr.next_ptr;
+               GLib.Slice.free (bs.total_size, curr._data);
+               real_size--;
+               if (allow_rehash) {
+                       if (real_size < ARRAY_THRESHOLD) {
+                               _rehash_linked_to_array<K, V> (flags, ref data, ref dummy_size, ref 
real_size, real_size, hash, equal, ref first, ref last);
+                       } else if (3 * _get_buckets_no (dummy_size) < _get_buckets_no (real_size) || 3 * 
_get_buckets_no (real_size) < _get_buckets_no (dummy_size)) {
+                               _rehash_linked<K, V> (flags, ref data, ref dummy_size, ref real_size, 
real_size, hash, equal, ref first, ref last);
+                       }
+               }
+               return true;
        }
 
-       private static inline Bucket _get_next (Bucket curr, int dummy_size, int real_size) {
-               if (curr._bs.inext_offset != -1) {
-                       return curr.inext;
-               } else if (curr._bs.next_offset != -1) {
-                       for (uint i = curr._id + 1; i < _get_buckets_no(dummy_size); i++) {
-                               curr = Bucket (curr._bs, curr._data, i);
-                               if (curr.present) {
-                                       return curr;
+       private static inline void *_delete_iter_linked<K, V> (Flags flags, ref char *data, ref int 
dummy_size, ref int real_size, ref void **iter_base, void *iter_ptr, out V value, HashDataFunc<K> hash, 
EqualDataFunc<K> equal, ref void *first, ref void *last) {
+               BucketStructure bs = BucketStructure (flags, false);
+               void **curr_base = iter_base;
+               void *curr_ptr = iter_ptr;
+               iter_ptr = _get_next_linked (flags, data, dummy_size, real_size, ref iter_base, iter_ptr);
+               while (true) {
+#if ASSERT
+                       assert (*curr_base != null);
+#endif
+                       if (*curr_base == curr_ptr) {
+                               Bucket curr = Bucket (bs, curr_ptr);
+                               *curr_base = *curr.next_ptr;
+                               K k = (owned)curr.key;
+                               _delete_helper<K> ((owned)k);
+                               if ((flags & Flags.MAP) != 0) {
+                                       V v = (owned)curr.value;
+                                       _delete_helper<V> ((owned)v);
+                               }
+                               real_size--;
+                               if ((flags & Flags.LINKED_HASH) != 0) {
+#if ASSERT
+                                       assert ((first == curr_ptr) == (*curr.iprev_ptr == null));
+                                       assert ((last  == curr_ptr) == (*curr.inext_ptr == null));
+#endif
+                                       if (first == curr_ptr) {
+                                               first = *curr.inext_ptr;
+                                       } else {
+                                               *curr.iprev.inext_ptr = *curr.inext_ptr;
+                                       }
+                                       if (last == curr_ptr) {
+                                               last = *curr.iprev_ptr;
+                                       } else {
+                                               *curr.inext.iprev_ptr = *curr.iprev_ptr;
+                                       }
+
+                                       if (dummy_size < ARRAY_THRESHOLD) {
+                                               if (iter_ptr != null) {
+                                                       Bucket next = Bucket (bs, iter_ptr);
+                                                       K nk = next.key;
+                                                       uint khash = ((flags & Flags.CACHE_HASH) != 0 && 
(flags & Flags.CACHE_HASH_ONLY_IN_ARRAY) == 0) ? next.hash : hash (nk);
+                                                       _rehash_linked_to_array<K, V> (flags, ref data, ref 
dummy_size, ref real_size, real_size, hash, equal, ref first, ref last);                                      
              
+                                                       bool b = _lookup_array (flags, data, dummy_size, 
real_size, nk, khash, equal, out iter_ptr);
+                                                       assert (b);
+                                               } else {
+                                                       _rehash_linked_to_array<K, V> (flags, ref data, ref 
dummy_size, ref real_size, real_size, hash, equal, ref first, ref last);
+                                               }
+                                       } else if (3 * _get_buckets_no (dummy_size) < _get_buckets_no 
(real_size) || 3 * _get_buckets_no (real_size) < _get_buckets_no (dummy_size)) {
+                                               _rehash_linked<K, V> (flags, ref data, ref dummy_size, ref 
real_size, real_size, hash, equal, ref first, ref last);
+                                       }
                                }
+                               return iter_ptr;
+                       } else {
+                               Bucket curr = Bucket (bs, *curr_base);
+                               curr_base = curr.next_ptr;
                        }
-                       return Bucket.null (curr._bs, curr._data);
-               } else {
-                       return (curr._id + 1 < real_size) ? Bucket (curr._bs, curr._data, curr._id + 1): 
Bucket.null (curr._bs, curr._data);
                }
        }
 
-       private static inline InsertResult _insert<K, V> (Flags flags, BucketStructure bs, ref char *data, 
ref int dummy_size, ref int real_size, K key, V? value, uint khash, HashDataFunc<K> hash, EqualDataFunc<K> 
equal, bool replace, ref uint first, ref uint last, ref uint cellar_free, ref uint address_free, bool 
allow_rehash = true) {
-               if (bs.next_offset != -1) {
-                       // STEP 1: Lookup bucket
-                       Bucket first_deleted;
-                       Bucket prev;
-                       Bucket curr = _lookup (bs, data, dummy_size, real_size, key, khash, equal, out prev, 
null, out first_deleted);
-                       if (!curr.is_null) {
-                               if (replace) {
+       private static inline void _rehash_linked_to_array<K, V> (Flags flags, ref char *data, ref int 
dummy_size, ref int real_size, int new_size, HashDataFunc hash, EqualDataFunc equal, ref void *first, ref 
void *last) {
+               BucketStructure bs = BucketStructure (flags, false);
+               BucketStructure new_bs = BucketStructure (flags, true);
+#if ASSERT
+               assert (bs.next_offset != -1);
+               assert (new_bs.next_offset != -1);
+               assert (new_size < ARRAY_THRESHOLD);
+#endif
+               char *old_data = data;
+               int old_dummy_size = dummy_size;
+               int old_real_size = real_size;
+               data = GLib.Slice.alloc (ARRAY_THRESHOLD * new_bs.total_size);
+               first = null;
+               last = null;
+               dummy_size = new_size;
+               real_size = 0;
+               void *iter_base, iter_ptr;
+               for (iter_ptr = _get_first_linked (flags, old_data, old_dummy_size, real_size, first, out 
iter_base); iter_ptr != null; iter_ptr = _get_next_linked (flags, old_data, old_dummy_size, old_real_size, 
ref iter_base, iter_ptr)) {
+                       Bucket bucket = Bucket (bs, iter_ptr);
+#if ASSERT
+                       char *data_save = data;
+                       int real_size_save = real_size;
+                       int dummy_size_save = dummy_size;
+#endif
+                       K key = (owned)bucket.key;
+                       V? value = ((flags & Flags.MAP) != 0) ? (owned)bucket.value : null;
+                       uint khash = ((flags & Flags.CACHE_HASH) != 0 && (flags & 
Flags.CACHE_HASH_ONLY_IN_ARRAY) == 0) ? bucket.hash : hash (key);
+                       InsertResult it = _insert_array<K, V> (flags, ref data, ref dummy_size, ref 
real_size, key, value, khash, hash, equal, false, ref first, ref last, false);
+#if ASSERT
+                       assert (it == InsertResult.INSERT);
+                       assert (data_save == data);
+                       assert (real_size_save + 1 == real_size);
+                       assert (dummy_size_save == dummy_size);
+#endif
+               }
+               _cleanup_linked<K, V> (flags, old_data, old_dummy_size, true);
+       }
+
+       private static inline void _rehash_linked<K, V> (Flags flags, ref char *data, ref int dummy_size, ref 
int real_size, int new_size, HashDataFunc hash, EqualDataFunc equal, ref void *first, ref void *last, bool 
to_array = false) {
+               BucketStructure bs = BucketStructure (flags, false);
+#if ASSERT
+               assert (bs.next_offset != -1);
+               assert (new_size >= ARRAY_THRESHOLD);
+#endif
+               void *old_data = data;
+               int old_dummy_size = dummy_size;
+               int old_real_size = real_size;
+               data = GLib.Slice.alloc0 (sizeof(void *) * _get_buckets_no (new_size));
+               first = null;
+               last = null;
+               dummy_size = new_size;
+               real_size = 0;
+               bool skip_hash = !((flags & Flags.CACHE_HASH) != 0 && (flags & 
Flags.CACHE_HASH_ONLY_IN_ARRAY) == 0);
+               for (void **iter_base = (void **)old_data; iter_base < (void **)old_data + _get_buckets_no 
(old_dummy_size); iter_base++) {
+                       void *iter_ptr = *iter_base; 
+                       while (iter_ptr != null) {
+                               Bucket bucket = Bucket (bs, iter_ptr);
+                               void *next_ptr = *bucket.next_ptr;
+                               *bucket.next_ptr = null;
+                               uint khash = skip_hash ? hash (bucket.key) : bucket.hash;
+                               void **new_base = (void **)((char *)data + sizeof (void *) * (khash % 
_get_buckets_no (new_size)));
+                               *bucket.next_ptr = *new_base;
+                               *new_base = iter_ptr;
+                               real_size++;
+                               iter_ptr = next_ptr;
+                       }
+               }
+               GLib.Slice.free (sizeof(void *) * _get_buckets_no (old_dummy_size), old_data);
+       }
+
+       private static inline void _cleanup_linked<K, V> (Flags flags, void *data, int dummy_size, bool 
skip_destroy = false) {
+               BucketStructure bs = BucketStructure (flags, false);
+               for (void **base_ptr = (void **)data; base_ptr < (void **)((char *)data + sizeof(void *) * 
_get_buckets_no (dummy_size)); base_ptr++) {
+                       void *iter_ptr = *base_ptr;
+                       while (iter_ptr != null) {
+                               Bucket curr = Bucket (bs, iter_ptr);
+                               if (!skip_destroy) {
                                        K k = (owned)curr.key;
-                                       k = key;
-                                       curr.key = (owned)k;
-                                       if (bs.value_offset != -1) {
+                                       _delete_helper<K> ((owned)k);
+                                       if ((flags & Flags.MAP) != 0) {
                                                V v = (owned)curr.value;
-                                               v = value;
-                                               curr.value = (owned)v;
+                                               _delete_helper<V> ((owned)v);
                                        }
-                                       return InsertResult.REPLACE;
-                               } else {
-                                       return InsertResult.FAIL;
                                }
+                               void *new_iter_ptr = *curr.next_ptr;
+                               GLib.Slice.free (bs.total_size, iter_ptr);
+                               iter_ptr = new_iter_ptr;
                        }
-                       // STEP 2: Allocate new bucket
-                       if (!first_deleted.is_null) {
-                               curr = first_deleted;
-                               if (curr.next.is_null) {
-                                       _allocate (curr, ref cellar_free, ref address_free);
-                               } else {
-                               }
-                       } else {
-                               curr = _allocate_any (bs, data, ref cellar_free, ref address_free);
-                               if (GLib.unlikely(curr.is_null)) {
-                                       // This should be rare
-                                       assert (allow_rehash);
-                                       BucketStructure new_bs = BucketStructure (flags, real_size + 1);
-                                       _rehash (flags, bs, new_bs, ref data, dummy_size, real_size, 
real_size + 1, hash, equal, ref first, ref last, ref cellar_free, ref address_free, true);
-                                       dummy_size = real_size = real_size + 1;
-                                       bs = new_bs;
-                                       curr = _lookup (bs, data, dummy_size, real_size, key, khash, equal, 
out prev);
-                                       assert (curr.is_null);
-                                       curr = _allocate_any (bs, data, ref cellar_free, ref address_free);
-                                       assert (!curr.is_null);
-                                       allow_rehash = false;
-                               }
-                               if (!prev.is_null) {
-                                       curr.next = prev.next;
-                                       prev.next = curr;
-                               } else {
-                                       curr.next = Bucket.null (bs, data);
-                               }
+               }
+               GLib.Slice.free (sizeof(void *) * _get_buckets_no (dummy_size), data);
+       }
+
+       /**********************************************************************
+        * Array section                                                      *
+        **********************************************************************/
+       private static inline bool _lookup_array (Flags flags, void *data, int dummy_size, int real_size, 
void *key, uint hash, EqualDataFunc equal, out void *location) {
+               assert (real_size < ARRAY_THRESHOLD);
+               BucketStructure bs = BucketStructure (flags, true);
+#if ARRAY
+               assert (bs.next_offset == -1);
+#endif
+               bool skip_hash = !((flags & Flags.CACHE_HASH) != 0);
+               for (int i = 0; i < real_size; i++) {
+                       Bucket curr = Bucket (bs, (void *)((char *)data + bs.total_size * i));
+                       if ((skip_hash || curr.hash == hash) && equal (curr.key, key)) {
+                               location = (void *)((char *)data + bs.total_size * i);
+                               return true;
                        }
-                       // STEP 3: Insert bucket
-                       curr.present = true;
-                       {
-                               K k = key;
+               }
+               location = (void *)((char *)data + bs.total_size * real_size);
+               return false;
+       }
+
+       private static inline void *_get_first_array (Flags flags, void *data, int dummy_size, int real_size) 
{
+               return real_size != 0 ? data : null;
+       }
+
+       private static inline void *_get_next_array (Flags flags, void *data, int dummy_size, int real_size, 
void *curr_ptr) {
+               BucketStructure bs = BucketStructure (flags, true);
+#if ARRAY
+               assert (bs.next_offset == -1);
+#endif
+               if ((int)(((char *)curr_ptr - (char *)data)/bs.total_size + 1) < real_size) {
+                       return (void *)((char *)curr_ptr + bs.total_size);
+               } else {
+                       return null;
+               }
+       }
+
+       private static inline InsertResult _insert_array<K, V> (Flags flags, ref char *data, ref int 
dummy_size, ref int real_size, K key, V? value, uint khash, HashDataFunc<K> hash, EqualDataFunc<K> equal, 
bool replace, ref void *first, ref void *last, bool allow_rehash = true) {
+               BucketStructure bs = BucketStructure (flags, true);
+#if ASSERT
+               assert (bs.next_offset == -1);
+#endif
+               void *location;
+               if (_lookup_array (flags, data, dummy_size, real_size, key, khash, equal, out location)) {
+                       if (replace) {
+                               Bucket curr = Bucket (bs, location);
+                               K k = (owned)curr.key;
+                               k = key;
                                curr.key = (owned)k;
-                       }
-                       {
-                               V v = value;
-                               curr.value = (owned)v;
-                       }
-                       curr.hash = khash;
-                       if (last == LINK_END) {
-                               first = curr._id;
-                               last = curr._id;
-                               curr.iprev_id = LINK_END;
-                               curr.inext_id = LINK_END;
-                       } else {
-                               Bucket lastb = Bucket (bs, data, last);
-                               lastb.inext = curr;
-                               curr.inext_id = LINK_END;
-                               curr.iprev_id = last;
-                               last = curr._id;
-                       }
-                       if (allow_rehash) {
-                               BucketStructure new_bs = BucketStructure (flags, real_size + 1);
-                               _rehash (flags, bs, new_bs, ref data, dummy_size, real_size + 1, real_size + 
1, hash, equal, ref first, ref last, ref cellar_free, ref address_free);
-                               real_size = dummy_size = real_size + 1;
+                               if ((flags & Flags.MAP) != 0) {
+                                       V v = (owned)curr.value;
+                                       v = value;
+                                       curr.value = (owned)v;
+                               }
+                               return InsertResult.REPLACE;
                        } else {
-                               real_size++;
+                               return InsertResult.FAIL;
                        }
-                       return InsertResult.INSERT;
                } else {
-                       for (int i = 0; i < real_size; i++) {
-                               Bucket curr = Bucket (bs, data, i);
-                               if ((bs.hash_offset == -1 || curr.hash == khash) && equal (curr.key, key)) {
-                                       if (replace) {
-                                               K k = (owned)curr.key;
-                                               k = key;
-                                               curr.key = (owned)k;
-                                               if (bs.value_offset != -1) {
-                                                       V v = (owned)curr.value;
-                                                       v = value;
-                                                       curr.value = (owned)v;
-                                               }
-                                               return InsertResult.REPLACE;
-                                       } else {
-                                               return InsertResult.FAIL;
-                                       }
-                               }
-                       }
-                       assert (real_size <= ARRAY_THRESHOLD);
-                       Bucket curr = Bucket (bs, data, real_size);
-                       {
-                               K k = key;
-                               curr.key = (owned)k;
-                       }
-                       {
+                       Bucket curr = Bucket (bs, location);
+                       K k = key;
+                       curr.key = (owned)k;
+                       if ((flags & Flags.MAP) != 0) {
                                V v = value;
                                curr.value = (owned)v;
                        }
-                       curr.hash = khash;
-                       if (allow_rehash) {
-                               BucketStructure new_bs = BucketStructure (flags, real_size + 1);
-                               _rehash (flags, bs, new_bs, ref data, dummy_size, real_size + 1, real_size + 
1, hash, equal, ref first, ref last, ref cellar_free, ref address_free);
-                               real_size = dummy_size = real_size + 1;
-                       } else {
-                               real_size++;
+                       if ((flags & Flags.CACHE_HASH) != 0) {
+                               curr.hash = khash;
+                       }
+                       real_size++;
+#if ASSERT
+                       assert (real_size != ARRAY_THRESHOLD || allow_rehash);
+#endif
+                       if (allow_rehash && real_size == ARRAY_THRESHOLD) {
+                               _rehash_array<K, V> (flags, ref data, ref dummy_size, ref real_size, 
real_size, hash, equal, ref first, ref last);
                        }
                        return InsertResult.INSERT;
                }
        }
 
-       private static inline bool _delete<K, V> (Flags flags, BucketStructure bs, ref char *data, ref int 
dummy_size, ref int real_size, K key, out V? value, uint khash, HashDataFunc<K> hash, EqualDataFunc<K> equal, 
ref uint first, ref uint last, ref uint cellar_free, ref uint address_free, bool allow_rehash = true) {
+       private static inline bool _delete_array<K, V> (Flags flags, ref char *data, ref int dummy_size, ref 
int real_size, K key, out V? value, uint khash, HashDataFunc<K> hash, EqualDataFunc<K> equal, ref void 
*first, ref void *last) {
+               BucketStructure bs = BucketStructure (flags, true);
+#if ASSERT
+               assert (bs.next_offset == -1);
+#endif
                value = null;
-               Bucket prev;
-               Bucket curr = _lookup (bs, data, dummy_size, real_size, key, khash, equal, null, out prev);
-               if (!curr.is_null) {
-                       if (bs.key_offset != -1) {
-                               K *kp = curr.key;
-                               K k = (owned)kp;
-                       }
-                       if (bs.value_offset != -1) {
-                               V *vp = curr.value;
-                               value = (owned)vp;
-                       }
-                       if (bs.inext_offset != -1) {
-                               assert ((first == curr._id) == curr.iprev.is_null);
-                               assert ((last == curr._id) == curr.inext.is_null);
-                               if (!curr.iprev.is_null) {
-                                       curr.iprev.inext = curr.inext;
-                               } else {
-                                       first = curr.inext._id;
-                               }
-                               if (!curr.iprev.is_null) {
-                                       curr.inext.iprev = curr.iprev;
-                               } else {
-                                       last = curr.iprev_id;
-                               }
-                       }
-                       if (bs.next_offset != -1) {
-                               if (prev.is_null) {
-                                       // CASE 1: head of chain
-                                       curr.present = false;
-                                       if (curr.next.is_null) {
-                                               _release (curr, dummy_size, ref cellar_free, ref 
address_free);
-                                       }
-                               } else if (curr._id >= _get_primary_bucket_no (dummy_size)) {
-                                       // CASE 2: in cellar region
-                                       prev.next = curr.next;
-                                       curr.present = false;
-                                       curr.next = Bucket.null (bs, data);
-                                       _release (curr, dummy_size, ref cellar_free, ref address_free);
-                               } else {
-                                       // CASE 3: in address region
-                                       curr.present = false;
-                                       Bucket j = curr.next;
-                                       prev.next = Bucket.null (bs, data);
-                                       curr.next = Bucket.null (bs, data);
-                                       while (!j.is_null) {
-                                               Bucket k = Bucket (bs, data, j._hash (hash) % 
_get_primary_bucket_no (dummy_size));
-                                               while (!k.next.is_null && k.next._id >= 
_get_primary_bucket_no (dummy_size)) {
-                                                       k = k.next;
-                                               }
-                                               Bucket nj = j.next;
-                                               j.next = k.next;
-                                               k.next = j;
-                                               j = nj;
-                                       }
-                                       if (curr.next.is_null) {
-                                               _release (curr, dummy_size, ref cellar_free, ref 
address_free);
-                                       }
-                                       if (!prev.present && prev.next.is_null) {
-                                               _release (prev, dummy_size, ref cellar_free, ref 
address_free);
-                                       }
-                               }
-                       } else {
-                               GLib.Memory.move (data + bs.total_size * curr._id, data + bs.total_size * 
(curr._id + 1), bs.total_size * (real_size - curr._id - 1));
-                       }
-                       if (allow_rehash) {
-                               BucketStructure new_bs = BucketStructure (flags, real_size - 1);
-                               _rehash (flags, bs, new_bs, ref data, dummy_size, real_size - 1, real_size - 
1, hash, equal, ref first, ref last, ref cellar_free, ref address_free);
-                               dummy_size = real_size = real_size - 1;
-                       } else {
-                               real_size--;
+               void *location;
+               if (_lookup_array (flags, data, dummy_size, real_size, key, khash, equal, out location)) {
+                       Bucket curr = Bucket (bs, location);
+                       K k = (owned)curr.key;
+                       _delete_helper<K> ((owned)k);
+                       if ((flags & Flags.MAP) != 0) {
+                               V v = (owned)curr.value;
+                               _delete_helper<V> ((owned)v);
                        }
+                       char *next = (char *)location + bs.total_size;
+                       char *end = (char *)data + bs.total_size * real_size;
+                       GLib.Memory.move (location, next, end - next);
+                       dummy_size = --real_size;
                        return true;
                } else {
                        return false;
                }
        }
 
-       private static inline void _rehash (Flags flags, BucketStructure old_bs, BucketStructure new_bs, ref 
char *data, int old_dummy_size, int old_real_size, int new_size, HashDataFunc hash, EqualDataFunc equal, ref 
uint first, ref uint last, ref uint cellar_free, ref uint address_free, bool force = false) {
-               if (!force && _get_buckets_no(old_dummy_size) == _get_buckets_no(new_size))
-                       return;
-               char *new_data = GLib.Slice.alloc0 (_get_buckets_no(new_size) * new_bs.total_size);
-               cellar_free = (_get_primary_bucket_no (new_size) != _get_buckets_no(new_size)) ? 
_get_primary_bucket_no (new_size) : LINK_END;
-               address_free = 0;
-               for (uint i = 0; i < _get_buckets_no(new_size); i++) {
-                       Bucket b = Bucket (new_bs, new_data, i);
-                       b.fprev = (i == 0 || i == _get_primary_bucket_no (new_size)) ? Bucket.null (new_bs, 
new_data) : Bucket (new_bs, new_data, i - 1);
-                       b.fnext = (i == _get_primary_bucket_no (new_size) - 1 || i == 
_get_buckets_no(new_size) - 1) ? Bucket.null (new_bs, new_data) : Bucket (new_bs, new_data, i + 1);
-                       b.present = false;
-                       b.next_id = LINK_END;
-               }
-               int new_real_size = 0;
-               for (Bucket b = _get_first (old_bs, data, first, old_dummy_size, old_real_size); !b.is_null; 
b = _get_next (b, old_dummy_size, old_real_size)) {
-                       char *nnew_data = new_data;
-                       int nnew_dummy_size = new_size;
-                       int nnew_real_size = new_real_size;
-                       void *key = old_bs.key_offset != -1 ? b.key : null;
-                       void *value = old_bs.value_offset != -1 ? b.value : null;
-                       InsertResult ir = _insert<void *, void *> (flags, new_bs, ref nnew_data, ref 
nnew_dummy_size, ref nnew_real_size, key, value, b._hash(hash), hash, equal, false, ref first, ref last, ref 
cellar_free, ref address_free, false);
-                       assert (ir == InsertResult.INSERT);
-                       assert (new_data == nnew_data);
-                       assert (new_size == nnew_dummy_size);
-                       assert (++new_real_size == nnew_real_size);
-               }
-               GLib.Slice.free (_get_buckets_no(old_dummy_size) * old_bs.total_size, data);
-               data = new_data;
-       }
-
-       private static inline Bucket _allocate_any (BucketStructure bs, char *data, ref uint cellar_free, ref 
uint address_free) {
-               if (cellar_free != LINK_END) {
-                       Bucket bucket = Bucket (bs, data, cellar_free);
-                       cellar_free = bucket.fnext._id;
-                       Bucket next_free = Bucket (bs, data, cellar_free);
-                       if (!next_free.is_null)
-                               next_free.fprev_id = LINK_END;
-                       return bucket;
-               } else if (address_free != LINK_END) {
-                       Bucket bucket = Bucket (bs, data, address_free);
-                       address_free = bucket.fnext._id;
-                       Bucket next_free = Bucket (bs, data, address_free);
-                       if (!next_free.is_null)
-                               next_free.fprev_id = LINK_END;
-                       return bucket;
-               } else {
-                       return Bucket.null (bs, data);
+       private static inline void *_delete_iter_array<K, V> (Flags flags, ref char *data, ref int 
dummy_size, ref int real_size, ref void **iter_base, void *iter_ptr, out V value, HashDataFunc<K> hash, 
EqualDataFunc<K> equal, ref void *first, ref void *last) {
+               BucketStructure bs = BucketStructure (flags, true);
+               Bucket curr = Bucket (bs, iter_ptr);
+               K k = (owned)curr.key;
+               _delete_helper<K> ((owned)k);
+               if ((flags & Flags.MAP) != 0) {
+                       V v = (owned)curr.value;
+                       _delete_helper<V> ((owned)v);
+               }
+               void *end = (void *)((char *)data + bs.total_size * real_size);
+               void *next = (void *)((char *)iter_ptr + bs.total_size);
+               real_size--;
+               if (end == next) {
+                       return null;
+               }
+               GLib.Memory.move (iter_ptr, next, (char *)end - (char *)next);
+               return iter_ptr;
+       }
+
+       private static inline void _rehash_array<K, V> (Flags flags, ref char *data, ref int dummy_size, ref 
int real_size, int new_size, HashDataFunc hash, EqualDataFunc equal, ref void *first, ref void *last) {
+               BucketStructure bs = BucketStructure (flags, true);
+#if ASSERT
+               BucketStructure new_bs = BucketStructure (flags, false);
+               assert (bs.next_offset == -1);
+               assert (new_bs.next_offset != -1);
+#endif
+               char *old_data = data;
+               int old_dummy_size = dummy_size;
+               int old_real_size = real_size;
+               data = GLib.Slice.alloc0 (sizeof(void *) * _get_buckets_no (new_size));
+               first = null;
+               last = null;
+               dummy_size = new_size;
+               real_size = 0;
+               for (int i = 0; i < new_size; i++) {
+                       Bucket bucket = Bucket (bs, (char *)old_data + bs.total_size * i);
+#if ASSERT
+                       char *data_save = data;
+                       int real_size_save = real_size;
+                       int dummy_size_save = dummy_size;
+#endif
+                       K key = bucket.key;
+                       V? value = ((flags & Flags.MAP) != 0) ? bucket.value : null;
+                       uint khash = ((flags & Flags.CACHE_HASH) != 0 && (flags & 
Flags.CACHE_HASH_ONLY_IN_ARRAY) == 0) ? bucket.hash : hash (key);
+                       InsertResult it = _insert_linked<K, V> (flags, ref data, ref dummy_size, ref 
real_size, key, value, khash, hash, equal, false, ref first, ref last, false);
+#if ASSERT
+                       assert (it == InsertResult.INSERT);
+                       assert (data_save == data);
+                       assert (real_size_save + 1 == real_size);
+                       assert (dummy_size_save == dummy_size);
+#endif
                }
+               _cleanup_array<K, V> (flags, old_data, old_dummy_size, old_real_size, true);
        }
 
-       private static inline void _allocate (Bucket bucket, ref uint cellar_free, ref uint address_free) {
-               assert (bucket.fprev.is_null == (bucket._id == cellar_free || bucket._id == address_free));
-               if (!bucket.fnext.is_null) {
-                       bucket.fnext.fprev = bucket.fprev;
+       private static inline void _cleanup_array<K, V> (Flags flags, void *data, int dummy_size, int 
real_size, bool skip_destroy = false) {
+               BucketStructure bs = BucketStructure (flags, true);
+               if (!skip_destroy) {
+                       for (void *iter_ptr = (void *)data; iter_ptr < (void *)((char *)data + bs.total_size 
* real_size); iter_ptr = (void *)((char *)iter_ptr + bs.total_size)) {
+                               Bucket curr = Bucket (bs, iter_ptr);
+                               K k = (owned)curr.key;
+                               _delete_helper<K> ((owned)k);
+                               if ((flags & Flags.MAP) != 0) {
+                                       V v = (owned)curr.value;
+                                       _delete_helper<V> ((owned)v);
+                               }
+                       }
                }
-               if (!bucket.fprev.is_null) {
-                       bucket.fprev.fnext = bucket.fnext;
-               } else if (bucket._id == cellar_free) {
-                       cellar_free = bucket.fnext._id;
-               } else {
-                       address_free = bucket.fnext._id;
-               } 
+               GLib.Slice.free (bs.total_size * ARRAY_THRESHOLD, data);
        }
 
-       private static inline void _release (Bucket bucket, int dummy_size, ref uint cellar_free, ref uint 
address_free) {
-               assert (!bucket.present && bucket.next.is_null);
-               bucket.fprev_id = LINK_END;
-               if (bucket._id < _get_primary_bucket_no (dummy_size)) {
-                       bucket.fnext_id = address_free;
-                       address_free = bucket._id;
+       /**********************************************************************
+        * Helpers                                                            *
+        **********************************************************************/
+       private static inline void _delete_helper<G> (owned G g) {}
+
+#if DEBUG
+       internal static inline void _dump (Flags flags, char *data, int dummy_size, int real_size, void 
*first, void *last) {
+               BucketStructure bs = BucketStructure (flags, dummy_size < ARRAY_THRESHOLD);
+               stderr.printf ("#    Dumping hashtable...\n");
+               if (dummy_size >= ARRAY_THRESHOLD) {
+                       if ((flags & Flags.LINKED_HASH) != 0) {
+                               stderr.printf ("#    First element: %p\n", first);
+                               stderr.printf ("#    Last element: %p\n", last);
+                       }
+                       stderr.printf("#    
==========================================================================\n");
+                       int digits_id = (int)GLib.Math.log10(_get_buckets_no (dummy_size));
+                       for (int i = 0; i < _get_buckets_no (dummy_size); i++) {
+                               void *iter = *(void **)((char *)data + sizeof (void *) * i);
+                               stderr.printf ("#    Bucket chain %*d:\n", digits_id, i);
+                               while (iter != null) {
+                                       Bucket curr = Bucket (bs, iter);
+                                       stderr.printf ("#       Bucket %p: key = \"%s\"", iter, 
(string)curr.key);
+                                       if ((flags & Flags.MAP) != 0) {
+                                               stderr.printf(", value = \"%s\"\n", (string)curr.value);
+                                       }
+                                       if ((flags & Flags.LINKED_HASH) != 0) {
+                                               stderr.printf (", prev = %p, next = %p\n", *curr.iprev_ptr, 
*curr.inext_ptr);
+                                       }
+                                       stderr.printf ("\n");
+                                       iter = *curr.next_ptr;
+                               }
+                       }
+                       stderr.printf("#    
==========================================================================\n");
                } else {
-                       bucket.fnext_id = cellar_free;
-                       cellar_free = bucket._id;
+                       stderr.printf("#    
==========================================================================\n");
+                       int digits_id = (int)GLib.Math.log10(ARRAY_THRESHOLD);
+                       for (int i = 0; i < real_size; i++) {
+                               Bucket b = Bucket (bs, (char *)data + i * bs.total_size);
+                               stderr.printf ("#     %*d Bucket: key = \"%s\"%s\n",  digits_id, i, 
(string)b.key, (flags & Flags.MAP) != 0 ? ", value = \"%s\"".printf((string)b.value) : "");
+                       }
+                       stderr.printf("#    
==========================================================================\n");
                }
        }
+#endif
 
        private static inline uint _folded_hash (uint hash, int size) {
                return hash;
        }
 
-       private static inline int _get_primary_bucket_no (int dummy_size) {
-               return 1 << (int)GLib.Math.ceil(GLib.Math.log2((dummy_size/ALPHA)*BETA));
-       }
-
        private static inline int _get_buckets_no (int dummy_size) {
-               if (dummy_size < ARRAY_THRESHOLD) {
-                       return ARRAY_THRESHOLD;
-               }
-               return (int)GLib.Math.ceil(_get_primary_bucket_no (dummy_size)/BETA);
+               int i = (int)GLib.SpacedPrimes.closest (dummy_size);
+               return i < 11 ? 11 : i;
+               //return (int)(_get_primary_bucket_no (dummy_size)/BETA) + 1;
        }
 
        private struct BucketStructure {
-               internal inline BucketStructure (Flags flags, int size) {
+               internal inline BucketStructure (Flags flags, bool array) {
                        total_size = 0;
                        key_offset = total_size;
                        total_size += (int8)sizeof(void *);
@@ -510,32 +673,27 @@ class Gee.Hash {
                        } else {
                                value_offset = -1;
                        }
-                       if ((flags & Flags.CACHE_HASH) != 0 && ((flags & Flags.CACHE_HASH_ONLY_IN_ARRAY) == 0 
|| size < ARRAY_THRESHOLD)) {
-                               hash_offset = total_size;
-                               total_size += (int8)sizeof(int);
-                       } else {
-                               hash_offset = -1;
-                       }
-                       if ((flags & Flags.LINKED_HASH) != 0 && size >= ARRAY_THRESHOLD) {
+                       if ((flags & Flags.LINKED_HASH) != 0 && !array) {
                                iprev_offset = total_size;
-                               total_size += (int8)sizeof(int);
+                               total_size += (int8)sizeof(void *);
                                inext_offset = total_size;
-                               total_size += (int8)sizeof(int);
+                               total_size += (int8)sizeof(void *);
                        } else {
                                iprev_offset = -1;
                                inext_offset = -1;
                        }
-                       if (size >= ARRAY_THRESHOLD) {
-                               fprev_offset = 0;
-                               fnext_offset = (int8)sizeof(int);
-                               total_size = int8.max (total_size, 2*(int8)sizeof(int));
+                       if (!array) {
                                next_offset = total_size;
-                               total_size += (int8)sizeof(int);
+                               total_size += (int8)sizeof(void *);
                        } else {
-                               fprev_offset = -1;
-                               fnext_offset = -1;
                                next_offset = -1;
                        }
+                       if ((flags & Flags.CACHE_HASH) != 0 && ((flags & Flags.CACHE_HASH_ONLY_IN_ARRAY) == 0 
|| array)) {
+                               hash_offset = total_size;
+                               total_size += (int8)sizeof(int);
+                       } else {
+                               hash_offset = -1;
+                       }
                        int8 alignment = (int8)ulong.max (sizeof(int), sizeof(void *)); // FIXME: use 
configure.ac
                        total_size = ((total_size - 1)/alignment + 1)*alignment;
                }
@@ -545,44 +703,25 @@ class Gee.Hash {
                int8 hash_offset;
                int8 iprev_offset;
                int8 inext_offset;
-               int8 fprev_offset;
-               int8 fnext_offset;
                int8 next_offset;
                int8 total_size;
        }
 
        private struct Bucket {
-               internal inline Bucket (BucketStructure bs, char *data, uint i) {
-                       _bs = bs;
-                       _data = data;
-                       _id = i;
-               }
-
-               internal inline Bucket.null (BucketStructure bs, char *data) {
+               internal inline Bucket (BucketStructure bs, void *data) {
                        _bs = bs;
                        _data = data;
-                       _id = LINK_END;
                }
 
-               internal void *key {
+               internal inline void *key {
                        get {
-#if ASSERT
-                               assert (_data != null);
-                               assert (_id != LINK_END);
-                               assert (_bs.key_offset != -1);
-#endif
-                               void *value = null;
-                               GLib.Memory.copy (&value, _data + _bs.total_size * _id + _bs.key_offset, 
sizeof (void *));
-                               return value;
+                               return *(void **)((char *)_data + _bs.key_offset);
                        }
                        set {
 #if ASSERT
                                assert (_data != null);
-                               assert (_id != LINK_END);
 #endif
-                               if (_bs.key_offset != -1) {
-                                       GLib.Memory.copy (_data + _bs.total_size * _id + _bs.key_offset, 
&value, sizeof (void *));
-                               }
+                               *(void **)((char *)_data + _bs.key_offset) = value;
                        }
                }
 
@@ -590,20 +729,16 @@ class Gee.Hash {
                        get {
 #if ASSERT
                                assert (_data != null);
-                               assert (_id != LINK_END);
                                assert (_bs.value_offset != -1);
 #endif
-                               void *value = null;
-                               GLib.Memory.copy (&value, _data + _bs.total_size * _id + _bs.value_offset, 
sizeof (void *));
-                               return value;
+                               return *(void **)((char *)_data + _bs.value_offset);
                        }
                        set {
 #if ASSERT
                                assert (_data != null);
                                assert (_id != LINK_END);
 #endif
-                               if (_bs.value_offset != -1)
-                                       GLib.Memory.copy (_data + _bs.total_size * _id + _bs.value_offset, 
&value, sizeof (void *));
+                               *(void **)((char *)_data + _bs.value_offset) = value;
                        }
                }
 
@@ -611,207 +746,92 @@ class Gee.Hash {
                        get {
 #if ASSERT
                                assert (_data != null);
-                               assert (_id != LINK_END);
                                assert (_bs.hash_offset != -1);
 #endif
-                               uint value = 0;
-                               GLib.Memory.copy (&value, _data + _bs.total_size * _id + _bs.hash_offset, 
sizeof (uint));
-                               return value;
+                               return *(uint *)((char *)_data + _bs.hash_offset);
                        }
                        set {
+#if ASSERT
                                assert (_data != null);
-                               assert (_id != LINK_END);
-                               if (_bs.hash_offset != -1)
-                                       GLib.Memory.copy (_data + _bs.total_size * _id + _bs.hash_offset, 
&value, sizeof (uint));
+#endif
+                               *(uint *)((char *)_data + _bs.hash_offset) = value;
                        }
                }
 
                internal Bucket iprev {
                        get {
-                               return Bucket (_bs, _data, iprev_id);
+                               return Bucket (_bs, *iprev_ptr);
                        }
                        set {
-                               assert (value._data == _data);
-                               iprev_id = value._id;
+#if ASSERT
+                               assert (_data != null || _data == value._data);
+#endif
+                               *iprev_ptr = value._data;
                        }
                }
 
-               internal uint iprev_id {
+               internal void **iprev_ptr {
                        get {
 #if ASSERT
                                assert (_data != null);
-                               assert (_id != LINK_END);
                                assert (_bs.iprev_offset != -1);
 #endif
-                               uint value = 0;
-                               GLib.Memory.copy (&value, _data + _bs.total_size * _id + _bs.iprev_offset, 
sizeof (uint));
-                               return value;
-                       }
-                       set {
-                               assert (_data != null);
-                               assert (_id != LINK_END);
-                               if (_bs.iprev_offset != -1)
-                                       GLib.Memory.copy (_data + _bs.total_size * _id + _bs.iprev_offset, 
&value, sizeof (uint));
+                               return (void **)((char *)_data + _bs.iprev_offset);
                        }
                }
 
                internal Bucket inext {
                        get {
-                               return Bucket (_bs, _data, inext_id);
+                               return Bucket (_bs, *inext_ptr);
                        }
                        set {
-                               assert (value._data == _data);
-                               inext_id = value._id;
-                       }
-               }
-
-               internal uint inext_id {
-                       get {
 #if ASSERT
-                               assert (_data != null);
-                               assert (_id != LINK_END);
-                               assert (_bs.inext_offset != -1);
+                               assert (_data != null || _data == value._data);
 #endif
-                               uint value = 0;
-                               GLib.Memory.copy (&value, _data + _bs.total_size * _id + _bs.inext_offset, 
sizeof (uint));
-                               return value;
-                       }
-                       set {
-                               if (_bs.inext_offset != -1)
-                                       GLib.Memory.copy (_data + _bs.total_size * _id + _bs.inext_offset, 
&value, sizeof (uint));
-                       }
-               }
-
-               internal Bucket fprev {
-                       get {
-                               return Bucket (_bs, _data, fprev_id);
-                       }
-                       set {
-                               assert (value._data == _data);
-                               fprev_id = value._id;
+                               *inext_ptr = value._data;
                        }
                }
 
-               internal uint fprev_id {
+               internal void **inext_ptr {
                        get {
 #if ASSERT
                                assert (_data != null);
-                               assert (_id != LINK_END);
-                               assert (_bs.fprev_offset != -1);
+                               assert (_bs.inext_offset != -1);
 #endif
-                               uint value = 0;
-                               GLib.Memory.copy (&value, _data + _bs.total_size * _id + _bs.fprev_offset, 
sizeof (uint));
-                               return value;
-                       }
-                       set {
-                               if (_bs.fprev_offset != -1)
-                                       GLib.Memory.copy (_data + _bs.total_size * _id + _bs.fprev_offset, 
&value, sizeof (uint));
+                               return (void **)((char *)_data + _bs.inext_offset);
                        }
                }
 
-               internal Bucket fnext {
+               internal Bucket next {
                        get {
-                               return Bucket (_bs, _data, fnext_id);
+                               return Bucket (_bs, *next_ptr);
                        }
                        set {
-                               assert (value._data == _data);
-                               fnext_id = value._id;
-                       }
-               }
-
-               internal uint fnext_id {
-                       get {
 #if ASSERT
-                               assert (_data != null);
-                               assert (_id != LINK_END);
-                               assert (_bs.fnext_offset != -1);
+                               assert (_data != null || _data == value._data);
 #endif
-                               uint value = 0;
-                               GLib.Memory.copy (&value, _data + _bs.total_size * _id + _bs.fnext_offset, 
sizeof (uint));
-                               return value;
-                       }
-                       set {
-                               if (_bs.fnext_offset != -1)
-                                       GLib.Memory.copy (_data + _bs.total_size * _id + _bs.fnext_offset, 
&value, sizeof (uint));
-                       }
-               }
-
-               internal Bucket next {
-                       get {
-                               return Bucket (_bs, _data, next_id);
-                       }
-                       set {
-                               assert (value._data == _data);
-                               next_id = value._id;
-                       }
-               }
-
-               internal uint next_id {
-                       get {
-                               assert (_data != null);
-                               assert (_id != LINK_END);
-                               assert (_bs.next_offset != -1);
-                               uint value = 0;
-                               GLib.Memory.copy (&value, _data + _bs.total_size * _id + _bs.next_offset, 
sizeof (uint));
-                               return value >> 1;
-                       }
-                       set {
-                               if (_bs.next_offset != -1) {
-                                       value = (value << 1) | present;
-                                       GLib.Memory.copy (_data + _bs.total_size * _id + _bs.next_offset, 
&value, sizeof (uint));
-                               }
+                               *next_ptr = value._data;
                        }
                }
 
-               internal bool present {
+               internal void **next_ptr {
                        get {
 #if ASSERT
                                assert (_data != null);
-                               assert (_id != LINK_END);
                                assert (_bs.next_offset != -1);
 #endif
-                               uint value = 0;
-                               GLib.Memory.copy (&value, _data + _bs.total_size * _id + _bs.next_offset, 
sizeof (uint));
-                               return 0 != (value & 1);
-                       }
-                       set {
-#if ASSERT
-                               assert (_data != null);
-                               assert (_id != LINK_END);
-#endif
-                               if (_bs.next_offset != -1) {
-                                       uint next = (next_id << 1) | value;
-                                       GLib.Memory.copy (_data + _bs.total_size * _id + _bs.next_offset, 
&next, sizeof (uint));
-                               }
+                               return (void **)((char *)_data + _bs.next_offset);
                        }
                }
 
                internal bool is_null {
                        get {
-#if ASSERT
-                               assert (_data != null);
-#endif
-                               return _id == LINK_END;
-                       }
-               }
-
-               internal uint _hash (HashDataFunc func) {
-                       if (_bs.hash_offset == -1) {
-                               return hash;
-                       } else {
-                               return func (key);
-                       }
-               }
-
-               internal uint id {
-                       get {
-                               return _id;
+                               return _data != null;
                        }
                }
 
-               internal char *_data;
+               internal void *_data;
                internal BucketStructure _bs;
-               internal uint _id;
        }
 
        [Flags]
@@ -819,8 +839,7 @@ class Gee.Hash {
                MAP,
                CACHE_HASH,
                CACHE_HASH_ONLY_IN_ARRAY,
-               LINKED_HASH,
-               FOLD_HASHES
+               LINKED_HASH
        }
 
        public enum InsertResult {
@@ -829,9 +848,7 @@ class Gee.Hash {
                REPLACE
        }
 
-       internal static const int ARRAY_THRESHOLD = 9;
-       private static const double ALPHA = 0.7;
-       private static const double BETA = 0.86;
-       private static const uint LINK_END = 0x7fffffff; //uint.MAX >> 1;
+       internal static const int ARRAY_THRESHOLD = (int)0x80000000; //int.MIN;
+       private static const double ALPHA = 0.9;
 }
 
diff --git a/gee/hashset.vala b/gee/hashset.vala
index 1498823..9f24023 100644
--- a/gee/hashset.vala
+++ b/gee/hashset.vala
@@ -68,8 +68,6 @@ public class Gee.HashSet<G> : AbstractSet<G> {
        private int _dummy_size;
        private int _real_size;
        private char *_data;
-       private uint _cellar_free;
-       private uint _address_free;
 
        // concurrent modification protection
        private int _stamp = 0;
@@ -107,7 +105,7 @@ public class Gee.HashSet<G> : AbstractSet<G> {
         * { inheritDoc}
         */
        public override bool contains (G key) {
-               return Hash.lookup (Hash.Flags.CACHE_HASH, _data, _dummy_size, _real_size, key, hash_func, 
equal_func);
+               return Hash.lookup (Hash.Flags.CACHE_HASH, _data, _dummy_size, _real_size, key, hash_func, 
equal_func, null);
        }
 
        /**
@@ -121,11 +119,8 @@ public class Gee.HashSet<G> : AbstractSet<G> {
         * { inheritDoc}
         */
        public override bool add (G key) {
-               uint first = 0, last = 0;
-               if (_dummy_size != _real_size) {
-                       Hash.rehash (Hash.Flags.CACHE_HASH, ref _data, ref _dummy_size, ref _real_size, 
_real_size, hash_func, equal_func, ref first, ref last, ref _cellar_free, ref _address_free);
-               }
-               Hash.InsertResult ir = Hash.insert<G, void *> (Hash.Flags.CACHE_HASH, ref _data, ref 
_dummy_size, ref _real_size, key, null, hash_func, equal_func, false, ref first, ref last, ref _cellar_free, 
ref _address_free);
+               void *first = null, last = null;
+               Hash.InsertResult ir = Hash.insert<G, void *> (Hash.Flags.CACHE_HASH, ref _data, ref 
_dummy_size, ref _real_size, key, null, hash_func, equal_func, false, ref first, ref last);
                _stamp++;
                switch (ir) {
                case Hash.InsertResult.FAIL:
@@ -141,11 +136,8 @@ public class Gee.HashSet<G> : AbstractSet<G> {
         * { inheritDoc}
         */
        public override bool remove (G key) {
-               uint first = 0, last = 0;
-               if (_dummy_size != _real_size) {
-                       Hash.rehash (Hash.Flags.CACHE_HASH, ref _data, ref _dummy_size, ref _real_size, 
_real_size, hash_func, equal_func, ref first, ref last, ref _cellar_free, ref _address_free);
-               }
-               bool result = Hash.delete<G, void *> (Hash.Flags.CACHE_HASH, ref _data, ref _dummy_size, ref 
_real_size, key, null, hash_func, equal_func, ref first, ref last, ref _cellar_free, ref _address_free);
+               void *first = null, last = null;
+               bool result = Hash.delete<G, void *> (Hash.Flags.CACHE_HASH, ref _data, ref _dummy_size, ref 
_real_size, key, null, hash_func, equal_func, ref first, ref last);
                _stamp++;
                return result;
        }
@@ -167,7 +159,8 @@ public class Gee.HashSet<G> : AbstractSet<G> {
 
        private class Iterator<G> : Object, Traversable<G>, Gee.Iterator<G> {
                private HashSet<G> _set;
-               private int _index = -1;
+               private void *_iter_base = null;
+               private void *_iter_ptr = null;
                private bool _removed = false;
                private int _stamp;
 
@@ -179,49 +172,49 @@ public class Gee.HashSet<G> : AbstractSet<G> {
                public bool next () {
                        assert (_set._stamp == _stamp);
                        if (_removed) {
-                               if (_index != -1)
+                               if (_iter_ptr != null)
                                        _removed = false;
-                               return _index != -1;
-                       } else if (_index == -1) {
-                               _index = Hash.get_first (Hash.Flags.CACHE_HASH, _set._data, _set._dummy_size, 
_set._real_size, 0);
-                               return _index != -1;
+                               return _iter_ptr != null;
+                       } else if (_iter_ptr == null) {
+                               _iter_ptr = Hash.get_first (Hash.Flags.CACHE_HASH, _set._data, 
_set._dummy_size, _set._real_size, null, out _iter_base);
+                               return _iter_ptr != null;
                        } else {
-                               int new_index = Hash.get_next (Hash.Flags.CACHE_HASH, _set._data, 
_set._dummy_size, _set._real_size, _index);
-                               if (new_index != -1) {
-                                       _index = new_index;
+                               void *iter_base = _iter_base;
+                               void *iter_ptr = _iter_ptr;
+                               Hash.get_next (Hash.Flags.CACHE_HASH, _set._data, _set._dummy_size, 
_set._real_size, ref iter_base, ref iter_ptr);
+                               if (iter_ptr != null) {
+                                       _iter_base = iter_base;
+                                       _iter_ptr = iter_ptr;
+                                       return true;
+                               } else {
+                                       return false;
                                }
-                               return new_index != -1;
                        }
                }
 
                public bool has_next () {
                        assert (_set._stamp == _stamp);
-                       int new_index;
-                       if (_removed) {
-                               new_index = _index;
-                       } else if (_index == -1) {
-                               new_index = Hash.get_first (Hash.Flags.CACHE_HASH, _set._data, 
_set._dummy_size, _set._real_size, 0);
-                       } else {
-                               new_index = Hash.get_next (Hash.Flags.CACHE_HASH, _set._data, 
_set._dummy_size, _set._real_size, _index);
+                       void *iter_ptr = _iter_ptr;
+                       if (!_removed) {
+                               if (_iter_ptr == null) {
+                                       iter_ptr = Hash.get_first (Hash.Flags.CACHE_HASH, _set._data, 
_set._dummy_size, _set._real_size, null, null);
+                               } else {
+                                       void *iter_base = _iter_base;
+                                       Hash.get_next (Hash.Flags.CACHE_HASH, _set._data, _set._dummy_size, 
_set._real_size, ref iter_base, ref iter_ptr);
+                               }
                        }
-                       return new_index != -1;
+                       return iter_ptr != null;
                }
 
                public new G get () {
                        assert (valid);
-                       return Hash.get_key<G> (Hash.Flags.CACHE_HASH, _set._data, _set._dummy_size, _index);
+                       return Hash.get_key<G> (Hash.Flags.CACHE_HASH, _set._data, _set._dummy_size, 
_iter_ptr);
                }
 
                public void remove () {
                        assert (valid);
-                       uint first = 0, last = 0;
-                       unowned G element = Hash.get_key<G> (Hash.Flags.CACHE_HASH, _set._data, 
_set._dummy_size, _index);
-                       if (_set._dummy_size >= Hash.ARRAY_THRESHOLD)
-                               _index = Hash.get_next (Hash.Flags.CACHE_HASH, _set._data, _set._dummy_size, 
_set._real_size, _index);
-                       else if (_index == _set._real_size - 1)
-                               _index = -1;
-                       bool res = Hash.delete<G, void *> (Hash.Flags.CACHE_HASH, ref _set._data, ref 
_set._dummy_size, ref _set._real_size, element, null, _set.hash_func, _set.equal_func, ref first, ref last, 
ref _set._cellar_free, ref _set._address_free, false);
-                       assert (res);
+                       void *first = null, last = null;
+                       _iter_ptr = Hash.delete_iter<G, void *> (Hash.Flags.CACHE_HASH, ref _set._data, ref 
_set._dummy_size, ref _set._real_size, ref _iter_base, _iter_ptr, null, _set._hash_func, _set._equal_func, 
ref first, ref last);
                        _set._stamp = ++_stamp;
                        _removed = true;
                }
@@ -235,35 +228,37 @@ public class Gee.HashSet<G> : AbstractSet<G> {
                public bool valid {
                        get {
                                assert (_set._stamp == _stamp);
-                               return _index != -1 && !_removed;
+                               return _iter_ptr != null && !_removed;
                        }
                }
 
                public bool foreach (ForallFunc<G> f) {
                        assert (_set._stamp == _stamp);
-                       if (!_removed && _index != -1) {
-                               if (!f (Hash.get_key<G> (Hash.Flags.CACHE_HASH, _set._data, _set._dummy_size, 
_index))) {
+                       if (!_removed && _iter_ptr != null) {
+                               if (!f (Hash.get_key<G> (Hash.Flags.CACHE_HASH, _set._data, _set._dummy_size, 
_iter_ptr))) {
                                        return false;
                                }
                        } 
-                       if (_removed && _index == -1) {
+                       if (_removed && _iter_ptr == null) {
                                return true;
                        }
                        if (_removed) {
                                _removed = false;
                        }
-                       int new_index;
-                       if (_index == -1) {
-                               new_index = Hash.get_first (Hash.Flags.CACHE_HASH, _set._data, 
_set._dummy_size, _set._real_size, 0);
+                       void *iter_ptr = _iter_ptr;
+                       void *iter_base = _iter_base;
+                       if (_iter_ptr == null) {
+                               iter_ptr = Hash.get_first (Hash.Flags.CACHE_HASH, _set._data, 
_set._dummy_size, _set._real_size, null, out iter_base);
                        } else {
-                               new_index = Hash.get_next (Hash.Flags.CACHE_HASH, _set._data, 
_set._dummy_size, _set._dummy_size, _index);
+                               Hash.get_next (Hash.Flags.CACHE_HASH, _set._data, _set._dummy_size, 
_set._real_size, ref iter_base, ref iter_ptr);
                        }
-                       while (new_index != -1) {
-                               _index = new_index;
-                               if (!f (Hash.get_key<G> (Hash.Flags.CACHE_HASH, _set._data, _set._dummy_size, 
_index))) {
+                       while (iter_ptr != null) {
+                               _iter_ptr = iter_ptr;
+                               _iter_base = iter_base;
+                               if (!f (Hash.get_key<G> (Hash.Flags.CACHE_HASH, _set._data, _set._dummy_size, 
_iter_ptr))) {
                                        return false;
                                }
-                               new_index = Hash.get_next (Hash.Flags.CACHE_HASH, _set._data, 
_set._dummy_size, _set._dummy_size, _index);
+                               Hash.get_next (Hash.Flags.CACHE_HASH, _set._data, _set._dummy_size, 
_set._real_size, ref iter_base, ref iter_ptr);
                        }
                        return true;
                }
diff --git a/tests/testdata.vala b/tests/testdata.vala
index 5f00c97..ee93afe 100644
--- a/tests/testdata.vala
+++ b/tests/testdata.vala
@@ -26,7 +26,7 @@ public class TestData {
        private static string?[] thousands = {null, "thousand", "million", "billion", "trillion"};
 
        private static uint data_size () {
-               return Test.quick() ? 128 : 1024;
+               return 1024; //Test.quick() ? 128 : 1024;
        }
 
        private static uint DATA_SIZE = data_size ();


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]