[svn:parrot] r39577 - in branches/tt761_keys_revamp: src/pmc t/pmc

bacek at svn.parrot.org bacek at svn.parrot.org
Mon Jun 15 23:36:23 UTC 2009


Author: bacek
Date: Mon Jun 15 23:36:22 2009
New Revision: 39577
URL: https://trac.parrot.org/parrot/changeset/39577

Log:
[pmc] Initial version of HashIterator/HashIteratorKey.

Added:
   branches/tt761_keys_revamp/src/pmc/hashiterator.pmc
   branches/tt761_keys_revamp/src/pmc/hashiteratorkey.pmc
   branches/tt761_keys_revamp/t/pmc/hashiterator.t
Modified:
   branches/tt761_keys_revamp/src/pmc/hash.pmc

Modified: branches/tt761_keys_revamp/src/pmc/hash.pmc
==============================================================================
--- branches/tt761_keys_revamp/src/pmc/hash.pmc	Mon Jun 15 21:33:37 2009	(r39576)
+++ branches/tt761_keys_revamp/src/pmc/hash.pmc	Mon Jun 15 23:36:22 2009	(r39577)
@@ -20,6 +20,7 @@
 
 #include "pmc_iterator.h"
 #include "pmc_key.h"
+#include "pmc_hashiteratorkey.h"
 
 /*
 
@@ -507,6 +508,12 @@
         PMC         *nextkey;
         Hash * const hash = (Hash *)SELF.get_pointer();
 
+        /* called from iterator */
+        if (VTABLE_type(INTERP, key) == enum_class_HashIteratorKey) {
+            PMC *val = (PMC*)PARROT_HASHITERATORKEY(key)->bucket->value;
+            return VTABLE_get_string(INTERP, val);
+        }
+
         if ((PObj_get_FLAGS(key) & KEY_type_FLAGS) == KEY_hash_iterator_FLAGS) {
             /* called from iterator with an integer idx in key */
             if (hash->key_type == Hash_key_type_int) {
@@ -624,6 +631,11 @@
         HashBucket    *b;
         PMC           *nextkey;
 
+        /* called from iterator */
+        if (VTABLE_type(INTERP, key) == enum_class_HashIteratorKey) {
+            return (PMC*)PARROT_HASHITERATORKEY(key)->bucket->value;
+        }
+
         /* called from iterator with an integer idx in key */
         if ((PObj_get_FLAGS(key) & KEY_type_FLAGS) == KEY_hash_iterator_FLAGS) {
             PMC *result;

Added: branches/tt761_keys_revamp/src/pmc/hashiterator.pmc
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ branches/tt761_keys_revamp/src/pmc/hashiterator.pmc	Mon Jun 15 23:36:22 2009	(r39577)
@@ -0,0 +1,236 @@
+/*
+Copyright (C) 2001-2009, Parrot Foundation.
+$Id$
+
+=head1 NAME
+
+src/pmc/hashiterator.pmc - Implementation of Iterator for Hashes.
+
+=head1 DESCRIPTION
+
+Generic iterator for traversing Hash.
+
+=head1 SYNOPSIS
+
+=head2 default usage
+
+    .local pmc iterator, hash, key, entry
+    iterator = iter hash
+  iter_loop:
+    unless iterator, iter_end  # while (more values)
+    key   = shift iterator     # get the key. Some key
+    entry = hash[key]
+    ...
+    goto iter_loop
+  iter_end:
+
+=head2 C++-style usage
+
+    .local pmc iterator, hash, iter_key, key, entry
+    iterator = iter hash
+  iter_loop:
+    unless iterator, iter_end  # while (more values)
+    iter_key = shift iterator     # get the key
+    key = iter_key.'key'()        # get an original key used to put value
+    key = iter_key.'value'()      # get an entry
+    ...
+    goto iter_loop
+  iter_end:
+
+
+=head1 Methods
+
+=over 4
+
+=cut
+
+*/
+
+#include "pmc_hash.h"
+#include "pmc_hashiteratorkey.h"
+
+/*
+
+Advance to next position. Return found (if any) HashBucket.
+
+*/
+static HashBucket*
+advance_to_next(PARROT_INTERP, PMC *self) {
+    Parrot_HashIterator_attributes *attrs  = PARROT_HASHITERATOR(self);
+    HashBucket                     *bucket = attrs->bucket;
+
+    /* Try to advance current bucket */
+    if (bucket)
+        bucket = bucket->next;
+
+    while (!bucket) {
+        /* If there is no more buckets */
+        if (attrs->pos == attrs->total_buckets)
+            break;
+
+        bucket = attrs->parrot_hash->bi[attrs->pos++];
+    }
+    attrs->bucket = bucket;
+    return bucket;
+}
+
+pmclass HashIterator extends Iterator no_ro {
+    ATTR PMC        *pmc_hash;      /* the Hash which this Iterator iterates */
+    ATTR Hash       *parrot_hash;   /* Underlying implementation of hash */
+    ATTR HashBucket *bucket;        /* Current bucket */
+    ATTR INTVAL      total_buckets; /* */
+    ATTR INTVAL      pos;           /* */
+
+/*
+
+=item C<void init_pmc(PMC *initializer)>
+
+Initializes the iterator with an aggregate PMC.
+Defaults iteration mode to iterate from start.
+
+=cut
+
+*/
+
+    VTABLE void init_pmc(PMC *hash) {
+        Parrot_HashIterator_attributes *attrs =
+            mem_allocate_zeroed_typed(Parrot_HashIterator_attributes);
+
+        attrs->pmc_hash         = hash;
+        attrs->parrot_hash      = (Hash*)VTABLE_get_pointer(INTERP, hash);
+        attrs->total_buckets    = attrs->parrot_hash->mask + 1;
+        attrs->bucket           = 0;
+        attrs->pos              = 0;
+        PMC_data(SELF)          = attrs;
+
+        PObj_custom_mark_destroy_SETALL(SELF);
+
+        /* Initial state of iterator is "before start" */
+        /* So, advance to first element */
+        advance_to_next(INTERP, SELF);
+    }
+
+/*
+
+=item C<void destroy()>
+
+destroys this PMC
+
+=cut
+
+*/
+
+    VTABLE void destroy() {
+        mem_sys_free(PMC_data(SELF));
+    }
+
+/*
+
+=item C<void mark()>
+
+Marks the hash as live.
+
+=cut
+
+*/
+
+    VTABLE void mark() {
+        PMC *hash = PARROT_HASHITERATOR(SELF)->pmc_hash;
+        if (hash)
+             Parrot_gc_mark_PObj_alive(INTERP, (PObj *)hash);
+    }
+
+/*
+
+=item C<PMC *clone()>
+
+=cut
+
+*/
+    VTABLE PMC* clone() {
+        return PMCNULL;
+    }
+
+/*
+
+=item C<INTVAL get_bool()>
+
+Returns true if there is more elements to iterate over.
+
+=cut
+
+*/
+
+    VTABLE INTVAL get_bool() {
+        return PARROT_HASHITERATOR(SELF)->bucket != 0;
+    }
+
+/*
+
+=item C<INTVAL elements()>
+
+Returns the number of remaining elements in the array.
+
+=cut
+
+*/
+
+    VTABLE INTVAL elements() {
+        return 0;
+    }
+
+    VTABLE INTVAL get_integer() {
+        return SELF.elements();
+    }
+
+/*
+
+=item C<PMC *shift_pmc()>
+
+Returns the HashIteratorKey for the current position and advance
+the next one.
+
+=cut
+
+*/
+
+    VTABLE PMC *shift_pmc() {
+        Parrot_HashIterator_attributes *attrs =
+                PARROT_HASHITERATOR(SELF);
+
+        PMC        *ret;
+
+        if (!attrs->bucket)
+            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
+                "StopIteration");
+
+        ret = pmc_new(INTERP, enum_class_HashIteratorKey);
+        /* Poke directly into HIK. We don't want to create any kind of public API for this */
+        PARROT_HASHITERATORKEY(ret)->parrot_hash = attrs->parrot_hash;
+        PARROT_HASHITERATORKEY(ret)->bucket      = attrs->bucket;
+
+        /* Move to next bucket */
+        advance_to_next(INTERP, SELF);
+
+        return ret;
+    }
+
+/*
+*/
+
+}
+
+/*
+
+=back
+
+=cut
+
+*/
+
+/*
+ * Local variables:
+ *   c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */

Added: branches/tt761_keys_revamp/src/pmc/hashiteratorkey.pmc
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ branches/tt761_keys_revamp/src/pmc/hashiteratorkey.pmc	Mon Jun 15 23:36:22 2009	(r39577)
@@ -0,0 +1,115 @@
+/*
+Copyright (C) 2001-2009, Parrot Foundation.
+$Id$
+
+=head1 NAME
+
+src/pmc/hashiteratorkey.pmc - accessor for single value during hash iteration.
+
+=head1 DESCRIPTION
+
+Single (key,value) pair.
+
+
+=head1 Methods
+
+=over 4
+
+=cut
+
+*/
+
+pmclass HashIteratorKey no_ro {
+    ATTR Hash        *parrot_hash; /* Underlying parrot's hash */
+    ATTR HashBucket  *bucket;      /* Current bucket from HashItertor */
+
+/*
+
+=item C<void init()>
+
+Initializes the PMC.
+
+Not really part of public API.
+
+=cut
+
+*/
+
+    VTABLE void init() {
+        Parrot_HashIteratorKey_attributes *attrs =
+            mem_allocate_zeroed_typed(Parrot_HashIteratorKey_attributes);
+
+        PMC_data(SELF) = attrs;
+
+        PObj_active_destroy_SET(SELF);
+    }
+
+/*
+
+=item C<void destroy()>
+
+Destroys this PMC
+
+=cut
+
+*/
+
+    VTABLE void destroy() {
+        mem_sys_free(PMC_data(SELF));
+    }
+
+/*
+
+=item C<get_pmc()>
+
+Get "key".
+
+=cut
+
+*/
+    VTABLE PMC* get_pmc() {
+        return PMCNULL;
+    }
+
+    VTABLE INTVAL get_integer() {
+        return -1;
+    }
+
+    VTABLE STRING* get_string() {
+        Parrot_HashIteratorKey_attributes *attrs =
+                PARROT_HASHITERATORKEY(SELF);
+
+        switch (attrs->parrot_hash->key_type) {
+            case Hash_key_type_int:
+                return Parrot_str_from_int(INTERP, (INTVAL)attrs->bucket->key);
+
+            case Hash_key_type_STRING:
+                return (STRING*)attrs->bucket->key;
+
+            default:
+                /* Horribly die */
+                break;
+        }
+
+        return NULL;
+    }
+
+
+
+}
+
+/*
+
+=back
+
+=cut
+
+*/
+
+/*
+ * Local variables:
+ *   c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */
+

Added: branches/tt761_keys_revamp/t/pmc/hashiterator.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ branches/tt761_keys_revamp/t/pmc/hashiterator.t	Mon Jun 15 23:36:22 2009	(r39577)
@@ -0,0 +1,74 @@
+#! parrot
+# Copyright (C) 2001-2008, Parrot Foundation.
+# $Id$
+
+=head1 NAME
+
+t/pmc/hash.t - Test the Hash PMC
+
+=head1 SYNOPSIS
+
+    % prove t/pmc/hash.t
+
+=head1 DESCRIPTION
+
+Tests the C<Hash> PMC. Checks key access with various types of
+normal and potentially hazardous keys. Does a bit of stress testing as
+well.
+
+=cut
+
+.sub main :main
+    .include 'test_more.pir'
+    .include 'except_types.pasm'
+
+    plan(6)
+
+    iter_over_empty_hash()
+    iter_over_single_element()
+    iter_over_single_element_with_checks()
+
+.end
+
+.sub 'iter_over_empty_hash'
+    .local pmc hash, it
+    hash = new 'Hash'
+    it   = new 'HashIterator', hash
+    $I0  = isfalse it
+    ok($I0, "Iterator for empty Hash is empty")
+.end
+
+.sub 'iter_over_single_element'
+    .local pmc hash, it
+    hash = new 'Hash'
+    hash["foo"] = "bar"
+    it   = new 'HashIterator', hash
+    $I0  = istrue it
+    ok($I0, "Iterator for non empty Hash is not empty")
+    $P0  = shift it
+    $I0  = isfalse it
+    ok($I0, "And contains one element")
+.end
+
+.sub 'iter_over_single_element_with_checks'
+    .local pmc hash, it
+    hash = new 'Hash'
+    hash["foo"] = "bar"
+
+    it   = new 'HashIterator', hash
+    $P0  = shift it
+    $I0  = isa $P0, 'HashIteratorKey'
+    ok($I0, "HashIteratorKey fetched successfully")
+
+    $S0  = $P0 # Get key
+    is($S0, "foo", "Key fetched successfully")
+    $S1  = hash[$P0]
+    is($S1, "bar", "Value fetched successfully")
+
+.end
+
+# Local Variables:
+#   mode: pir
+#   fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:


More information about the parrot-commits mailing list