Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
tree: de6a984c5e
Fetching contributors…

Cannot retrieve contributors at this time

328 lines (227 sloc) 7.399 kb
/*
Copyright (C) 2001-2011, Parrot Foundation.
=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/pmc_hash.h"
#include "pmc/pmc_hashiteratorkey.h"
/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
static void advance_to_next(ARGMOD(PMC *self))
__attribute__nonnull__(1)
FUNC_MODIFIES(*self);
#define ASSERT_ARGS_advance_to_next __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(self))
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: static */
/*
=item C<static void advance_to_next(PMC *self)>
Advance to next position. Return found (if any) HashBucket.
=cut
*/
static void
advance_to_next(ARGMOD(PMC *self))
{
ASSERT_ARGS(advance_to_next)
Parrot_HashIterator_attributes * const attrs = PARROT_HASHITERATOR(self);
if (attrs->elements <= 0) {
attrs->elements = -1;
return;
}
if (attrs->parrot_hash->key_type == Hash_key_type_int
|| attrs->parrot_hash->key_type == Hash_key_type_ptr
|| attrs->parrot_hash->key_type == Hash_key_type_cstring) {
/* indexed scan */
if (attrs->bucket)
attrs->bucket = attrs->bucket->next;
while (!attrs->bucket) {
/* Check pos overflow, can happen if items are deleted */
if (attrs->pos == attrs->total_buckets) {
attrs->elements = 0;
break;
}
attrs->bucket = attrs->parrot_hash->index[attrs->pos++];
}
}
else {
/* linear scan */
const int n_buckets = N_BUCKETS(attrs->total_buckets);
if (!attrs->bucket)
attrs->bucket = attrs->parrot_hash->buckets;
while (attrs->pos < n_buckets) {
attrs->bucket = attrs->parrot_hash->buckets + attrs->pos++;
if (attrs->bucket->key)
break;
}
/* Can happen if items are deleted */
if (!attrs->bucket->key)
attrs->elements = 0;
}
--attrs->elements;
return;
}
pmclass HashIterator extends Iterator provides iterator no_ro auto_attrs {
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; /* Total buckets in index */
ATTR INTVAL pos; /* Current position in index */
ATTR INTVAL elements; /* How many elements left to iterate over */
/*
=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 * const attrs =
(Parrot_HashIterator_attributes *) PMC_data(SELF);
attrs->pmc_hash = hash;
attrs->parrot_hash = (Hash*)VTABLE_get_pointer(INTERP, hash);
attrs->total_buckets = attrs->parrot_hash->mask + 1;
attrs->elements = attrs->parrot_hash->entries;
attrs->bucket = NULL;
attrs->pos = 0;
PObj_custom_mark_SET(SELF);
}
/*
=item C<void mark()>
Marks the hash as live.
=cut
*/
VTABLE void mark() {
PMC * const hash = PARROT_HASHITERATOR(SELF)->pmc_hash;
Parrot_gc_mark_PMC_alive(INTERP, hash);
/* We don't mark underlying parrot_hash. Hash PMC will mark it */
}
/*
=item C<PMC *clone()>
=cut
*/
VTABLE PMC* clone() {
return PMCNULL;
}
/*
=item C<void set_integer_native()>
=cut
*/
VTABLE void set_integer_native(INTVAL value) {
Parrot_HashIterator_attributes * const attrs =
PARROT_HASHITERATOR(SELF);
if (value == ITERATE_FROM_START) {
/* Restart iterator */
attrs->elements = attrs->parrot_hash->entries;
attrs->bucket = NULL;
attrs->pos = 0;
return;
}
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
"HashIterator: unknown iterator type");
};
/*
=item C<PMC *get_pmc()>
Returns this Iterator's Hash.
=cut
*/
VTABLE PMC* get_pmc() {
return PARROT_HASHITERATOR(SELF)->pmc_hash;
}
/*
=item C<INTVAL get_bool()>
Returns true if there is more elements to iterate over.
=cut
*/
VTABLE INTVAL get_bool() {
return PARROT_HASHITERATOR(SELF)->elements != 0;
}
/*
=item C<INTVAL elements()>
Returns the number of remaining elements in the Hash.
=cut
*/
VTABLE INTVAL elements() {
return PARROT_HASHITERATOR(SELF)->elements;
}
VTABLE INTVAL get_integer() {
return PARROT_HASHITERATOR(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 * const attrs =
PARROT_HASHITERATOR(SELF);
PMC *ret;
/* Move to next bucket */
advance_to_next(SELF);
if (attrs->elements < 0)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
"StopIteration");
ret = Parrot_pmc_new(INTERP, enum_class_HashIteratorKey);
VTABLE_set_pointer_keyed_int(INTERP, ret, 0, attrs->parrot_hash);
VTABLE_set_pointer_keyed_int(INTERP, ret, 1, attrs->bucket);
return ret;
}
/*
*/
VTABLE STRING* shift_string() {
Parrot_HashIterator_attributes * const attrs = PARROT_HASHITERATOR(SELF);
/* Move to next bucket */
advance_to_next(SELF);
if (attrs->elements < 0)
return CONST_STRING(INTERP, "");
return Parrot_hash_key_to_string(INTERP, attrs->parrot_hash, attrs->bucket->key);
}
/*
*/
VTABLE INTVAL shift_integer() {
Parrot_HashIterator_attributes * const attrs = PARROT_HASHITERATOR(SELF);
/* Move to next bucket */
advance_to_next(SELF);
if (attrs->elements < 0)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_OUT_OF_BOUNDS,
"StopIteration");
return Parrot_hash_key_to_int(INTERP, attrs->parrot_hash, attrs->bucket->key);
}
}
/*
=back
=cut
*/
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
*/
Jump to Line
Something went wrong with that request. Please try again.