[svn:parrot] r47870 - in branches/hash_allocator: include/parrot src

whiteknight at svn.parrot.org whiteknight at svn.parrot.org
Sat Jun 26 15:20:50 UTC 2010


Author: whiteknight
Date: Sat Jun 26 15:20:49 2010
New Revision: 47870
URL: https://trac.parrot.org/parrot/changeset/47870

Log:
[hash] second pass. Things still probably don't work

Modified:
   branches/hash_allocator/include/parrot/hash.h
   branches/hash_allocator/src/hash.c

Modified: branches/hash_allocator/include/parrot/hash.h
==============================================================================
--- branches/hash_allocator/include/parrot/hash.h	Sat Jun 26 14:51:46 2010	(r47869)
+++ branches/hash_allocator/include/parrot/hash.h	Sat Jun 26 15:20:49 2010	(r47870)
@@ -47,7 +47,7 @@
 
 typedef struct _hashiteratorstate {
     INTVAL idx;
-    HashBucket curr;
+    HashBucket current;
 } HashIteratorState;
 
 struct _hash {

Modified: branches/hash_allocator/src/hash.c
==============================================================================
--- branches/hash_allocator/src/hash.c	Sat Jun 26 14:51:46 2010	(r47869)
+++ branches/hash_allocator/src/hash.c	Sat Jun 26 15:20:49 2010	(r47870)
@@ -678,42 +678,61 @@
     size_t           i;
 
     for (i = 0; i < hash->entries; ++i) {
-        HashBucket * const b = hash->buckets + i;
-
-        switch (hash->key_type) {
-          case Hash_key_type_int:
-            VTABLE_push_integer(interp, info, (INTVAL)b->key);
-            break;
-          case Hash_key_type_STRING:
-            VTABLE_push_string(interp, info, (STRING *)b->key);
-            break;
-          case Hash_key_type_PMC:
-            VTABLE_push_pmc(interp, info, (PMC *)b->key);
-            break;
-          default:
-            Parrot_ex_throw_from_c_args(interp, NULL, 1,
-                    "unimplemented key type");
-            break;
-        }
-
-        switch (hash->entry_type) {
-          case enum_hash_int:
-            VTABLE_push_integer(interp, info, (INTVAL)b->value);
-            break;
-          case enum_hash_string:
-            VTABLE_push_string(interp, info, (STRING *)b->value);
-            break;
-          case enum_hash_pmc:
-            VTABLE_push_pmc(interp, info, (PMC *)b->value);
-            break;
-          default:
-            Parrot_ex_throw_from_c_args(interp, NULL, 1,
-                    "unimplemented value type");
-            break;
+        HashBucket * b = hash->entries[i];
+        while (b) {
+            hash_freeze_bucket(interp, hash, info, b);
+            b = b->next;
         }
     }
 }
 
+/*
+
+=item C<static void hash_freeze_bucket(PARROT_INTERP, ARGIN(const Hash *hash),
+ARGMOD(PMC *info), ARGIN(HashBucket * b))>
+
+Freeze the contents of one bucket.
+
+=cut
+
+*/
+
+static void
+hash_freeze_bucket(PARROT_INTERP, ARGIN(const Hash *hash),
+    ARGMOD(PMC *info), ARGIN(HashBucket * b))
+{
+    switch (hash->key_type) {
+      case Hash_key_type_int:
+        VTABLE_push_integer(interp, info, (INTVAL)b->key);
+        break;
+      case Hash_key_type_STRING:
+        VTABLE_push_string(interp, info, (STRING *)b->key);
+        break;
+      case Hash_key_type_PMC:
+        VTABLE_push_pmc(interp, info, (PMC *)b->key);
+        break;
+      default:
+        Parrot_ex_throw_from_c_args(interp, NULL, 1,
+                "unimplemented key type");
+        break;
+    }
+
+    switch (hash->entry_type) {
+      case enum_hash_int:
+        VTABLE_push_integer(interp, info, (INTVAL)b->value);
+        break;
+      case enum_hash_string:
+        VTABLE_push_string(interp, info, (STRING *)b->value);
+        break;
+      case enum_hash_pmc:
+        VTABLE_push_pmc(interp, info, (PMC *)b->value);
+        break;
+      default:
+        Parrot_ex_throw_from_c_args(interp, NULL, 1,
+                "unimplemented value type");
+        break;
+    }
+}
 
 /*
 
@@ -783,99 +802,36 @@
 expand_hash(PARROT_INTERP, ARGMOD(Hash *hash))
 {
     ASSERT_ARGS(expand_hash)
-    HashBucket  **old_bi, **new_bi;
-    HashBucket   *bs, *b, *new_mem;
-    HashBucket * const old_offset = (HashBucket *)((char *)hash + sizeof (Hash));
-
-    void * const  old_mem    = hash->buckets;
-    const UINTVAL old_size   = hash->mask + 1;
-    const UINTVAL new_size   = old_size << 1; /* Double. Left-shift is 2x */
-    const UINTVAL old_nb     = N_BUCKETS(old_size);
-    size_t        offset, i;
-
-    /* resize mem */
-    if (old_offset != old_mem) {
-        /* This buffer has been reallocated at least once before. */
-        new_mem = (HashBucket *)Parrot_gc_reallocate_memory_chunk_with_interior_pointers(
-                interp, old_mem, HASH_ALLOC_SIZE(new_size), HASH_ALLOC_SIZE(old_size));
-    }
-    else {
-        /* Allocate a new buffer. */
-        new_mem = (HashBucket *)Parrot_gc_allocate_memory_chunk_with_interior_pointers(
-                interp, HASH_ALLOC_SIZE(new_size));
-        memcpy(new_mem, old_mem, HASH_ALLOC_SIZE(old_size));
-    }
-
-    /*
-         +---+---+---+---+---+---+-+-+-+-+-+-+-+-+
-         |  buckets  | old_bi    |  new_bi       |
-         +---+---+---+---+---+---+-+-+-+-+-+-+-+-+
-         ^                       ^
-         | new_mem               | hash->bucket_indices
-    */
-
-    bs     = new_mem;
-    old_bi = (HashBucket **)(bs + old_nb);
-    new_bi = (HashBucket **)(bs + N_BUCKETS(new_size));
-
-    /* things can have moved by this offset */
-    offset = (char *)new_mem - (char *)old_mem;
+    const UINTVAL old_size = hash->mask + 1;
+    const UINTVAL new_size = old_size << 1; /* Double. Left-shift is 2x */
+    const UINTVAL new_mask = new_size - 1;
+    HashBucket ** const old_bi = hash->bucket_indices;
+    HashBucket ** const new_bi = Parrot_gc_reallocate_fixed_size_storage(interp,
+        new_size * sizeof (HashBucket *));
 
-    /* relocate the bucket index */
-    mem_sys_memmove(new_bi, old_bi, old_size * sizeof (HashBucket *));
+    /* clear freshly allocated bucket index */
+    memset(new_bi + old_size, 0, sizeof (HashBucket *) * old_size);
 
     /* update hash data */
     hash->bucket_indices = new_bi;
-    hash->buckets        = bs;
     hash->mask = new_size - 1;
 
-    /* clear freshly allocated bucket index */
-    memset(new_bi + old_size, 0, sizeof (HashBucket *) * old_size);
-
-    /*
-     * reloc pointers - this part would be also needed, if we
-     * allocate hash memory from GC movable memory, and then
-     * also the free_list needs updating (this is empty now,
-     * as expand_hash is only called for that case).
-     */
-    if (offset) {
-        size_t j;
-        for (j = 0; j < old_size; ++j) {
-            HashBucket **next_p = new_bi + j;
-            while (*next_p) {
-                *next_p = (HashBucket *)((char *)*next_p + offset);
-                b       = *next_p;
-                next_p  = &b->next;
-            }
-        }
-    }
-
-    /* recalc bucket index */
+    /* Recalculate the index for each bucket. Some will stay where they are,
+       some will move to a new index. */
     for (i = 0; i < old_size; ++i) {
-        HashBucket **next_p = new_bi + i;
+        HashBucket * b = hash->bucket_indices[i];
 
-        while ((b = *next_p) != NULL) {
-            /* rehash the bucket */
+        while (b) {
             const size_t new_loc =
-                (hash->hash_val)(interp, b->key, hash->seed) & (new_size - 1);
-
+                (hash->hash_val)(interp, b->key, hash->seed) & (new_mask);
+            HashBucket * const next_b = b->next;
             if (i != new_loc) {
-                *next_p         = b->next;
                 b->next         = new_bi[new_loc];
                 new_bi[new_loc] = b;
             }
-            else
-                next_p = &b->next;
+            b = next_b;
         }
     }
-
-    /* add new buckets to free_list in reverse order
-     * lowest bucket is top on free list and will be used first */
-    for (i = 0, b = (HashBucket *)new_bi - 1; i < old_nb; ++i, --b) {
-        b->next         = hash->free_list;
-        b->key          = b->value         = NULL;
-        hash->free_list = b;
-    }
 }
 
 
@@ -1373,10 +1329,12 @@
         bucket = (HashBucket *)Parrot_gc_allocate_fixed_size_storage(interp,
             sizeof(HashBucket));
 
-        /* TODO: Expand the hash if we need to */
-
         /* Add the value to the new bucket, increasing the count of elements */
         ++hash->entries;
+
+        if ((double)(hash->entries / (hash->mash + 1)) > HASH_INDICES)
+            expand_hash(interp, hash);
+
         bucket->key   = key;
         bucket->value = value;
         bucket->next = hash->bucket_indices[hashval & hash->mask];
@@ -2127,19 +2085,6 @@
 
 F<docs/pdds/pdd08_keys.pod>.
 
-=head1 TODO
-
-Future optimizations:
-
-=over 4
-
-=item * Stop reallocating the bucket pool, and instead add chunks on.
-(Saves pointer fixups and copying during C<realloc>.)
-
-=item * Hash contraction (don't if it's worth it)
-
-=back
-
 =cut
 
 */


More information about the parrot-commits mailing list