[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