1/* 2Copyright (C) 2001-2014, Parrot Foundation. 3 4=head1 NAME 5 6src/pmc/orderedhashiterator.pmc - OrderedHashIterator 7 8=head1 DESCRIPTION 9 10Specialized iterator for an OrderedHash PMC. 11 12=head1 METHODS 13 14=over 4 15 16=cut 17 18*/ 19 20#include "pmc/pmc_orderedhash.h" 21#include "pmc/pmc_hashiteratorkey.h" 22 23/* HEADERIZER HFILE: none */ 24/* HEADERIZER BEGIN: static */ 25/* HEADERIZER END: static */ 26 27pmclass OrderedHashIterator extends Iterator provides iterator no_ro auto_attrs { 28 ATTR PMC *pmc_hash; /* the Hash which this Iterator iterates */ 29 ATTR PMC *next_entry; /* Next entry to shift/pop */ 30 ATTR INTVAL pos; /* */ 31 ATTR INTVAL elements; /* How many elements left to iterate over */ 32 ATTR INTVAL reverse; /* Direction of iteration. 1 - for reverse iteration */ 33 34/* 35 36=item C<void init_pmc(PMC *initializer)> 37 38Initializes the iterator with an aggregate PMC. 39Defaults iteration mode to iterate from start. 40 41=cut 42 43*/ 44 45 VTABLE void init_pmc(PMC *hash) { 46 Parrot_OrderedHashIterator_attributes * const attrs = 47 (Parrot_OrderedHashIterator_attributes *) PMC_data(SELF); 48 49 attrs->pmc_hash = hash; 50 attrs->pos = 0; 51 attrs->elements = VTABLE_elements(INTERP, hash); 52 attrs->next_entry = PARROT_ORDEREDHASH(hash)->first; 53 PMC_data(SELF) = attrs; 54 55 PObj_custom_mark_SET(SELF); 56 } 57 58/* 59 60=item C<void mark()> 61 62Marks the hash as live. 63 64=cut 65 66*/ 67 68 VTABLE void mark() :no_wb { 69 PMC * const hash = PARROT_ORDEREDHASHITERATOR(SELF)->pmc_hash; 70 Parrot_gc_mark_PMC_alive(INTERP, hash); 71 } 72 73/* 74 75=item C<PMC *clone()> 76 77=cut 78 79*/ 80 VTABLE PMC* clone() :no_wb { 81 UNUSED(INTERP) 82 UNUSED(SELF) 83 return PMCNULL; 84 } 85 86/* 87 88=item C<void set_integer_native()> 89 90=cut 91 92*/ 93 VTABLE void set_integer_native(INTVAL value) { 94 Parrot_OrderedHashIterator_attributes * const attrs = 95 PARROT_ORDEREDHASHITERATOR(SELF); 96 97 /* Restart iterator */ 98 attrs->elements = VTABLE_elements(INTERP, attrs->pmc_hash); 99 switch (value) { 100 case ITERATE_FROM_START: 101 case ITERATE_FROM_START_KEYS: 102 attrs->pos = 0; 103 attrs->reverse = 0; 104 attrs->next_entry = PARROT_ORDEREDHASH(attrs->pmc_hash)->first; 105 break; 106 case ITERATE_FROM_END: 107 attrs->pos = attrs->elements; 108 attrs->reverse = 1; 109 attrs->next_entry = PARROT_ORDEREDHASH(attrs->pmc_hash)->last; 110 break; 111 default: 112 Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_INVALID_OPERATION, 113 "HashIterator: unknown iterator type"); 114 } 115 }; 116 117/* 118 119=item C<PMC *get_pmc()> 120 121Returns this Iterator's Hash. 122 123=cut 124 125*/ 126 VTABLE PMC* get_pmc() :no_wb { 127 UNUSED(INTERP) 128 return PARROT_ORDEREDHASHITERATOR(SELF)->pmc_hash; 129 } 130 131/* 132 133=item C<INTVAL get_bool()> 134 135Returns true if there is more elements to iterate over. 136 137=cut 138 139*/ 140 141 VTABLE INTVAL get_bool() :no_wb { 142 return STATICSELF.elements() > 0; 143 } 144 145/* 146 147=item C<INTVAL elements()> 148 149Returns the number of remaining elements in the Hash. 150 151=cut 152 153*/ 154 155 VTABLE INTVAL elements() :no_wb { 156 UNUSED(INTERP) 157 return PARROT_ORDEREDHASHITERATOR(SELF)->elements; 158 } 159 160 VTABLE INTVAL get_integer() :no_wb { 161 return SELF.elements(); 162 } 163 164/* 165 166=item C<PMC *shift_pmc()> 167 168Returns the HashIteratorKey for the current position and advance 169the next one. 170 171=cut 172 173*/ 174 175 VTABLE PMC *shift_pmc() :manual_wb { 176 Parrot_OrderedHashIterator_attributes * const attrs = 177 PARROT_ORDEREDHASHITERATOR(SELF); 178 179 PMC *ret; 180 181 if (!attrs->elements) 182 Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS, 183 "StopIteration"); 184 185 /* Get bucket and move to next bucket */ 186 ret = VTABLE_get_pmc_keyed_int(INTERP, attrs->next_entry, 187 ORDERED_HASH_ITEM_KEY); 188 attrs->next_entry = VTABLE_get_pmc_keyed_int(INTERP, attrs->next_entry, 189 ORDERED_HASH_ITEM_NEXT); 190 ++attrs->pos; 191 --attrs->elements; 192 193 PARROT_GC_WRITE_BARRIER(INTERP, SELF); 194 return ret; 195 } 196 197/* 198 199=item C<PMC *pop_pmc()> 200 201Returns the HashIteratorKey for the current position and advance 202the next one for reverse iterator. 203 204=cut 205 206*/ 207 208 VTABLE PMC *pop_pmc() :manual_wb { 209 Parrot_OrderedHashIterator_attributes * const attrs = 210 PARROT_ORDEREDHASHITERATOR(SELF); 211 212 PMC *ret; 213 214 if (!attrs->elements) 215 Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_OUT_OF_BOUNDS, 216 "StopIteration"); 217 218 ret = VTABLE_get_pmc_keyed_int(INTERP, attrs->next_entry, 219 ORDERED_HASH_ITEM_KEY); 220 attrs->next_entry = VTABLE_get_pmc_keyed_int(INTERP, attrs->next_entry, 221 ORDERED_HASH_ITEM_PREV); 222 --attrs->pos; 223 --attrs->elements; 224 225 PARROT_GC_WRITE_BARRIER(INTERP, SELF); 226 return ret; 227 } 228 229/* 230 231*/ 232 233 VTABLE STRING* shift_string() :manual_wb { 234 PMC * const key = SELF.shift_pmc(); 235 PARROT_GC_WRITE_BARRIER(INTERP, SELF); 236 return VTABLE_get_string(INTERP, key); 237 } 238} 239 240/* 241 242=back 243 244=cut 245 246*/ 247 248/* 249 * Local variables: 250 * c-file-style: "parrot" 251 * End: 252 * vim: expandtab shiftwidth=4 cinoptions='\:2=2' : 253 */ 254