[svn:parrot] r47868 - in branches/hash_allocator: include/parrot src src/call
whiteknight at svn.parrot.org
whiteknight at svn.parrot.org
Sat Jun 26 14:46:13 UTC 2010
Author: whiteknight
Date: Sat Jun 26 14:46:12 2010
New Revision: 47868
URL: https://trac.parrot.org/parrot/changeset/47868
Log:
[hash] First pass at converting hash to use the fixed-size allocator. Things are indoubtably broken
Modified:
branches/hash_allocator/include/parrot/hash.h
branches/hash_allocator/src/call/args.c
branches/hash_allocator/src/hash.c
Modified: branches/hash_allocator/include/parrot/hash.h
==============================================================================
--- branches/hash_allocator/include/parrot/hash.h Sat Jun 26 13:31:35 2010 (r47867)
+++ branches/hash_allocator/include/parrot/hash.h Sat Jun 26 14:46:12 2010 (r47868)
@@ -23,9 +23,8 @@
typedef UINTVAL BucketIndex;
#define INITBucketIndex ((BucketIndex)-2)
-#define N_BUCKETS(n) ((n) - (n)/4)
-#define HASH_ALLOC_SIZE(n) (N_BUCKETS(n) * sizeof (HashBucket) + \
- (n) * sizeof (HashBucket *))
+#define N_BUCKETS(n) ((n) - (n)/4))
+#define HASH_ALLOC_SIZE(n) ((n) * sizeof (HashBucket *))
typedef int (*hash_comp_fn)(PARROT_INTERP, ARGIN(const void *), ARGIN(const void *));
typedef size_t (*hash_hash_key_fn)(PARROT_INTERP, ARGIN(const void *), size_t seed);
@@ -46,16 +45,15 @@
void *value;
} HashBucket;
-struct _hash {
- /* Large slab store of buckets */
- HashBucket *buckets;
+typedef struct _hashiteratorstate {
+ INTVAL idx;
+ HashBucket curr;
+} HashIteratorState;
+struct _hash {
/* List of Bucket pointers */
HashBucket **bucket_indices;
- /* Store for empty buckets */
- HashBucket *free_list;
-
/* Number of values stored in hashtable */
UINTVAL entries;
Modified: branches/hash_allocator/src/call/args.c
==============================================================================
--- branches/hash_allocator/src/call/args.c Sat Jun 26 13:31:35 2010 (r47867)
+++ branches/hash_allocator/src/call/args.c Sat Jun 26 14:46:12 2010 (r47868)
@@ -490,15 +490,16 @@
else if (VTABLE_does(interp, aggregate, CONST_STRING(interp, "hash"))) {
const INTVAL elements = VTABLE_elements(interp, aggregate);
INTVAL index;
- PMC * const key = Parrot_pmc_new(interp, enum_class_Key);
- VTABLE_set_integer_native(interp, key, 0);
- SETATTR_Key_next_key(interp, key, (PMC *)INITBucketIndex);
+ Hash * const hash = (Hash *)VTABLE_get_pointer(interp, aggregate);
+ HashIteratorState state;
+ state.idx = INITBucketIndex;
+ state.current = NULL;
/* Low-level hash iteration. */
for (index = 0; index < elements; ++index) {
if (!PMC_IS_NULL(key)) {
- STRING * const name = (STRING *)parrot_hash_get_idx(interp,
- (Hash *)VTABLE_get_pointer(interp, aggregate), key);
+ STRING * const name = (STRING *)Parrot_hash_get_next_key(interp,
+ hash, &state);
PARROT_ASSERT(name);
VTABLE_set_pmc_keyed_str(interp, call_object, name,
VTABLE_get_pmc_keyed_str(interp, aggregate, name));
Modified: branches/hash_allocator/src/hash.c
==============================================================================
--- branches/hash_allocator/src/hash.c Sat Jun 26 13:31:35 2010 (r47867)
+++ branches/hash_allocator/src/hash.c Sat Jun 26 14:46:12 2010 (r47868)
@@ -28,10 +28,14 @@
#include "pmc/pmc_key.h"
/* the number of entries above which it's faster to hash the hashval instead of
- * looping over the used HashBuckets directly */
+ looping over the used HashBuckets directly */
#define SMALL_HASH_SIZE 4
#define INITIAL_BUCKETS 4
+/* The ratio of buckets to indices in the hash before we decide to realloc the
+ indices array */
+#define HASH_INDICES_RATIO 2.0
+
/* HEADERIZER HFILE: include/parrot/hash.h */
/* HEADERIZER BEGIN: static */
@@ -785,21 +789,10 @@
void * const old_mem = hash->buckets;
const UINTVAL old_size = hash->mask + 1;
- const UINTVAL new_size = old_size << 1; /* Double. Right-shift is 2x */
+ const UINTVAL new_size = old_size << 1; /* Double. Left-shift is 2x */
const UINTVAL old_nb = N_BUCKETS(old_size);
size_t offset, i;
- /*
- allocate some less buckets
- e.g. 3 buckets, 4 pointers:
-
- +---+---+---+-+-+-+-+
- | --> buckets | |
- +---+---+---+-+-+-+-+
- ^ ^
- | old_mem | hash->bucket_indices
- */
-
/* resize mem */
if (old_offset != old_mem) {
/* This buffer has been reallocated at least once before. */
@@ -1007,11 +1000,9 @@
NOTNULL(hash_comp_fn compare), NOTNULL(hash_hash_key_fn keyhash))
{
ASSERT_ARGS(parrot_create_hash)
- HashBucket *bp;
- void *alloc = Parrot_gc_allocate_memory_chunk_with_interior_pointers(
- interp, sizeof (Hash) + HASH_ALLOC_SIZE(INITIAL_BUCKETS));
- Hash * const hash = (Hash*)alloc;
- size_t i;
+ const INTVAL numbuckets = N_BUCKETS(INITIAL_BUCKETS);
+ Hash * const hash = (Hash*)Parrot_gc_allocate_fixed_size_storage(interp, sizeof (Hash));
+ HashBucket ** const bp = Parrot_gc_allocate_memory_chunk(interp, HASH_ALLOC_SIZE(INITIAL_BUCKETS));
PARROT_ASSERT(INITIAL_BUCKETS % 4 == 0);
@@ -1023,22 +1014,7 @@
hash->mask = INITIAL_BUCKETS - 1;
hash->entries = 0;
hash->container = PMCNULL;
-
- bp = (HashBucket *)((char *)alloc + sizeof (Hash));
- hash->free_list = NULL;
-
- /* fill free_list from hi addresses so that we can use
- * buckets[i] directly in an OrderedHash, *if* nothing
- * was deleted */
-
- hash->buckets = bp;
- bp += N_BUCKETS(INITIAL_BUCKETS);
- hash->bucket_indices = (HashBucket **)bp;
-
- for (i = 0, --bp; i < N_BUCKETS(INITIAL_BUCKETS); ++i, --bp) {
- bp->next = hash->free_list;
- hash->free_list = bp;
- }
+ hash->bucket_indices = bp;
return hash;
}
@@ -1061,10 +1037,8 @@
parrot_hash_destroy(PARROT_INTERP, ARGFREE_NOTNULL(Hash *hash))
{
ASSERT_ARGS(parrot_hash_destroy)
- HashBucket * const bp = (HashBucket*)((char*)hash + sizeof (Hash));
- if (bp != hash->buckets)
- mem_gc_free(interp, hash->buckets);
- mem_gc_free(interp, hash);
+ Parrot_gc_free_memory_chunk(interp, hash->bucket_indices);
+ Parrot_gc_free_fixed_size_storage(interp, hash);
}
@@ -1153,13 +1127,54 @@
return hash->entries;
}
+/*
+
+=item C<void * Parrot_hash_get_next_key(PARROT_INTERP, ARGIN(const Hash * hash),
+ ARGMOD(HashIteratorState *state)>
+
+Iterate through the hash using a state object to keep track of the current
+position in the hash as we go. Results are undefined if you modify the hash
+during iteration. It likely won't do what you want.
+
+=cut
+
+*/
+
+void *
+Parrot_hash_get_next_key(PARROT_INTERP, ARGIN(const Hash * hash),
+ ARGMOD(HashIteratorState *state)
+{
+ INTVAL i = state->idx == INITBucketIndex ?
+ 0 : state->idx;
+ HashBucket * bp = state->current == NULL ?
+ hash->bucket_indices[i] : state->current->next;
+ void * result = NULL;
+
+ while(i < hash->entries) {
+ while (bp) {
+ if (bp->key) {
+ result = bp->key;
+ break;
+ }
+ bp = bp->next;
+ }
+ if (result != null)
+ break;
+ i++;
+ bp = hash->bucket_indices[i];
+ }
+ state->idx = i;
+ state->current = bp;
+ return result;
+}
+
/*
=item C<void * parrot_hash_get_idx(PARROT_INTERP, const Hash *hash, PMC *key)>
Finds the next index into the hash's internal storage for the given Key. Used
-by iterators. Ugly.
+by iterators. Ugly, and DEPRECATED.
=cut
@@ -1235,29 +1250,14 @@
PARROT_WARN_UNUSED_RESULT
PARROT_CAN_RETURN_NULL
HashBucket *
-parrot_hash_get_bucket(PARROT_INTERP, ARGIN(const Hash *hash), ARGIN_NULLOK(const void *key))
+parrot_hash_get_bucket(PARROT_INTERP, ARGIN(const Hash *hash),
+ ARGIN_NULLOK(const void *key))
{
ASSERT_ARGS(parrot_hash_get_bucket)
if (hash->entries <= 0)
return NULL;
-
- /* a very fast search for very small hashes */
- if (hash->entries <= SMALL_HASH_SIZE) {
- const UINTVAL entries = hash->entries;
- UINTVAL i;
-
- for (i = 0; i < entries; ++i) {
- HashBucket * const bucket = hash->buckets + i;
-
- /* the hash->compare cost is too high for this fast path */
- if (bucket->key == key)
- return bucket;
- }
- }
-
- /* if the fast search didn't work, try the normal hashing search */
- {
+ else {
const UINTVAL hashval = (hash->hash_val)(interp, key, hash->seed);
HashBucket *bucket = hash->bucket_indices[hashval & hash->mask];
@@ -1370,19 +1370,15 @@
if (bucket)
bucket->value = value;
else {
- /* Get a new bucket off the free list. If the free list is empty, we
- expand the hash so we get more items on the free list */
- bucket = hash->free_list;
- if (!bucket) {
- expand_hash(interp, hash);
- bucket = hash->free_list;
- }
+ 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;
- hash->free_list = bucket->next;
- bucket->key = key;
- bucket->value = value;
+ bucket->key = key;
+ bucket->value = value;
bucket->next = hash->bucket_indices[hashval & hash->mask];
hash->bucket_indices[hashval & hash->mask] = bucket;
}
@@ -1419,9 +1415,7 @@
hash->bucket_indices[hashval] = bucket->next;
--hash->entries;
- bucket->next = hash->free_list;
- bucket->key = NULL;
- hash->free_list = bucket;
+ Parrot_gc_free_fixed_size_storage(interp, bucket);
return;
}
More information about the parrot-commits
mailing list