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